自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

程序猿如何從產(chǎn)品的角度去提升應(yīng)用的體驗(yàn)之Android權(quán)限優(yōu)化篇

移動(dòng)開發(fā) Android
推送對(duì)于一個(gè)APP來說是很重要的功能。推送在好的產(chǎn)品設(shè)計(jì)中可以有效地提高產(chǎn)品活躍度,增加用戶的忠誠度以及留存率。但是,用戶有可能會(huì)在無意中把應(yīng)用的通知權(quán)限給禁止了,導(dǎo)致收不到推送(用戶主動(dòng)禁止應(yīng)用的通知權(quán)限除外)。

前言:大家平時(shí)在開發(fā)的過程中是否會(huì)遇到這種情況:很多產(chǎn)品體驗(yàn)上的細(xì)節(jié),特別是涉及到技術(shù)相關(guān)的細(xì)節(jié),產(chǎn)品與設(shè)計(jì)可能并不會(huì)給出詳細(xì)的解決方案,甚至可能并不太關(guān)注這方面的體驗(yàn)細(xì)節(jié)。例如,應(yīng)用的緩存清理機(jī)制該怎么實(shí)現(xiàn)?權(quán)限申請的時(shí)機(jī)應(yīng)該放在哪?用戶沒有給予應(yīng)用必要的權(quán)限該怎么處理......這種時(shí)候,作為一個(gè)開發(fā)人員,特別是對(duì)自家產(chǎn)品的使用體驗(yàn)有追求的開發(fā)人員,其實(shí)完全可以充當(dāng)一回產(chǎn)品,從產(chǎn)品的角度出發(fā)去思考,該怎樣在技術(shù)實(shí)現(xiàn)的細(xì)節(jié)上,讓自家的APP體驗(yàn)變得更好。千萬不要小瞧這些細(xì)節(jié),一個(gè)產(chǎn)品的***體驗(yàn),就是由無數(shù)的細(xì)節(jié)堆砌而成的。

1. 應(yīng)用通知權(quán)限的優(yōu)化

眾所周知,推送對(duì)于一個(gè)APP來說是很重要的功能。推送在好的產(chǎn)品設(shè)計(jì)中可以有效地提高產(chǎn)品活躍度,增加用戶的忠誠度以及留存率。但是,用戶有可能會(huì)在無意中把應(yīng)用的通知權(quán)限給禁止了,導(dǎo)致收不到推送(用戶主動(dòng)禁止應(yīng)用的通知權(quán)限除外)。例如,華為手機(jī)會(huì)在通知中心直接提示用戶是否關(guān)掉某個(gè)應(yīng)用的通知權(quán)限。如果用戶,特別是小白用戶一不小心把通知權(quán)限給禁止了,導(dǎo)致應(yīng)用收不到推送,反而可能還會(huì)把這種情況當(dāng)做bug來向客服反饋(任何時(shí)候都千萬不要高估用戶對(duì)于智能手機(jī)使用的了解,尤其是你的APP的目標(biāo)用戶還包括中老年人的時(shí)候)。 

 

華為手機(jī)的推送中心 

如果大家有細(xì)心觀察的話會(huì)發(fā)現(xiàn),當(dāng)應(yīng)用的通知權(quán)限被禁止的時(shí)候,體驗(yàn)好的應(yīng)用會(huì)在適當(dāng)?shù)臅r(shí)機(jī)以及場景下出現(xiàn)提示,告知用戶通知在應(yīng)用中起到的作用,嘗試去消除用戶的不信任和謹(jǐn)慎心理,并引導(dǎo)用戶去打開通知權(quán)限。

那么,我們怎么知道自己的應(yīng)用程序通知權(quán)限被禁止了呢?如果被禁止了又該怎么辦呢?下面就來說一下解決方案。

1.1 檢測應(yīng)用的通知權(quán)限狀態(tài)

檢測應(yīng)用的通知權(quán)限其實(shí)比較簡單。通過查詢 官方文檔 可以發(fā)現(xiàn),在support庫的API 24.0.0 版本,已經(jīng)有現(xiàn)成的方法可以直接查詢應(yīng)用的通知權(quán)限狀態(tài):

  1. NotificationManagerCompat.from(this).areNotificationEnable(); 

但是,這就意味著應(yīng)用的 compileSdkVersion 也需要與support庫的版本保持一致。如果應(yīng)用目前所使用的compileSdkVersion 低于 24.0.0 或者由于某些歷史原因而不能將compileSdkVersion 升到 24.0.0以上,那么就沒有辦法檢測到應(yīng)用的通知權(quán)限了嗎?

其實(shí),辦法還是有的。通過查看系統(tǒng)源碼,可以發(fā)現(xiàn),NotificationManagerCompat.from(this).areNotificationEnable() 這個(gè)方法在不同版本的SDK上會(huì)有不同的實(shí)現(xiàn)。

  1. /** 
  2.  
  3. Returns whether notifications from the calling package are not blocked. 
  4.  
  5. */ 
  6.  
  7. public boolean areNotificationsEnabled() {  
  8.     return IMPL.areNotificationsEnabled(mContext, mNotificationManager); 
  9.  
  10.  

IMPL是一個(gè)實(shí)現(xiàn)了Impl接口的實(shí)現(xiàn)類對(duì)象,而且在靜態(tài)代碼塊中通過判斷手機(jī)系統(tǒng)所使用的版本號(hào)來初始化不同的實(shí)現(xiàn)類:

  1. static {    if (BuildCompat.isAtLeastN()) { 
  2.         IMPL = new ImplApi24(); 
  3.     } else if (Build.VERSION.SDK_INT >= 19) { 
  4.         IMPL = new ImplKitKat(); 
  5.     }  else if (Build.VERSION.SDK_INT >= 14) { 
  6.         IMPL = new ImplIceCreamSandwich(); 
  7.     } else { 
  8.         IMPL = new ImplBase(); 
  9.     } 
  10.     SIDE_CHANNEL_BIND_FLAGS = IMPL.getSideChannelBindFlags(); 
  11.  

當(dāng)手機(jī)系統(tǒng)Android版本小于4.4.0的時(shí)候, areNotificationEnable()方法會(huì)默認(rèn)返回true。所以,此方法只有在4.4.0以上的手機(jī)系統(tǒng)上才能返回準(zhǔn)確的結(jié)果。

  1. /** 
  2.  * Returns whether notifications from the calling package are blocked. 
  3.  */ 
  4. public boolean areNotificationsEnabled() { 
  5.     INotificationManager service = getService(); 
  6.     try {        return service.areNotificationsEnabled(mContext.getPackageName()); 
  7.     } catch (RemoteException e) { 
  8.         throw e.rethrowFromSystemServer(); 
  9.     } 
  10.  

這種反射的方式實(shí)際上就是通過AppOpsManager和AppOpsService去獲取位于/data/system/目錄下的文件Appops.xml里的數(shù)據(jù)。所以,這個(gè)系統(tǒng)源碼里的方法可以單獨(dú)抽取出來作為一個(gè)通用的檢測通知權(quán)限狀態(tài)的方法。有關(guān)AppOpsManager,這里先不做展開,等下在1.4章節(jié)單獨(dú)說一下。

1.2 引導(dǎo)用戶跳轉(zhuǎn)到通知權(quán)限設(shè)置界面

既然已經(jīng)能檢測到應(yīng)用的通知權(quán)限狀態(tài),當(dāng)應(yīng)用的通知權(quán)限被禁止的時(shí)候,應(yīng)該出現(xiàn)提示告知用戶通知在應(yīng)用中起到的作用,并引導(dǎo)用戶去打開通知權(quán)限。以下為跳轉(zhuǎn)到通知權(quán)限設(shè)置的通用方法:

  1. public void toNotificationSetting() {    if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 
  2.         Intent intent = new Intent(); 
  3.         intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); 
  4.         intent.putExtra("app_package", this.getPackageName()); 
  5.         intent.putExtra("app_uid", this.getApplicationInfo().uid); 
  6.         startActivity(intent); 
  7.     } else if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) { 
  8.         Intent intent = new Intent(); 
  9.         intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 
  10.         intent.addCategory(Intent.CATEGORY_DEFAULT); 
  11.         intent.setData(Uri.parse("package:" + this.getPackageName())); 
  12.         startActivity(intent); 
  13.     } 
  14.  

在5.0以上,可以直接跳轉(zhuǎn)到某個(gè)應(yīng)用的通知權(quán)限快捷設(shè)置界面。但是在5.0以下,暫時(shí)還沒有找到可以直接跳轉(zhuǎn)到通知權(quán)限設(shè)置界面的方法,所以目前的做法是跳轉(zhuǎn)某個(gè)應(yīng)用的設(shè)置界面,在設(shè)置界面列表中應(yīng)該會(huì)有通知權(quán)限管理的入口。如果你有更好的做法,歡迎在評(píng)論中指出來。這里再另外拋出一個(gè)問題,供大家思考:關(guān)于通知權(quán)限提示的方案,應(yīng)該在什么時(shí)機(jī)或場景下出現(xiàn)好?出現(xiàn)提示的頻率為多少好呢?是只提示一次呢,還是只要用戶沒打開通知權(quán)限就一直提示呢?歡迎大家在留言中說出自己的看法。

1.3 當(dāng)通知權(quán)限被關(guān)閉后,Toast可能無法正常工作的問題

雖然跟通知權(quán)限的優(yōu)化沒什么關(guān)系,不過在這里還是要提一下。這個(gè)是在調(diào)研通知權(quán)限優(yōu)化問題的時(shí)候偶然發(fā)現(xiàn)的坑:在大部分的機(jī)型上,當(dāng)應(yīng)用的通知權(quán)限被關(guān)閉后,系統(tǒng)的 Toast會(huì)直接無法正常工作。

以下是我測試過的數(shù)據(jù):

 

可以看出,這個(gè)坑影響的機(jī)型范圍還是挺大的。為什么會(huì)這樣呢?

查閱源碼后可以發(fā)現(xiàn) Toast 里也用到了NotificationManagerService。在Toast執(zhí)行show()方法后,執(zhí)行到enqueueToast()的時(shí)候如下:

  1. if (ENABLE_BLOCKED_TOASTS && !noteNotificationOp(pkg, Binder.getCallingUid())) {    if (!isSystemToast) { 
  2.         Slog.e(TAG, "Suppressing toast from package " + pkg + " by user request.");        return
  3.     } 
  4.  

原來這里也用到了檢測通知權(quán)限的方法noteNotificationOp()。如果通知權(quán)限被禁止了,那么Toast也就無法正常工作。

對(duì)于Android手機(jī)來說,Toast在應(yīng)用中隨處可見,如果因?yàn)橥ㄖ獧?quán)限導(dǎo)致Toast不工作那么影響還是挺大的。所以,在這里建議大家尋找一下Toast的替代方案,不要在項(xiàng)目中直接使用系統(tǒng)自帶的Toast。同樣的,如果大家有什么好的解決方案,也歡迎在留言中指出來。

1.4 AppOpsManager的工作原理

既然上面提到了AppOpsManager,那么這里來簡單地介紹一下它的工作原理。AppOpsManager的工作框架圖如下:

 

Setting UI通過AppOpsManager與AppOpsService 交互,給用戶提供入口管理各個(gè)app的操作。

AppOpsService具體處理用戶的各項(xiàng)設(shè)置,用戶的設(shè)置項(xiàng)存儲(chǔ)在 /data/system/appops.xml文件中。

AppOpsService也會(huì)被注入到各個(gè)相關(guān)的系統(tǒng)服務(wù)中,進(jìn)行權(quán)限操作的檢驗(yàn)。

各個(gè)權(quán)限操作對(duì)應(yīng)的系統(tǒng)服務(wù)(比如定位相關(guān)的Location Service,Audio相關(guān)的Audio Service等)中注入AppOpsService的判斷。如果用戶做了相應(yīng)的設(shè)置,那么這些系統(tǒng)服務(wù)就要做出相應(yīng)的處理。比如,LocationManagerSerivce的定位相關(guān)接口在實(shí)現(xiàn)時(shí),會(huì)有判斷調(diào)用該接口的app是否被用戶設(shè)置成禁止該操作,如果有該設(shè)置,就不會(huì)繼續(xù)進(jìn)行定位。

2. 應(yīng)用權(quán)限的提示優(yōu)化

由于篇幅的原因,這里就拿相機(jī)權(quán)限來舉例。假設(shè)需求如下:

在需要使用相機(jī)的場景下,先提前檢測相機(jī)權(quán)限是否打開,如果沒有打開,則嘗試申請相機(jī)權(quán)限,如果用戶還是拒絕,則出現(xiàn)權(quán)限提示,引導(dǎo)用戶去開啟相機(jī)權(quán)限。下面是微信的處理方式:

(1)6.0系統(tǒng)以上,先嘗試申請相機(jī)權(quán)限,用戶點(diǎn)擊禁止后彈出引導(dǎo)界面

 

(2)6.0系統(tǒng)以下,用戶點(diǎn)擊保持禁止后彈出引導(dǎo)界面 

 

在6.0以上,我們一般可以通過系統(tǒng)自帶的方法來檢測某個(gè)權(quán)限是否被允許:

  1. ActivityCompat.checkSelfPermission(context, permission) 

但是,在6.0以下,如果想檢測相機(jī)權(quán)限,卻沒有一個(gè)很好的方法。***,經(jīng)過查閱各種資料,發(fā)現(xiàn)好像只能通過一種簡單粗暴的方式去檢測相機(jī)權(quán)限:

  1. /** 
  2.  * 在6.0系統(tǒng)以下,通過嘗試打開相機(jī)的方式判斷有無拍照權(quán)限 
  3.  * 
  4.  * @return 
  5.  */ 
  6. private boolean checkCameraPermissionUnderM() { 
  7.     boolean isCanUse = true
  8.     Camera mCamera = null
  9.     try { 
  10.         mCamera = Camera.open(); 
  11.         Camera.Parameters mParameters = mCamera.getParameters(); 
  12.         mCamera.setParameters(mParameters); 
  13.     } catch (Exception e) { 
  14.         isCanUse = false
  15.     }    if (mCamera != null) { 
  16.         try { 
  17.             mCamera.release(); 
  18.         } catch (Exception e) { 
  19.             e.printStackTrace();            return isCanUse; 
  20.         } 
  21.     }    return isCanUse; 
  22.  

當(dāng)使用這個(gè)方法的時(shí)候,在6.0以下的手機(jī),一般調(diào)用 Camera.open()方法,如果相機(jī)權(quán)限沒打開,會(huì)先彈出相機(jī)權(quán)限申請彈框。如果點(diǎn)擊允許,那么該方法就會(huì)返回true,點(diǎn)擊禁止則返回false。這里需要指出的是,如果你使用相機(jī)的方式是通過Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE)來跳轉(zhuǎn)到系統(tǒng)的相機(jī)界面的話,那么即使應(yīng)用的相機(jī)權(quán)限被禁止了,也還是可以正常使用相機(jī)來拍照的。這種情況下要不要做權(quán)限檢查,就看個(gè)人的看法了。

不知道大家有沒注意到,微信在6.0以上和6.0以下彈出的提示對(duì)話框有點(diǎn)不同。在6.0以上提供“去設(shè)置”的選項(xiàng),點(diǎn)擊會(huì)跳轉(zhuǎn)到設(shè)置里的應(yīng)用列表界面,在6.0以下僅僅是提示。這也是一個(gè)產(chǎn)品的細(xì)節(jié)。個(gè)人看法,因?yàn)樵?.0以下,有些國產(chǎn)系統(tǒng)的權(quán)限管理根本就不在設(shè)置里面,而是需要到官方提供的手機(jī)管家類型應(yīng)用里面才可以進(jìn)行權(quán)限的管理。那么多的國產(chǎn)系統(tǒng),需要適配有點(diǎn)困難,如果沒有很好的解決方案,那么還不如不要擅自幫用戶做決定。可以看得出微信在跳轉(zhuǎn)到權(quán)限設(shè)置界面的適配上也經(jīng)過了一番考量,***選擇了這種折中的方案。

說到這里,既然權(quán)限提示優(yōu)化的思路已經(jīng)有了,大家也可以在自己的項(xiàng)目中封裝一個(gè)權(quán)限管理類,“檢查權(quán)限-被禁止-嘗試申請權(quán)限-被拒絕-彈出提示框-引導(dǎo)用戶去打開權(quán)限”通過一個(gè)方法一氣呵成。

3. 總結(jié)

本文涉及到的知識(shí)點(diǎn)可能并不深?yuàn)W,更多的是想向大家展示一下,假如開發(fā)人員從產(chǎn)品的角度去提升應(yīng)用的體驗(yàn),可以從什么角度去切入。如果能給大家?guī)硪恍﹩l(fā)就好了??赐晡恼潞螅环菜伎家幌?,自己的應(yīng)用在權(quán)限提示上的體驗(yàn)是否做到***了呢?如果還有可以改善的地方,那么趕緊根據(jù)自家應(yīng)用的實(shí)際情況,改善一下權(quán)限提示的體驗(yàn)吧。相信我,做了這件事,你的用戶會(huì)感激你的。 

責(zé)任編輯:龐桂玉 來源: Android技術(shù)之家
相關(guān)推薦

2013-09-16 16:01:23

Android開發(fā)代碼

2017-01-23 08:19:05

2024-12-10 00:00:10

MySQLJOIN算法

2021-01-06 10:50:27

程序員35歲互聯(lián)網(wǎng)

2015-09-16 15:48:55

Android性能優(yōu)化電量

2015-09-16 14:37:50

Android性能優(yōu)化運(yùn)算

2015-09-16 13:54:30

Android性能優(yōu)化渲染

2023-03-09 16:42:00

程序性能優(yōu)化Java技巧

2013-04-08 10:16:40

產(chǎn)品產(chǎn)品體驗(yàn)

2022-03-25 10:23:40

用戶體驗(yàn)APP優(yōu)化

2011-11-07 09:26:51

域樹

2011-06-30 17:13:17

SEO用戶體驗(yàn)

2010-03-18 20:19:16

2016-11-04 10:30:17

微信小程序

2022-07-15 13:01:13

Kotlin編程語言Java

2009-07-01 13:54:41

Servlet和JSP

2017-04-13 09:45:03

大數(shù)據(jù)新媒體VC

2019-11-11 09:02:51

MySQL數(shù)據(jù)庫索引

2018-10-26 15:30:49

程序員MySQL數(shù)據(jù)庫

2021-08-02 10:50:57

性能微服務(wù)數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)