国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

一篇文章搞定《Android權(quán)限問題(全版本)》

這篇具有很好參考價值的文章主要介紹了一篇文章搞定《Android權(quán)限問題(全版本)》。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、前言

文章內(nèi)容如下:
如果你只是想快速的完成你Android權(quán)限申請的工作,那么直接上工具PermissionX
如果是想真正的了解Android的權(quán)限問題,那么建議你用15分鐘通讀一下本文。(可以不去實驗,收藏以備后用)
首先了解Android版本和SDK的關(guān)系,幫助我們分辨后面的權(quán)限版本。
其次把最常見的Android7-13版本的我們需要注意的權(quán)限問題聊一下。
最后是現(xiàn)在App都需要的動態(tài)申請權(quán)限的工具使用。

二、Android版本和SDK版本的關(guān)系

目前最新的Android版本已經(jīng)到了Android13,相應(yīng)的SDK版本也達到了33。說的不如看圖快,直接看。
位置:(Android Studio -> Preferences -> Appearance & Behavior -> System Settings -> Android SDK)

一篇文章搞定《Android權(quán)限問題(全版本)》

三、Android版本變化中權(quán)限的變化

這里說一下比較明顯變化的版本,還有最近幾個版本的變化:
眾所周知Android5.1 -> Android6.0的權(quán)限變化,都被大家了解爛了。但還是要說一下,多看看對你沒壞處。
可以看到Android5.1到Android6.0的權(quán)限變化,也就是對應(yīng)著我們的SDK23版本
也就是說當(dāng)build.gradle中targetSdkVersion設(shè)置小于23時,會繼續(xù)引用舊版本權(quán)限管理機制,當(dāng)targetSdkVersion大于等于23時,則會使用新的權(quán)限管理。

1、Android5以前 — targetSdkVersion < 23

當(dāng)targetSdkVersion小于23時,你的項目會繼續(xù)使用舊版本的權(quán)限機制:
所申請的權(quán)限只需要在AndroidManifest.xml列舉就可以(如下),從而容易導(dǎo)致一些安全隱患:
一篇文章搞定《Android權(quán)限問題(全版本)》
1、用戶在安裝時獲取到所有權(quán)限,在使用權(quán)限時無需進行預(yù)判斷。
2、如果用戶手動來到設(shè)置將權(quán)限關(guān)閉,我們的項目在用到該權(quán)限時會發(fā)生Crash,所以如果使用低版本權(quán)限管理,請將需要用到權(quán)限的地方try-catch起來。
3、低版本權(quán)限提示彈窗都是手機廠商自定義的。他們擁有系統(tǒng)權(quán)限,在檢測到你的App使用權(quán)限時會提示用戶權(quán)限授權(quán),如果用戶拒絕則替用戶到設(shè)置中心關(guān)閉權(quán)限。

2、Android6 — targetSdkVersion23

1、將權(quán)限分為了普通權(quán)限和隱私權(quán)限,普通權(quán)限在清單文件中聲明則直接獲取。隱私權(quán)限也需要在清單文件中聲明,但是在安裝完成后,所有的隱私權(quán)限都為拒絕狀態(tài),需要在用到隱私權(quán)限時判斷權(quán)限是否開啟,否則項目直接發(fā)生Crash。
比如常用的隱私權(quán)限:相機、定位、打電話、短信、讀寫存儲、麥克風(fēng)錄音、傳感器。(具體的看下圖)
一篇文章搞定《Android權(quán)限問題(全版本)》
上圖中有一個權(quán)限群的概念,同一組的任何一個權(quán)限被授權(quán)了,其他權(quán)限也自動被授權(quán)。
例如,一旦WRITE_EXTERNAL_STORAGE被授權(quán)了,APP同時也就有了READ_EXTERNAL_STORAGE權(quán)限。
這里申請權(quán)限的步驟想必大家也是清楚的,我就隨便提一嘴。(因為可以直接使用下面的PermissionX去幫你減少這些繁瑣的權(quán)限處理過程)
1、在AndroidManifest.xml聲明
2、檢查我們未授權(quán)的權(quán)限checkSelfPermission(Context context, String permission)
3、申請我們的權(quán)限r(nóng)equestPermissions(Activity activity, String[] permissions, int requestCode)
4、申請權(quán)限的結(jié)果onRequestPermissionsResult(int requestCode, String[] permissions, String[] grantResults)
5、后續(xù)就是自己處理邏輯了(PermissionX提供了一些處理方案)

3、Android7 — targetSdkVersion24、25

為了提高私有目錄的安全性,防止應(yīng)用信息的泄漏,從 Android 7.0 開始,應(yīng)用私有目錄的訪問權(quán)限被做限制。具體表現(xiàn)為,開發(fā)人員不能夠再簡單地通過 file:// URI 訪問其他應(yīng)用的私有目錄文件或者讓其他應(yīng)用訪問自己的私有目錄文件。會觸發(fā) FileUriExposedException的錯誤異常。
解決辦法:使用FileProvider(具體使用不做贅述了)
作為四大組件之一的 ContentProvider,一直扮演著應(yīng)用間共享資源的角色。這里我們要使用到的 FileProvider,就是 ContentProvider 的一個特殊子類,幫助我們將訪問受限的 file:// URI 轉(zhuǎn)化為可以授權(quán)共享的 content:// URI。

4、Android8 — targetSdkVersion26、27

Android 8.0 之前,如果應(yīng)用在運行時請求權(quán)限并且被授予該權(quán)限,系統(tǒng)會錯誤地將屬于同一權(quán)限組并且在清單中注冊的其他權(quán)限也一起授予應(yīng)用。(上面有提到權(quán)限組)
對于針對 Android 8.0 的應(yīng)用,此行為已被糾正。系統(tǒng)只會授予應(yīng)用明確請求的權(quán)限。然而,一旦用戶為應(yīng)用授予某個權(quán)限,則所有后續(xù)對該權(quán)限組中權(quán)限的請求都將被自動批準。
出現(xiàn)的問題大家也就知道了,就是之前申請了READ_EXTERNAL_STORAGE相應(yīng)的WRITE_EXTERNAL_STORAGE也會申請,而現(xiàn)在不可以。
解決方案:之前沒動態(tài)申請WRITE_EXTERNAL_STORAGE的再加入申請權(quán)限列表中申請就可以了。
但是這里READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE是一個權(quán)限組,所以申請的時候也只是提示你同意一個存儲權(quán)限就可以了。

5、Android9 — targetSdkVersion28

前臺服務(wù)需要添加權(quán)限
在安卓9.0版本之后,必須要授予FOREGROUND_SERVICE權(quán)限,才能夠使用前臺服務(wù),否則會拋出異常。

6、Android10 — targetSdkVersion29

重點來了:作用域存儲(這個帶好好說一說,因為這是很多應(yīng)用都會遇到的問題)
這個新功能直接顛覆了長久以來我們一直慣用的外置存儲空間的使用方式,因此大量App都將面臨著較多代碼模塊的升級。
Android長久以來都支持外置存儲空間這個功能,也就是我們常說的SD卡存儲。故App都喜歡在SD卡的根目錄下建立一個自己專屬的目錄,用來存放各類文件和數(shù)據(jù)。
優(yōu)點:第一,存儲在SD卡的文件不會計入到應(yīng)用程序的占用空間當(dāng)中,也就是說即使你在SD卡存放了1G的文件,你的應(yīng)用程序在設(shè)置中顯示的占用空間仍然可能只有幾十K。
第二,存儲在SD卡的文件,即使應(yīng)用程序被卸載了,這些文件仍然會被保留下來,這有助于實現(xiàn)一些需要數(shù)據(jù)被永久保留的功能。
缺點:第一,流氓行為即使我卸載了一個完全不再使用的程序,它所產(chǎn)生的垃圾文件卻可能會一直保留在我的手機上
第二,存儲在SD卡上的文件屬于公有文件,所有的應(yīng)用程序都有權(quán)隨意訪問,這也對數(shù)據(jù)的安全性帶來了很大的挑戰(zhàn)。(這種流氓行為Google他出手了,也就是作用域存儲)
Google的作用域到底是什么:
從Android 10開始,每個應(yīng)用程序只能有權(quán)在自己的外置存儲空間關(guān)聯(lián)目錄下讀取和創(chuàng)建文件。
獲取該目錄的代碼為:

context.getExternalFilesDir()
// storage/emulated/0/Android/data/<包名>/files(大概目錄為)

將數(shù)據(jù)存放到這個目錄下,你將可以完全使用之前的寫法來對文件進行讀寫,不需要做任何變更和適配。但同時,剛才提到的那兩個“好處”也就不存在了。也就是應(yīng)用刪除相關(guān)存儲也會消失。
那么有些朋友可能會問了,我就是需要訪問其他目錄該怎么辦呢?比如讀取手機相冊中的圖片,或者向手機相冊中添加一張圖片。
為此,Android系統(tǒng)針對文件類型進行了分類,圖片、音頻、視頻這三類文件將可以通過MediaStore API來進行訪問,而其他類型的文件則需要使用系統(tǒng)的文件選擇器來進行訪問。
具體的適配Android10的解決方案寫在下面了:Android10存儲適配方案

7、Android11 — targetSdkVersion30

如果按照Android10的解決方案進行適配了,那么就什么都不需要做。
如果是暫時的設(shè)置了requestLegacyExternalStorage=“true”

<manifest ... >
  <application android:requestLegacyExternalStorage="true" ...>
    ...
  </application>
</manifest>

那么恭喜你:Scoped Storage就會被強制啟用。也就是requestLegacyExternalStorage設(shè)置無效。
解決方案
1、按照Android10的解決方案進行適配(最好適配了。不然后續(xù)版本也要不斷修改)
2、你必須在AndroidManifest.xml中聲明MANAGE_EXTERNAL_STORAGE權(quán)限

 <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
     tools:ignore="ScopedStorage" />

注意相比于傳統(tǒng)聲明一個權(quán)限,這里增加了tools:ignore="ScopedStorage"這樣一個屬性。因為如果不加上這個屬性,Android Studio會用一個警告提醒我們,絕大部分的應(yīng)用程序都不應(yīng)該申請這個權(quán)限。
之后利用ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION這個action來跳轉(zhuǎn)到指定的授權(quán)頁面,進行授權(quán)。(所以還是去適配Android10的解決方案吧)

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R ||
        Environment.isExternalStorageManager()) {
    Toast.makeText(this, "已獲得訪問所有文件權(quán)限", Toast.LENGTH_SHORT).show()
} else {
    val builder = AlertDialog.Builder(this)
        .setMessage("本程序需要您同意允許訪問所有文件權(quán)限")
        .setPositiveButton("確定") { _, _ ->
            val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION)
            startActivity(intent)
        }
    builder.show()
}

8、Android12 — targetSdkVersion31、32

1、新增模糊定位功能,用戶可以選擇讓應(yīng)用只能訪問大致位置。
在Android12上,如果你的應(yīng)用需要獲取用戶準確的位置信息,那么就需要同時申請準確位置和大概位置兩項權(quán)限,AndroidManifest.xml文件中的代碼如下:

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>

注意:此兩項權(quán)限也都需要動態(tài)申請
2、獲取安裝的應(yīng)用列表權(quán)限
在Android 11上在使用PackageManger的方法來獲取安裝的應(yīng)用列表的時候就需要在AndroidManifest.xml文件中進行申請android.permission.QUERY_ALL_PACKAGES此權(quán)限了,但是Android12中部分手機還要添加android.permission.GET_INSTALLED_APPS權(quán)限才能正常獲取到應(yīng)用列表,權(quán)限代碼如下:

    <uses-permission android:name="android.permission.GET_INSTALLED_APPS"/>
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"
        tools:ignore="QueryAllPackagesPermission" />

android12雖然不用動態(tài)申請這兩個權(quán)限,但是首次進入應(yīng)用還會出現(xiàn)授權(quán)訪問的提示。
3、藍牙運行時權(quán)限:
新增了幾個藍牙相關(guān)的運行時權(quán)限。原因是因為當(dāng)開發(fā)者去訪問一些藍牙相關(guān)的接口時,卻需要申請地理位置權(quán)限才行,這就讓一些對隱私敏感的用戶非常反感。下面三個哦。
BLUETOOTH_SCAN,BLUETOOTH_ADVERTISE,BLUETOOTH_CONNECT。

9、Android13 — targetSdkVersion33

1、Google在Android 13上對本地數(shù)據(jù)訪問權(quán)限做了更進一步的細化
從Android 13開始,如果你的應(yīng)用targetSdk指定到了33或以上,那么READ_EXTERNAL_STORAGE權(quán)限就完全失去了作用,申請它將不會產(chǎn)生任何的效果。
相對應(yīng)地,Google新增了READ_MEDIA_IMAGES、READ_MEDIA_VIDEO和READ_MEDIA_AUDIO這3個運行時權(quán)限,分別用于管理手機的照片、視頻和音頻文件。
也就是說,以前只要申請一個READ_EXTERNAL_STORAGE權(quán)限就可以了?,F(xiàn)在不行了,得按需申請,用戶從而能夠更加精細地了解你的應(yīng)用到底申請了哪些媒體權(quán)限。

<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />

2、通知運行時權(quán)限
在之前的Android系統(tǒng)中,任何一個應(yīng)用想要發(fā)出通知的話都是不需要經(jīng)過用戶同意的,想發(fā)就能發(fā)。這就使得我們的手機通知欄經(jīng)常被一些垃圾通知占領(lǐng)
這次Android 13則把通知納入了運行時權(quán)限管理,也就是說,以后想要發(fā)送通知,得要先經(jīng)過用戶同意授權(quán)才行了。

<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

3、WIFI運行時權(quán)限
和藍牙類似,當(dāng)開發(fā)者去訪問一些WIFI相關(guān)的接口時,如熱點、WIFI直連、WIFI RTT等,也需要申請地理位置權(quán)限才行。

Android 13當(dāng)中新增了一個NEARBY_WIFI_DEVICES權(quán)限,當(dāng)再使用以上場景相關(guān)的WIFI API時,我們只需申請NEARBY_WIFI_DEVICES權(quán)限即可,從而更好地保護了用戶的隱私。

四、Android10存儲權(quán)限適配

1、臨時解決方案(僅適合適配到Android10)

臨時解決方案僅僅適合在Android10上解決問題,到了Android11都是不允許的。也就是你的targetSdkVersion升級到了30就需要重新適配。
Android10的臨時解決方法很簡單,只需要在AndroidManifest.xml中加入如下配置即可:

<manifest ... >
  <application android:requestLegacyExternalStorage="true" ...>
    ...
  </application>
</manifest>

這段配置表示,即使在Android 10系統(tǒng)上,仍然允許使用之前遺留的外置存儲空間的用法來運行程序,這樣就不用對代碼進行任何修改了。

2、首先是作用域存儲(上面講到了,就不贅述)

簡單來說就是把你原來用的獲取SD卡根目錄隨意存儲的方式,換成自己的外置存儲目錄。
原來的:獲取后創(chuàng)建自己想要的文件夾存儲(Android10以上是不可以了,也就是你targetSdkVersion >= 29)

Environment.getExternalStorageDirectory()
// storage/emulated/0 (正常獲取的默認目錄)

修改為:自己的外置存儲空間,這就可以進行存儲了

context.getExternalFilesDir()
// storage/emulated/0/Android/data/<包名>/files (獲取的默認目錄)

3、讀取手機相冊、視頻、音頻

這里只舉例圖片,視頻和音頻是一樣的方式獲取。
不同于過去可以直接獲取到相冊中圖片的絕對路徑,在作用域存儲當(dāng)中,我們只能借助MediaStore API獲取到圖片的Uri,示例代碼如下:

val cursor = contentResolver.query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, "${MediaStore.MediaColumns.DATE_ADDED} desc")
if (cursor != null) {
    while (cursor.moveToNext()) {
        val id = cursor.getLong(cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID))
        val uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
        println("image uri is $uri")
    }
        cursor.close()
}

上述代碼中,我們先是通過ContentResolver獲取到了相冊中所有圖片的id,然后再借助ContentUris將id拼裝成一個完整的Uri對象。一張圖片的Uri格式大致如下所示:

content://media/external/images/media/321

那么有些朋友可能會問了,獲取到了Uri之后,我又該怎樣將這張圖片顯示出來呢?這就有很多種辦法了,比如使用Glide來加載圖片,它本身就支持傳入Uri對象來作為圖片路徑:

Glide.with(context).load(uri).into(imageView)

4、添加圖片到相冊(視頻、音頻)

將一張圖片添加到手機相冊要相對稍微復(fù)雜一點
直接上代碼:
第一步:構(gòu)建一個ContentValues對象
第二步:添加他的三個參數(shù)一個是圖片顯示的名稱:DISPLAY_NAME。一個是圖片的mime類型:MIME_TYPE。還有一個是圖片存儲的路徑,不過這個值在Android 10和之前的系統(tǒng)版本中的處理方式不一樣。Android 10中新增了一個RELATIVE_PATH常量,表示文件存儲的相對路徑,可選值有DIRECTORY_DCIM、DIRECTORY_PICTURES、DIRECTORY_MOVIES、DIRECTORY_MUSIC等,分別表示相冊、圖片、電影、音樂等目錄。而在之前的系統(tǒng)版本中并沒有RELATIVE_PATH,所以我們要使用DATA常量(已在Android 10中廢棄),并拼裝出一個文件存儲的絕對路徑才行。
第三步:調(diào)用ContentResolver的insert()方法即可獲得插入圖片的Uri。
第四步:調(diào)用ContentResolver的openOutputStream()方法獲得文件的輸出流,然后將Bitmap對象寫入到該輸出流當(dāng)中即可。

fun addBitmapToAlbum(bitmap: Bitmap, displayName: String, mimeType: String, compressFormat: Bitmap.CompressFormat) {
    val values = ContentValues()
    values.put(MediaStore.MediaColumns.DISPLAY_NAME, displayName)
    values.put(MediaStore.MediaColumns.MIME_TYPE, mimeType)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
    } else {
        values.put(MediaStore.MediaColumns.DATA, "${Environment.getExternalStorageDirectory().path}/${Environment.DIRECTORY_DCIM}/$displayName")
    }
    val uri = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
    if (uri != null) {
        val outputStream = contentResolver.openOutputStream(uri)
        if (outputStream != null) {
            bitmap.compress(compressFormat, 100, outputStream)
                        outputStream.close()
        }
    }
}

5、下載文件到Download目錄

執(zhí)行文件下載操作是一個很常見的場景,比如說下載pdf、doc文件,或者下載APK安裝包等等。在過去,這些文件我們通常都會下載到Download目錄,這是一個專門用于存放下載文件的目錄。而從Android 10開始,我們已經(jīng)不能以絕對路徑的方式訪問外置存儲空間了,所以文件下載功能也會受到影響。
第一種解決方法:同時也是最簡單的一種方式,就是更改文件的下載目錄。將文件下載到應(yīng)用程序的關(guān)聯(lián)目錄下,這樣不用修改任何代碼就可以讓程序在Android 10系統(tǒng)上正常工作。但使用這種方式,你需要知道,下載的文件會被計入到應(yīng)用程序的占用空間當(dāng)中,同時如果應(yīng)用程序被卸載了,該文件也會一同被刪除。另外,存放在關(guān)聯(lián)目錄下的文件只能被當(dāng)前的應(yīng)用程序所訪問,其他程序是沒有讀取權(quán)限的。
第二種解決方案
將文件下載到Download目錄,和向相冊中添加一張圖片的過程是差不多的,Android 10在MediaStore中新增了一種Downloads集合,專門用于執(zhí)行文件下載操作。

val values = ContentValues()
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileName)
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS)
val uri = contentResolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values)

其余你下載的流程不用改變,只替換你寫入文件的部分。

五、直接上工具:動態(tài)申請權(quán)限PermissionX

說了這么多,直接上工具,畢竟干活重要。
PermissionX1.7全面支持Android 13的運行時權(quán)限申請
正常的申請權(quán)限的:1、檢查權(quán)限、申請權(quán)限、結(jié)果返回、返回后的處理(跳轉(zhuǎn)手動的等等),代碼臃腫,流程繁瑣。有沒有,有木有。

實現(xiàn)原理

具體用法之前,我們先來簡單說一下它的實現(xiàn)原理
之后慢慢開發(fā)者們開始去衍生了一些封裝的方案,比如將運行時權(quán)限的操作封裝到BaseActivity中,或者提供一個透明的Activity來處理運行時權(quán)限等。(涉及到Activity那就是重量級了,畢竟還要注冊)
這時候有人想到了用輕量級的Fragment進行注冊,畢竟Android在Fragment中也提供了一份相同的API,使得我們在Fragment中也能申請運行時權(quán)限。
但不同的是,F(xiàn)ragment并不像Activity那樣必須有界面,我們完全可以向Activity中添加一個隱藏的Fragment,然后在這個隱藏的Fragment中對運行時權(quán)限的API進行封裝。這是一種非常輕量級的做法,不用擔(dān)心隱藏Fragment會對Activity的性能造成什么影響。
這就是PermissionX的實現(xiàn)原理了。

使用

1、引入工具

repositories {
  google()
  mavenCentral()
}

dependencies {
    implementation 'com.guolindev.permissionx:permissionx:1.7.1'
}

2、基礎(chǔ)簡單使用

PermissionX.init(this)
.permissions(Manifest.permission.CALL_PHONE)
.request { allGranted, grantedList, deniedList ->
    if (allGranted) {
        call()
    } else {
        Toast.makeText(this, "您拒絕了撥打電話權(quán)限", Toast.LENGTH_SHORT).show()
    }
}

是的,PermissionX的基本用法就這么簡單。首先調(diào)用init()方法來進行初始化,并在初始化的時候傳入一個FragmentActivity參數(shù)。由于AppCompatActivity是FragmentActivity的子類,所以只要你的Activity是繼承自AppCompatActivity的,那么直接傳入this就可以了。
接下來調(diào)用permissions()方法傳入你要申請的權(quán)限名,這里傳入CALL_PHONE權(quán)限。你也可以在permissions()方法中傳入任意多個權(quán)限名,中間用逗號隔開即可。
最后調(diào)用request()方法來執(zhí)行權(quán)限申請,并在Lambda表達式中處理申請結(jié)果??梢钥吹?,Lambda表達式中有3個參數(shù):allGranted表示是否所有申請的權(quán)限都已被授權(quán),grantedList用于記錄所有已被授權(quán)的權(quán)限,deniedList用于記錄所有被拒絕的權(quán)限。
對比原來的方式,簡單明了許多有木有?。。?!

其他情況處理

1、假如用戶拒絕了某個權(quán)限,在下次申請之前,我們最好彈出一個對話框來向用戶解釋申請這個權(quán)限的原因,這個又該怎么實現(xiàn)呢?
onExplainRequestReason()方法可以用于監(jiān)聽那些被用戶拒絕,而又可以再次去申請的權(quán)限。
而我們只需要將onExplainRequestReason()方法串接到request()方法之前即可,如下所示:

PermissionX.init(this)
.permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE)
.onExplainRequestReason { deniedList ->
}
.request { allGranted, grantedList, deniedList ->
    if (allGranted) {
        Toast.makeText(this, "所有申請的權(quán)限都已通過", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(this, "您拒絕了如下權(quán)限:$deniedList", Toast.LENGTH_SHORT).show()
    }
}

這種情況下,所有被用戶拒絕的權(quán)限會優(yōu)先進入onExplainRequestReason()方法進行處理,拒絕的權(quán)限都記錄在deniedList參數(shù)當(dāng)中。接下來,我們只需要在這個方法中調(diào)用showRequestReasonDialog()方法,即可彈出解釋權(quán)限申請原因的對話框

PermissionX.init(this)
.permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE)
.onExplainRequestReason { deniedList ->
    showRequestReasonDialog(deniedList, "即將重新申請的權(quán)限是程序必須依賴的權(quán)限", "我已明白", "取消")
}
.request { allGranted, grantedList, deniedList ->
    if (allGranted) {
        Toast.makeText(this, "所有申請的權(quán)限都已通過", Toast.LENGTH_SHORT).show()
    } else {
        Toast.makeText(this, "您拒絕了如下權(quán)限:$deniedList", Toast.LENGTH_SHORT).show()
    }
}

showRequestReasonDialog()方法接受4個參數(shù):第一個參數(shù)是要重新申請的權(quán)限列表,這里直接將deniedList參數(shù)傳入。第二個參數(shù)則是要向用戶解釋的原因,我只是隨便寫了一句話,這個參數(shù)描述的越詳細越好。第三個參數(shù)是對話框上確定按鈕的文字,點擊該按鈕后將會重新執(zhí)行權(quán)限申請操作。第四個參數(shù)是一個可選參數(shù),如果不傳的話相當(dāng)于用戶必須同意申請的這些權(quán)限,否則對話框無法關(guān)閉,而如果傳入的話,對話框上會有一個取消按鈕,點擊取消后不會重新進行權(quán)限申請,而是會把當(dāng)前的申請結(jié)果回調(diào)到request()方法當(dāng)中。
具體的功能給你個地址自己看:師傅領(lǐng)進門修行在個人文章來源地址http://www.zghlxwxcb.cn/news/detail-436161.html

到了這里,關(guān)于一篇文章搞定《Android權(quán)限問題(全版本)》的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 一篇文章搞定《APP的啟動流程》

    一篇文章搞定《APP的啟動流程》

    前面已經(jīng)鋪墊了Binder、Handler、View的繪制流程 那么該來看看APP的啟動流程了,是如何啟動了我們這些重要的組件 本文會按照步驟和啟動需要的成員并附帶一點點源碼進行講解。 以了解熟悉啟動的流程為主。不會大篇幅的利用源碼深入。 本文結(jié)構(gòu): 1、冷啟動、溫啟動、熱啟

    2024年02月16日
    瀏覽(21)
  • 一篇文章搞定克拉美羅界(CRB)

    一篇文章搞定克拉美羅界(CRB)

    二郎最近在研究LBL(長基線)定位,大部分論文都提到了文中算法獲得的方差接近CRB,所以自己的算法性能較好。于是二郎就想知道克拉美羅界是什么意思,以及能應(yīng)用的場景。 1)查文檔: 克拉美羅界:為無偏估計量的方差確定一個下界,衡量無偏估計的性能。 無偏估計:

    2024年02月15日
    瀏覽(22)
  • 【Unity】一篇文章搞定AStar(A*)算法

    【Unity】一篇文章搞定AStar(A*)算法

    AStar(A*)算法,是一種在靜態(tài)網(wǎng)格中求解最短路徑直接有效的搜索方法。在游戲開發(fā)中,A*算法常應(yīng)用于部分RPG游戲和策略戰(zhàn)棋類游戲。對于Unity開發(fā)者來說,掌握A*算法也是十分有必要的。不過在了解A*算法之前,有必要先回顧一下深度優(yōu)先算法(DFS)、廣度優(yōu)先算法(BFS)

    2024年02月02日
    瀏覽(20)
  • 一篇文章搞定Java中常用集合的排序方法

    一篇文章搞定Java中常用集合的排序方法

    目錄 Array · 數(shù)組 List · 列表 Collections.sort() 簡單類型 復(fù)雜對象 類 使用Lambda表達式 Stream API Map · 鍵值對 對 Map 的 Key 進行排序 對 Map 的 Value 進行排序 最近在做算法題的時候,發(fā)現(xiàn)排序在大部分題中都不可或缺,今天心血來潮,總結(jié)下Java中集合排序常用的方法,基本覆蓋了大

    2024年02月09日
    瀏覽(26)
  • Spring之AOP(帶你一篇文章搞定AOP)

    Spring之AOP(帶你一篇文章搞定AOP)

    Spring的核心之一:AOP 用的依賴(包括上篇文章講訴的IOC依賴): AOP:面向切面編程。利用 AOP 可以對業(yè)務(wù)邏輯的各個部分進行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發(fā)的效率。通俗來說就是在不修改代碼的情況下添加新的功能

    2024年02月16日
    瀏覽(28)
  • 一篇文章搞定什么是nodeJs它和NPM關(guān)系與應(yīng)用

    現(xiàn)在前端的入門門檻越來越高了,不再是單純 html+css+js ,各種前端框架 層出不窮,各種ui組件庫層出不窮。 模塊化,打包化,各種工具庫層出不窮,前端變成 大前端 ,甚至前端可以搞定整個項目,通過 node 作為服務(wù)端api, 這里我們主角就是 nodeJs javaScript是一門腳本語言,

    2024年02月03日
    瀏覽(27)
  • OSPF技術(shù)連載16:DR和BDR選舉機制,一篇文章搞定!

    OSPF技術(shù)連載16:DR和BDR選舉機制,一篇文章搞定!

    你好,這里是網(wǎng)絡(luò)技術(shù)聯(lián)盟站。 在計算機網(wǎng)絡(luò)中,開放最短路徑優(yōu)先(Open Shortest Path First,OSPF)是一種廣泛使用的內(nèi)部網(wǎng)關(guān)協(xié)議(Interior Gateway Protocol,IGP),用于在大型網(wǎng)絡(luò)中實現(xiàn)路由選擇。在OSPF網(wǎng)絡(luò)中,當(dāng)一個OSPF區(qū)域內(nèi)有多個路由器時,為了減少鏈路狀態(tài)數(shù)據(jù)庫(Link

    2024年02月07日
    瀏覽(26)
  • 【仿真+實測】一篇文章搞定RC延遲電路 1.延遲開啟 2.快速泄放 3.精確泄放

    【仿真+實測】一篇文章搞定RC延遲電路 1.延遲開啟 2.快速泄放 3.精確泄放

    ?作者:面向搜索,排版:曉宇 微信公眾號:芯片之家(ID:chiphome-dy) RC延遲電路 在許多芯片的應(yīng)用手冊中都要求了 對上電時序進行控制 ,在這種場合下我們會經(jīng)??吹絉C延遲,今天我們通過multisim 14.0 對RC延遲計算電路的理論計算進行仿真驗證 Multisim軟件版本 附上multisi

    2024年02月09日
    瀏覽(75)
  • 【操作系統(tǒng)】一篇文章帶你理清Linux中的權(quán)限!

    【操作系統(tǒng)】一篇文章帶你理清Linux中的權(quán)限!

    ?? 乀艨ic: 個人主頁 ??說是高產(chǎn)但是還是過了快半個月才更新() ??來看看這次的博客吧~ 上次注意到發(fā)Linux相關(guān)的點擊量比其他的多很多,那就最近多更幾篇Linux相關(guān)的吧() 注:Linux的不同發(fā)行版本的指令可能有所不同,本次是按照CentOS7的標(biāo)準來進行追述的。 在談

    2024年04月11日
    瀏覽(24)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包