日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Android動態(tài)權(quán)限詳解

 西北望msm66g9f 2020-05-06

1. 什么是動態(tài)權(quán)限

??去年底,上級主管部門為加強國內(nèi)Android應(yīng)用隱私管理,出臺了一系列規(guī)定,我們的App也做了相應(yīng)的修改。主要一條修改為,隱私提示與權(quán)限獲取順序。修改測試過程中,發(fā)覺部分同學(xué)對Android權(quán)限相關(guān)知識和歷史并不了解,就此疫情期間忙里偷閑,整理些東西供參閱。

??首先,從一張圖開始此文。

IOS 12定位權(quán)限

??時間回到2013年,蘋果公司發(fā)布IOS7系統(tǒng)。其中一項令開發(fā)者頭疼的修改點:隱私中增加相冊、錄音等權(quán)限,App如需使用相應(yīng)權(quán)限,需要申請并由用戶同意(IOS7以前,可以直接訪問相冊)。
??針對此點,很多App在首次啟動時一通彈窗,申請各式各樣的權(quán)限。后來蘋果為改善用戶體驗,在App Store審核時要求App必須在使用前一刻才能申請權(quán)限,有效改善了此類問題。比如一款直播App,當(dāng)你啟動App時并不需要相機、錄音權(quán)限,等到你開播時才需要申請這兩個權(quán)限。這一場景,其實就類似今天要提到的Android動態(tài)授權(quán)。
??谷歌于2015年推出Android 6.0 Marshmallow,其中一個主要特點便是加入了危險權(quán)限管理。這里的“危險權(quán)限管理”就帶來了“運行時權(quán)限”這個新特性。
??“危險權(quán)限管理”即在進行一些涉及到用戶隱私的操作時,需要獲取用戶的授權(quán)才能使用。如通訊錄、短信、相機、定位等隱私權(quán)限。獲取用戶權(quán)限,谷歌提倡在應(yīng)用運行時向其授權(quán),簡稱,運行時權(quán)限(也被叫做“動態(tài)權(quán)限/動態(tài)授權(quán)”,后文稱“動態(tài)權(quán)限”)。
??那,在這之前,Android權(quán)限管理是怎樣的呢?自己杜撰了下國內(nèi)Android權(quán)限管理經(jīng)歷的大概四個階段。

Android權(quán)限管理簡史

第一階段:沒遮攔

??早期Android系統(tǒng)(Android 6.0以前),在安裝App前,會羅列出App申請的所有權(quán)限。如果繼續(xù)安裝,視為用戶同意賦予App所需權(quán)限。
??例如:sony L36h Android 4.2.2系統(tǒng)。在嘗試安裝App時,彈窗羅列了App申請的全部權(quán)限。只能對所需權(quán)限進行查看,無法拒絕授權(quán),可選擇取消安裝或繼續(xù)安裝。

Sony L36h安裝提示

??這種方式,對于開發(fā)者極為友好,僅需在Manifest中配置App所需權(quán)限即可,代碼就可以直接調(diào)用了。但是對于用戶來說,這種方法存在極大的安全隱患。
??例:獲取手機IMEI,需要PHONE_STATE權(quán)限;訪問網(wǎng)絡(luò),需要INIERNET權(quán)限。只許在Manifest文件中添加權(quán)限即可。

 <!-- PHONE_STATE權(quán)限-->
 <uses-permission android:name='android.permission.READ_PHONE_STATE' />
 <!-- 網(wǎng)絡(luò)權(quán)限-->
 <uses-permission android:name='android.permission.INTERNET' />

第二階段:第三方安全App

??基于以上背景,為解決部分敏感權(quán)限被不合理使用,國內(nèi)部分公司的安全類App,開始監(jiān)控應(yīng)用獲取手機敏感權(quán)限并做出提示。如360手機衛(wèi)士、騰訊手機管家等產(chǎn)品,當(dāng)監(jiān)測到有App嘗試使用短信權(quán)限、定位等敏感權(quán)限,會告知用戶,并可以拒絕賦予權(quán)限。剛開始,還比較順利。但隨著手機廠商逐漸開始修改ROM,第三方安全App的兼容、性能問題逐步爆發(fā)。
??例:HTC T328 Android 4.0.2系統(tǒng)。瀏覽器掃碼功能觸發(fā)相機調(diào)用時,360手機衛(wèi)士會彈出權(quán)限提示窗,用戶可以允許或拒絕授權(quán)。注意,此窗由第三方安全軟件彈出,非系統(tǒng)級彈窗,跟后面要說的兩種彈窗有所區(qū)別。

360手機衛(wèi)士 彈窗

第三階段:手機廠商介入

??隨著時間的推移,手機廠商開始發(fā)力,紛紛將第三方軟件的權(quán)限提示功能直接做入ROM。
??例:小米4,基于Android 4.4.4的MIUI7;oppo R9,基于Android 5.1的ColorOS 3.0,瀏覽器掃碼功能觸發(fā)相機調(diào)用時,會彈出權(quán)限提示窗。此窗,由ROM也就是系統(tǒng)自己彈出,為系統(tǒng)級權(quán)限彈窗。

小米4授權(quán)
OPPO R9授權(quán)

第四階段:谷歌升級權(quán)限管理

??以上3個時期,App在申請權(quán)限時都不需做改變,只需配置Manifest。2015年推出的Android 6.0,加入了危險權(quán)限管理。因手機廠商對ROM的修改,部分6.0以上機器并不支持此項特性。
??到了第四階段,App需要在對權(quán)限代碼進行修改后,才能正常使用對應(yīng)權(quán)限。簡單理解為3步:1、判斷是否授權(quán);2、如果未授權(quán)需申請權(quán)限,根據(jù)授權(quán)結(jié)果繼續(xù)執(zhí)行;3、已授權(quán)可以繼續(xù)操作。
??例:Pixel2,原生Android 10;華為mate8,基于Android 8.0的EMUI8。瀏覽器掃碼功能觸發(fā)相機調(diào)用時,會彈出權(quán)限提示窗。此窗,由App通知系統(tǒng)彈出,為系統(tǒng)級權(quán)限彈窗。

pixel2授權(quán)彈窗
華為mate8授權(quán)彈窗

??第三階段與第四階段,同為系統(tǒng)彈出授權(quán)彈窗。二者有什么區(qū)別嗎?
??首先,從UI上很難判斷所彈授權(quán)窗為第三階段或第四階段。第三階段彈的系統(tǒng)授權(quán)窗大都帶有一個倒計時自動拒絕邏輯;第四階段彈的系統(tǒng)授權(quán)窗基本不帶自動拒絕邏輯。此點可以粗略判斷系統(tǒng)使用的哪種機制。
??其次,從原理上。第三階段的彈窗,為系統(tǒng)監(jiān)測到App在使用危險權(quán)限行為自動彈出彈窗。第四階段的彈窗,為App發(fā)覺自己沒有權(quán)限,讓系統(tǒng)彈出的彈窗。粗俗的理解,第三階段,你去朋友家串門,到門口看到大門敞開就直接往里走,觸發(fā)了紅外線報警器,報警器通知了你朋友;第四階段,你去朋友家串門,到門口發(fā)覺門關(guān)著,就按下門鈴呼叫朋友給你開門。
??目前,國內(nèi)主要處于第三階段(涵蓋Android4.0~7.1)和第四階段(涵蓋Android6.0~10),此點將在后文用到。

如何應(yīng)對動態(tài)權(quán)限特性

方案一:逃避

??因為動態(tài)權(quán)限特性,僅從Android 6.0開始擁有,所以,可以簡單粗暴的通過不提升targetSDK(targetSDK<23)的方式,便可不觸發(fā)此特性。

targetSDK18正常獲取IMEI
僅提升targetSDK到26直接運行崩潰

??如果不改變?nèi)魏未a,直接將targetSDK提升到26,然后運行App,做同樣操作時會發(fā)生異常甚至崩潰,崩潰舉例如下:

無PHONE_STATE獲取IMEI崩潰

??產(chǎn)生這個崩潰的原因,是在Android 6.0及以上,未獲取權(quán)限的情況下直接執(zhí)行了需要權(quán)限的操作。那么如何解決呢,就涉及到了真正的修改方案。

方案二:實現(xiàn)動態(tài)權(quán)限

1. 在使用權(quán)限前,檢測權(quán)限。

??首先,我們需要判斷自己是否擁有權(quán)限。判斷時間點為執(zhí)行需要權(quán)限的對應(yīng)操作前。如我們在獲取IMEI前,需要判斷是否擁有PHONE_STATE權(quán)限。
??我們可以調(diào)用ContextCompat.checkSelfPermission()方法檢測授權(quán)狀態(tài),返回的結(jié)果為PackageManager中的兩個常量:PERMISSION_GRANTED(已授權(quán))和PERMISSION_DENIED(未授權(quán))。

2. 已授權(quán)的情況下,執(zhí)行你的原有操作。

??當(dāng)已授權(quán)時,就可以執(zhí)行你原有的操作了。代碼如下:

 // 檢測PHONE_STATE 如果已授權(quán)
 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
     //做你想做的
 }

??那么如果未授權(quán)怎么辦?

3. 未授權(quán)的情況下,申請權(quán)限。

??如果App未獲得授權(quán),我們就需要向用戶申請授權(quán)??梢哉{(diào)用requestPermissions()方法來請求授權(quán)。代碼如下:

 // 檢測PHONE_STATE 如果未授權(quán)
 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
     //申請權(quán)限
     ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), PERMISSIONS_REQUEST_PHONE_STATE)
 }

requestPermissions()中的第三個參數(shù)是一個int型請求碼,方便回調(diào)處理。
??調(diào)用申請授權(quán)方法后,ROM會調(diào)起一個系統(tǒng)級彈窗(如下圖),這個dialog你無法定制。當(dāng)用戶點擊同意后,系統(tǒng)會記錄,下次再判斷權(quán)限時就會返回已授權(quán)狀態(tài);當(dāng)App卸載時,記錄會被清除。

Android 10授權(quán)彈窗

??以上,就完成了最樸素版的授權(quán)邏輯。整體代碼如下:

 // 檢測PHONE_STATE 如果未授權(quán)
 if (ContextCompat.checkSelfPermission(this,Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
     //申請權(quán)限
     ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_PHONE_STATE), PERMISSIONS_REQUEST_PHONE_STATE)
 }else {
     //如果已授權(quán)做你想做的
 }

??那么彈出申請彈窗之后呢?上面說道,彈出的dialog為系統(tǒng)的,我們無法在dialog中加代碼,但當(dāng)彈窗被用戶點擊后,會觸發(fā)回調(diào),我們在指定函數(shù)中處理回調(diào)即可。

4. 重寫函數(shù),處理授權(quán)彈窗的點擊結(jié)果。

??直接在Activity或Fragment中重寫onRequestPermissionsResult()函數(shù),來處理權(quán)限申請結(jié)果。requestPermissions()的第三個參數(shù),將在這里被用到。代碼如下:

 // 處理授權(quán)彈窗回調(diào)
 override fun onRequestPermissionsResult(
     requestCode: Int,
     permissions: Array<out String>,
     grantResults: IntArray
 )
 {
     when(requestCode){
         // 識別剛剛用到的請求碼,根據(jù)請求碼識別不同彈窗回調(diào)并處理
         PERMISSIONS_REQUEST_PHONE_STATE ->{
             // 如果用戶點擊“允許”
             if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                 Toast.makeText(this'用戶允許權(quán)限!',Toast.LENGTH_SHORT).show()
                 // 可以繼續(xù)執(zhí)行你原來想做的事情了
 
             }else{
                 Toast.makeText(this'用戶拒絕權(quán)限!',Toast.LENGTH_SHORT).show()
                 // 用戶拒絕了,你想咋辦?
             }
             return;
         }
         // 可以識別其他請求碼并處理
     }
 }

??這樣,就完成了授權(quán)流程。然后,為提升授權(quán)概率,對流程進行優(yōu)化。

5. 優(yōu)化授權(quán)流程,提高授權(quán)幾率。

??首先,系統(tǒng)授權(quán)窗我們無法定制,但是我們可以在這之前做個引導(dǎo)。在觸發(fā)系統(tǒng)彈窗之前,彈出一個引導(dǎo)UI,來告知用戶將要申請權(quán)限,并說明所需權(quán)限可帶來哪些更好體驗。尤其當(dāng)你申請的權(quán)限看似與主要功能并無關(guān)系時,比如一個相機App如果需要申請定位權(quán)限的時候。
??其次,谷歌官方還提供了個函數(shù)shouldShowRequestPermissionRationale(),這個函數(shù)可以用來判斷,用戶上次是否拒絕了且未選則不再詢問。可以在授權(quán)前,通過此判斷,來決定給用戶展示首次授權(quán)引導(dǎo)或非首次授權(quán)引導(dǎo)。
??最后,當(dāng)用戶還是選擇了拒絕授權(quán)時,如果是必要權(quán)限(比如導(dǎo)航軟件申請定位權(quán)限),我們可以通過處理授權(quán)回調(diào),在用戶點擊拒絕時彈出引導(dǎo),告知用戶功能不可用,并引導(dǎo)用戶重新授權(quán)或到設(shè)置中手動開啟權(quán)限。
??以上3部分大體流程如下:

引導(dǎo)授權(quán)流程

綜上,動態(tài)權(quán)限主要實現(xiàn)步驟

  1. 在AndroidManifest明確我們需要哪些權(quán)限。(非動態(tài)權(quán)限也需要此步)
  2. 在執(zhí)行操作前檢是否獲得對應(yīng)授權(quán) -> checkSelfPermission()。
  3. 如果已授權(quán)可以繼續(xù)操作;如果未授權(quán),判斷之前是否授權(quán)被拒 -> shouldShowRequestPermissionRationale() (非必須操作)
    a) 判斷如果沒有被拒過,彈出首次授權(quán)引導(dǎo)。
    b) 判斷如果被據(jù)過,彈出非首次授權(quán)引導(dǎo)。
  4. 引導(dǎo)后,申請權(quán)限-> requestPermissions()。
  5. 處理申請的結(jié)果信息-> 回調(diào)函數(shù)onRequestPermissionsResult()。

??系統(tǒng)一共提供如下4個函數(shù)完成動態(tài)權(quán)限相關(guān)操作。

    /**
     * 檢查指定的權(quán)限是否授權(quán)(Context對象調(diào)用)
     */

    public static int checkSelfPermission (Context context, 
                String permission)


    /**
     * 在沒有授權(quán)的情況下,有些時候可能需要提示給用戶為什么需要改權(quán)限,就通過該函數(shù)來實現(xiàn)。
     * 關(guān)于shouldShowRequestPermissionRationale的返回值問題,我們分三種情況
     * 1. 第一次打開App時 -> false
     * 2. 上次彈出權(quán)限點擊了禁止(但沒有勾選“下次不在詢問”) -> true
     * 3. 上次選擇禁止并勾選:下次不在詢問 -> false
     */

    public static boolean shouldShowRequestPermissionRationale (Activity activity, 
                String permission)


    /**
     * 申請指定的權(quán)限(Activity或者Fragment對象調(diào)用)
     * @param permissions 權(quán)限列表,可以同時申請多個權(quán)限
     * @param requestCode 該次權(quán)限申請對應(yīng)的requestCode。和 onRequestPermissionsResult()回調(diào)函數(shù)里面的requestCode對應(yīng)
     */

    public static void requestPermissions (Activity activity, 
                String[] permissions, 
                int requestCode)


    /**
     * 處理請求權(quán)限的響應(yīng),當(dāng)用戶對請求權(quán)限的dialog做出響應(yīng)之后,系統(tǒng)會回調(diào)該函數(shù)(Activity或者Fragment中重寫)
     * @param requestCode 申請權(quán)限對應(yīng)的requestCode
     * @param permissions 權(quán)限列表
     * @param grantResults 權(quán)限列表對應(yīng)的返回值,判斷permissions里面的每個權(quán)限是否申請成功
     */

    public abstract void onRequestPermissionsResult (int requestCode, 
                String[] permissions, 
                int[] grantResults)



??寫到這里,動態(tài)授權(quán)實現(xiàn)demo部分均已完成,實際業(yè)務(wù)場景肯定比以上流程復(fù)雜的多。

系統(tǒng)版本兼容

??動態(tài)權(quán)限為Android 6.0新特性,那低于6.0的系統(tǒng),該如何寫適配代碼呢?
??首先想到的,是判斷系統(tǒng)版本,針對6.0以上使用動態(tài)權(quán)限代碼,針對低版本,使用老代碼。

 fun test(){
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
         // 走動態(tài)授權(quán)
         return
     else
         // 走非動態(tài)授權(quán)
         return
 }

??其實,可以不必如此麻煩。對于低版本,可以不必單獨寫代碼適配。在不支持動態(tài)授權(quán)的系統(tǒng)上,Manifest中申請過的權(quán)限,checkSelfPermission()方法,會直接返回PERMISSION_GRANTED。
??另外,根據(jù)系統(tǒng)版本區(qū)分是否支持動態(tài)權(quán)限,實際是不靠譜的。前文有提到,部分手機廠商在ROM提升到Android 6.0以后,閹割了動態(tài)權(quán)限特性。目前沒有找到準(zhǔn)確的API判斷當(dāng)前系統(tǒng)是否支持動態(tài)權(quán)限。這會帶來什么問題呢?
??舉一個前不久遇到的實例。App的某一功能,是對別人顯示我所在城市(地理位置屬于敏感數(shù)據(jù)),用戶反饋關(guān)閉系統(tǒng)定位權(quán)限后,仍會顯示他所在城市。我們需要考慮如何解決用戶的問題,所以增加個需求,如果用戶關(guān)閉了定位權(quán)限,則不獲取城市。那么問題來了,怎么判斷用戶是否關(guān)閉了定位權(quán)限呢?為了避開不支持動態(tài)權(quán)限的ROM,需求只能退一步,6.0及以上系統(tǒng)做以上邏輯,6.0以下直接不獲取地理位置。但是根據(jù)測試經(jīng)驗6.0以上系統(tǒng)仍不一定支持動態(tài)權(quán)限, 7.0及以上系統(tǒng),絕大部分ROM支持動態(tài)權(quán)限。所以妥協(xié)決定7.0以下全部不獲取,7.0以上調(diào)checkSelfPermission()判斷是否授權(quán),少數(shù)不支持動態(tài)權(quán)限的設(shè)備會誤認(rèn)為已授權(quán),需要增加設(shè)置項關(guān)閉功能。(提升到Android8.0應(yīng)該是絕對安全的,不過覆蓋量太少)
??以下為目前主流國內(nèi)廠商對動態(tài)權(quán)限支持情況。(測試方法:在全新安裝未進行過授權(quán)操作的情況下,使用checkSelfPermission()檢查PHONE_STATE、定位、相機權(quán)限,返回如果是PERMISSION_GRANTED,則認(rèn)為不支持動態(tài)權(quán)限)

?基于Android6.0的ROM基于Android7.0的ROM
小米
支持
華為支持支持
OPPO不支持支持
VIVO不支持7.1.1不支持
7.1.2支持部分權(quán)限
魅族
支持
錘子
不支持
360不支持不支持
中興
支持

關(guān)于權(quán)限彈窗

1. 授權(quán)彈窗元素

Android 8.0授權(quán)彈窗
  1. 權(quán)限組icon
  2. App名稱
  3. 申請的權(quán)限
  4. 允許、拒絕 操作
  5. 不再詢問選項
  6. 多彈窗索引

2. 是否存在不再詢問選項

??關(guān)于權(quán)限彈窗,針對同一個App的同一個權(quán)限,有時彈窗不帶“拒絕&不再詢問”選項,有時帶此選項。如下圖是谷歌原生系統(tǒng)、小米MIUI系統(tǒng)的兩種彈窗對比。這是什么原因呢?Android原生實現(xiàn):App全新安裝后首次申請權(quán)限,彈窗不帶此選項,即圖左效果。當(dāng)用戶拒絕授權(quán)后,App下次再申請該權(quán)限時,則帶此選項,即圖右效果。但是,國內(nèi)部分手機廠商并未遵循此標(biāo)準(zhǔn),比如華為的Android 10之前的系統(tǒng)、OPPO/VIVO的部分權(quán)限,授權(quán)彈窗不管是否首次,都帶此選項。此為系統(tǒng)行為,App無法決定。

pixel2不再詢問
MIUI不再詢問

3. 彈窗選項與App設(shè)置中權(quán)限選項對應(yīng)關(guān)系

??系統(tǒng)的授權(quán)彈窗,實際具有3項(允許、拒絕、 拒絕不再詢問)。但設(shè)置中的App權(quán)限選項,有的系統(tǒng)有2項(允許、拒絕),有的有3項(允許、詢問、拒絕)。授權(quán)彈窗選項與設(shè)置中的選項對應(yīng)關(guān)系如下。

以原生Android 10系統(tǒng)為例:

  • 彈窗 允許 -> 設(shè)置 允許;
  • 彈窗 拒絕 -> 設(shè)置 拒絕;
  • 彈窗 拒絕&不再詢問 -> 設(shè)置 拒絕 (跟上一項UI一致,本質(zhì)有區(qū)別)。
pixel2彈窗對應(yīng)設(shè)置

以基于Android 9.0的MIUI10.4.8為例:

  • 彈窗 允許 -> 設(shè)置 允許;
  • 彈窗 拒絕 -> 設(shè)置 詢問;
  • 彈窗 拒絕&不再詢問 -> 設(shè)置 拒絕。
MIUI彈窗對應(yīng)設(shè)置

4. 彈窗選項對四個函數(shù)的影響。

??彈窗彈出,用戶操作指定選項后,下次再調(diào)用四個函數(shù)會有如下現(xiàn)象:

UI選項與函數(shù)調(diào)用結(jié)果

權(quán)限分類

??Android 6.0系統(tǒng)開始,權(quán)限被分為Normal permissions、Signature permissions、Dangerous permissions,其中Signature permissions比較超綱,僅介紹普通權(quán)限和危險權(quán)限。
??其中普通權(quán)限使用方法跟低版本一樣,只用在Manifest里申請就可使用。大部分低風(fēng)險權(quán)限,不需要通過確認(rèn)框這種形式讓用戶顯示的同意。比如訪問網(wǎng)絡(luò)、檢查WiFi狀態(tài)等權(quán)限。
??另一種危險權(quán)限,也就是本文介紹的對象,它的產(chǎn)生主要為了保護用戶隱私,換言之,涉及到用戶隱私的一些權(quán)限,屬于危險權(quán)限。例如:相機權(quán)限、定位權(quán)限、PHONE_STATE(可讀取手機IMEI等識別碼)權(quán)限等。
??危險權(quán)限和權(quán)限組。(不同系統(tǒng)危險權(quán)限可能不同)

危險權(quán)限

??關(guān)于權(quán)限,還有一個權(quán)限組的概念。例如,讀取外置存儲權(quán)限(READ_EXTERNAL_STORAGE)和寫入外置存儲權(quán)限(WRITE_EXTERNAL_STORAGE),同屬存儲權(quán)限組(STORAGE)。
??權(quán)限組有什么作用呢?在Android O之前,同一權(quán)限組的權(quán)限,只要用戶授權(quán)一個,則整個權(quán)限組都被授權(quán)。
例如:
步驟一:Manifest中加入了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE
步驟二:在程序中只申請了READ_EXTERNAL_STORAGE權(quán)限,用戶同意后
步驟三:在程序中未申請WRITE_EXTERNAL_STORAGE權(quán)限,并嘗試直接使用
結(jié)果:可以直接使用,同組權(quán)限不需再申請。

??而Android O對此進行了修改。同一權(quán)限組不同權(quán)限,必須都要動態(tài)申請權(quán)限。但是如果第一個被用戶同意了,后面的同組權(quán)限再申請時,就不會再彈窗而是被直接同意了。
例如:
步驟一:Manifest中加入了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE
步驟二:在程序中只申請了READ_EXTERNAL_STORAGE權(quán)限,用戶同意后
步驟三:在程序中未申請WRITE_EXTERNAL_STORAGE權(quán)限,并嘗試直接使用
結(jié)果:崩潰。
修改步驟三:在程序中申請WRITE_EXTERNAL_STORAGE權(quán)限
結(jié)果:不會彈出授權(quán)彈窗,同一權(quán)限組直接被自動授權(quán)

??But,部分ROM修改了此邏輯。比如,華為9.0以下系統(tǒng),遵循的是原生系統(tǒng)Android 8.0之前的邏輯。但是,華為9.0以后系統(tǒng)和小米6.0以后系統(tǒng),都用的比原生系統(tǒng)Android 8.0更嚴(yán)格的邏輯。每個權(quán)限都需要單獨申請權(quán)限,而且會單獨彈窗要求用戶確認(rèn)。
例如:
步驟一:Manifest中加入了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE
步驟二:在程序中只申請了READ_EXTERNAL_STORAGE權(quán)限,用戶同意后
步驟三:在程序中申請WRITE_EXTERNAL_STORAGE權(quán)限
結(jié)果:會彈出授權(quán)彈窗,需要用戶再次授權(quán)
帶來問題:相同權(quán)限組不同權(quán)限的授權(quán)彈窗是一毛一樣的。這就導(dǎo)致用戶很懵逼,明明剛剛授權(quán)過了,為什么又要問我一次。

不同ROM權(quán)限組內(nèi)影響

??所以,部分手機上,你會發(fā)覺有些App,先后彈出兩個訪問文件存儲的權(quán)限彈窗。那是因為寫App的時候,先后申請了READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE權(quán)限導(dǎo)致。如何解決?
??查看requestPermissions()方法的第二個參數(shù),為一個數(shù)組。也就是說,可以傳入一個權(quán)限列表。

    /**
     * 申請指定的權(quán)限(Activity或者Fragment對象調(diào)用)
     * @param permissions 權(quán)限列表,可以同時申請多個權(quán)限
     * @param requestCode 該次權(quán)限申請對應(yīng)的requestCode。和 onRequestPermissionsResult()回調(diào)函數(shù)里面的requestCode對應(yīng)
     */

    public static void requestPermissions (Activity activity, 
                String[] permissions, 
                int requestCode)

??經(jīng)測試,如果直接調(diào)該方法同時傳入READ_EXTERNAL_STORAGE、WRITE_EXTERNAL_STORAGE只會彈出一個授權(quán)窗,而且用戶同意后可以同時獲得兩個權(quán)限。如果傳入不同組權(quán)限,則按先后每組彈出一個彈窗。而且,這種單次傳入多組權(quán)限的情況,彈窗中大都會出現(xiàn)一個m/n的編號,以標(biāo)識彈到第幾個,還剩幾個。如下圖分別是MIUI10(基于android9)和EMUI10(基于android10)的彈窗樣式:

紅米Note8Pro連續(xù)授權(quán)窗
華為Mate20連續(xù)授權(quán)窗

寫在最后

后期的一些權(quán)限策略變化,僅列部分戶感知較大的。

  • IOS 8(2014年),定位權(quán)限選項分為“使用期間”(新增項)、“始終允許”、“不允許”。(減少App后臺定位)
  • IOS 10(2016年),App訪問網(wǎng)絡(luò)需要授權(quán)。
  • Android 8.0(2017年),
    • 安裝未知來源應(yīng)用需要申請權(quán)限。(App自升級、三方應(yīng)用市場、廣告App安裝其他App需申請權(quán)限)
    • 權(quán)限組授權(quán)問題修復(fù),上文有提及。
  • Android 10(2019年),
    • 定位權(quán)限選項分為“使用期間”(新增項)、“始終允許”、“拒絕”。(減少App后臺定位)
    • 部分電話、藍(lán)牙、WLAN的API,需要申請精確位置權(quán)限。
    • 無法再獲取手機IMEI
  • IOS 13(2019年),定位權(quán)限選項分為“使用App時允許”、“允許一次”(新增選項)、“不允許”,去除了“始終允許”。(“允許一次”相當(dāng)于試用權(quán)限或臨時權(quán)限,重啟App后需要重新申請權(quán)限)
  • Android 11 預(yù)覽版(2020年),
    • 分區(qū)存儲強制執(zhí)行。Download目錄、SD卡目錄訪問受限。
    • 對位置、麥克風(fēng)、相機增加一次性權(quán)限許可,見IOS 13定位權(quán)限(即,如果用戶選了一次性許可,重啟App后需要重新申請權(quán)限)。
    • 自動阻止App重復(fù)的權(quán)限請求。也就是說如果用戶點擊2次拒絕授權(quán),那么系統(tǒng)會自動停止詢問授權(quán),當(dāng)然了,用戶也可以前往設(shè)置中手動調(diào)整。

??兩大平臺,都在多個版本中對用戶隱私進行了優(yōu)化,僅定位權(quán)限的優(yōu)化就多次提及。

??可見,在手機逐漸轉(zhuǎn)化為人體器官之一的今天,IOS和Android兩大移動平臺對于權(quán)限、隱私的管理越發(fā)嚴(yán)苛,而且趨同的速度約來越快。估計以后Android App想訪問網(wǎng)絡(luò)也需申請授權(quán)。但手機廠商自行定制修改ROM,仍是開發(fā)者最頭疼的問題。

參考文獻:谷歌官方文檔:https://developer./training/permissions/requesting.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多