【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 )
文章目錄
- 一、申請(qǐng)權(quán)限
- 二、申請(qǐng)權(quán)限原理對(duì)話框
- 三、引導(dǎo)用戶手動(dòng)設(shè)置權(quán)限對(duì)話框
- 四、在 AndroidManifest.xml 中配置權(quán)限
- 五、完整代碼示例
- 六、GitHub 地址
一、申請(qǐng)權(quán)限
申請(qǐng)權(quán)限 步驟 :
權(quán)限判定 : 首先要判定是否已經(jīng)授權(quán)指定的權(quán)限數(shù)組 ; 調(diào)用 EasyPermissions.hasPermissions 方法 , 進(jìn)行判定 ;
/*** 檢查當(dāng)前的上下文對(duì)象 ( 應(yīng)用 ) 是否被授權(quán)指定的權(quán)限集合** @param context 調(diào)用方法的上下文對(duì)象.* @param perms 一個(gè)或多個(gè)權(quán)限, 如 {@link Manifest.permission#CAMERA}.* @return true 如果所有的權(quán)限都被授權(quán)了返回 true, 如果有一個(gè)權(quán)限沒(méi)有被授予就會(huì)返回 false * yet granted.* @see Manifest.permission*/public static boolean hasPermissions(@NonNull Context context,@Size(min = 1) @NonNull String... perms)權(quán)限判定分支 : 如果有要求的權(quán)限 , 就開(kāi)始執(zhí)行實(shí)際的邏輯 , 如果沒(méi)有權(quán)限 , 就需要申請(qǐng)權(quán)限 ;
申請(qǐng)權(quán)限 : 調(diào)用 EasyPermissions.requestPermissions 方法 , 申請(qǐng)權(quán)限 ;
/*** 申請(qǐng)一組權(quán)限, 如果系統(tǒng)要求 ( 用戶之前拒絕過(guò) ) , 顯示 權(quán)限申請(qǐng)?jiān)韺?duì)話框 , * 向用戶表明申請(qǐng)?jiān)摍?quán)限的原因 .** @param host 上下文對(duì)象 , 一般是 Activity.* @param rationale 解釋為什么申請(qǐng)改組權(quán)限的原因的信息;* 這些信息會(huì)在用戶第一次拒絕權(quán)限申請(qǐng)后顯示在 權(quán)限申請(qǐng)?jiān)韺?duì)話框 中.* @param requestCode 追蹤本次權(quán)限申請(qǐng)的申請(qǐng)碼 , 必須小于 256.* @param perms 本次申請(qǐng)的權(quán)限 , 這是一個(gè)可變參數(shù) .* @see Manifest.permission*/public static void requestPermissions(@NonNull Activity host, @NonNull String rationale,int requestCode, @Size(min = 1) @NonNull String... perms) {requestPermissions(new PermissionRequest.Builder(host, requestCode, perms).setRationale(rationale).build());}注解中使用的常量定義 : 如果要在 @AfterPermissionGranted() 注解中使用常量 , 該常量只能使用 const val 定義 ;
- 定義方式 : const val 常量才是 Java 中的 public static final 對(duì)等的常量值 ;
- 定義位置 : const val 常量只能定義在 Kotlin 文件頂層, 或 object 對(duì)象表達(dá)式中, 不能定義在類(lèi)中 ;
數(shù)組轉(zhuǎn)為可變參數(shù) : Kotlin 中可以使用 Array<String> 數(shù)組作為可變參數(shù) , 數(shù)組前加上 * 符號(hào) , 可以將數(shù)組展開(kāi) , 轉(zhuǎn)為可變數(shù)組 , 如 *PERMMISSIONS ;
/*** 當(dāng)做可變參數(shù)時(shí) , 前面加上 * 符號(hào) , 展開(kāi)數(shù)組* *PERMMISSIONS 等同于可變參數(shù)*/var PERMMISSIONS: Array<String> = arrayOf(Manifest.permission.CAMERA,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.READ_CONTACTS,Manifest.permission.READ_SMS,Manifest.permission.WRITE_EXTERNAL_STORAGE)申請(qǐng)權(quán)限代碼示例 :
/*** AfterPermissionGranted 注解的作用是 , 當(dāng) 請(qǐng)求嗎 666 對(duì)應(yīng)的權(quán)限申請(qǐng)全部通過(guò)后* 再次回調(diào)一次該方法 . ( 相當(dāng)于調(diào)用了兩次該方法 )*/@AfterPermissionGranted( PERMISSION_REQUEST_CODE )fun doSomethingWithPermissions(){Log.i(TAG, "doSomethingWithPermissions")// 數(shù)組前加上 * 符號(hào) , 可以將數(shù)組展開(kāi) , 轉(zhuǎn)為可變數(shù)組// 調(diào)用 EasyPermissions.hasPermissions 方法判定是否已經(jīng)申請(qǐng)?jiān)摍?quán)限if(EasyPermissions.hasPermissions(this,*PERMMISSIONS)){// 如果有上述權(quán)限, 執(zhí)行該操作Toast.makeText(this, "權(quán)限申請(qǐng)通過(guò)", Toast.LENGTH_LONG).show()}else{// 如果沒(méi)有上述權(quán)限 , 那么申請(qǐng)權(quán)限EasyPermissions.requestPermissions(this,"權(quán)限申請(qǐng)?jiān)韺?duì)話框 : 描述申請(qǐng)權(quán)限的原理",PERMISSION_REQUEST_CODE,// 數(shù)組前加上 * 符號(hào) , 可以將數(shù)組展開(kāi) , 轉(zhuǎn)為可變數(shù)組*PERMMISSIONS)}}申請(qǐng)權(quán)限結(jié)果響應(yīng)操作 : 重寫(xiě) Activity 的 onRequestPermissionsResult 方法 , 申請(qǐng)權(quán)限完成后 , 不管成功還是失敗 , 都會(huì)回調(diào) 該方法 , 在此處將后續(xù)操作全部交給 EasyPermissions 操作 ;
/*** 二 、 重寫(xiě) Activity 的 onRequestPermissionsResult 方法* 主要是在該方法中使用 EasyPermissions 進(jìn)一步處理權(quán)限申請(qǐng)后續(xù)結(jié)果*/override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray){super.onRequestPermissionsResult(requestCode, permissions, grantResults)Log.i(TAG, "onRequestPermissionsResult")// 進(jìn)一步使用 EasyPermissions 處理后續(xù)結(jié)果EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}調(diào)用 EasyPermissions.onRequestPermissionsResult 的結(jié)果就是 , 如果用戶同意了權(quán)限申請(qǐng) , 就會(huì)回調(diào) onPermissionsGranted 方法 , 如果用戶拒絕了權(quán)限申請(qǐng) , 就會(huì)回調(diào) onPermissionsDenied 方法 ;
二、申請(qǐng)權(quán)限原理對(duì)話框
如果選擇了 “拒絕” 選項(xiàng) , 那就攤上事了 , 后面連帶一大堆操作 , 處理后續(xù)權(quán)限管理的問(wèn)題 ;
之前用戶選擇了拒絕 , 再次申請(qǐng) , 就會(huì)自動(dòng)彈出 權(quán)限申請(qǐng)?jiān)韺?duì)話框 , 該對(duì)話框的主要作用是 描述 申請(qǐng)權(quán)限的原理 ;
如果第一次申請(qǐng)權(quán)限 , 拒絕了某些權(quán)限的申請(qǐng) , 第二次就會(huì)自動(dòng)彈出 申請(qǐng)權(quán)限原理對(duì)話框 , 在這個(gè)對(duì)話框中 , 開(kāi)發(fā)者需要給出為什么申請(qǐng)這些權(quán)限 , 說(shuō)服用戶同意這些權(quán)限的申請(qǐng) ;
申請(qǐng)權(quán)限原理對(duì)話框 中的內(nèi)容是在 EasyPermissions.requestPermissions 方法的參數(shù)中設(shè)定的 ;
回調(diào)函數(shù) : 在 Activity 中實(shí)現(xiàn) EasyPermissions.RationaleCallbacks 接口 , 在本 Activity 中調(diào)用 EasyPermissions.requestPermissions 方法申請(qǐng)權(quán)限時(shí) , 就會(huì)自動(dòng)應(yīng)用上述機(jī)制 ,
/*** 申請(qǐng)權(quán)限原理對(duì)話框操作對(duì)應(yīng)的回調(diào)函數(shù) */public interface RationaleCallbacks {void onRationaleAccepted(int requestCode);void onRationaleDenied(int requestCode);}申請(qǐng)權(quán)限原理對(duì)話框 : 用戶申請(qǐng)權(quán)限 , 如果是首次申請(qǐng) , 該對(duì)話框不彈出 , 如果不是首次申請(qǐng) , 并且之前拒絕過(guò)某些權(quán)限申請(qǐng) , 就會(huì)彈出該對(duì)話框 , 用戶進(jìn)行以下操作 :
- 用戶點(diǎn)擊 確定 : 就會(huì)繼續(xù)執(zhí)行權(quán)限申請(qǐng)的流程 , 彈出 權(quán)限申請(qǐng) 彈窗 ; 回調(diào) onRationaleAccepted 方法 ;
- 用戶點(diǎn)擊 取消 : 一般不做任何操作 ; 回調(diào) onRationaleDenied 方法 ;
代碼示例 :
/*四 、 實(shí)現(xiàn) EasyPermissions.RationaleCallbacks 接口中的方法*//*** EasyPermissions.RationaleCallbacks 接口中的方法**/override fun onRationaleDenied(requestCode: Int) {Log.i(TAG, "權(quán)限申請(qǐng)?jiān)韺?duì)話框中選擇 取消 , 請(qǐng)求碼 $requestCode")}/*** EasyPermissions.RationaleCallbacks 接口中的方法**/override fun onRationaleAccepted(requestCode: Int) {Log.i(TAG, "權(quán)限申請(qǐng)?jiān)韺?duì)話框中選擇 確定 , 請(qǐng)求碼 $requestCode")}三、引導(dǎo)用戶手動(dòng)設(shè)置權(quán)限對(duì)話框
如果用戶在 授權(quán)界面 選擇了 “拒絕, 不要再詢問(wèn)” , 這事比上面的還要大 , 此時(shí)權(quán)限對(duì)話框根本就無(wú)法彈出 , 只能到設(shè)置界面取設(shè)置權(quán)限 ;
引導(dǎo)用戶手動(dòng)設(shè)置權(quán)限對(duì)話框 : 該對(duì)話框的作用就是 引導(dǎo)用戶跳轉(zhuǎn)到設(shè)置界面 , 設(shè)置需要的權(quán)限 ;
這個(gè)對(duì)話框需要自定義 , 但是 EasyPermission 庫(kù)給提供了一個(gè) AppSettingsDialog 對(duì)話框 , 其作用就是引導(dǎo)用戶跳轉(zhuǎn)到設(shè)置界面 , 設(shè)置對(duì)話框 ;
判定是否存在永久拒絕的權(quán)限 : 調(diào)用 EasyPermissions.somePermissionPermanentlyDenied 方法 , 判定是否存在被永久拒絕的權(quán)限 , 如果有 , 那么 創(chuàng)建 AppSettingsDialog 對(duì)話框 ,
彈出 引導(dǎo)用戶手動(dòng)設(shè)置權(quán)限對(duì)話框 代碼示例 :
// 如果申請(qǐng)的權(quán)限中有任何一個(gè)權(quán)限存在 永久拒絕 的情況if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {// 設(shè)置 引導(dǎo)用戶前往設(shè)置界面 自行設(shè)置權(quán)限的引導(dǎo)對(duì)話框AppSettingsDialog.Builder(this).setTitle("需要手動(dòng)設(shè)置權(quán)限").setRationale("存在永久拒絕的權(quán)限 , 需要手動(dòng)前往設(shè)置界面為應(yīng)用進(jìn)行授權(quán)").setPositiveButton("前往設(shè)置界面").setNegativeButton("不使用該功能").build().show()}彈出的對(duì)話框樣式 :
如果點(diǎn)擊 “前往設(shè)置界面” , 就會(huì)跳轉(zhuǎn)到 應(yīng)用信息 設(shè)置界面 :
操作完畢返回操作 : 從該對(duì)話框返回 , 不管是點(diǎn)擊哪個(gè)按鈕 , 都會(huì)進(jìn)入該方法中 , 此時(shí)判定是否授權(quán)成功 , 如果沒(méi)有授權(quán)成功 , 給用戶進(jìn)行提示 ; 如果有授權(quán)成功 , 那么進(jìn)行后續(xù)操作 ;
/*** 從 AppSettingsDialog 界面中返回, 回調(diào)該方法*/override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE){// 判斷五種權(quán)限是否申請(qǐng)成功var hasPermissions =EasyPermissions.hasPermissions(this, *PERMMISSIONS)// 界面中顯示權(quán)限申請(qǐng)結(jié)果Toast.makeText(this, "設(shè)置界面用戶手動(dòng)申請(qǐng)權(quán)限結(jié)果 $hasPermissions",Toast.LENGTH_LONG).show()}}四、在 AndroidManifest.xml 中配置權(quán)限
一定不要忘記在 AndroidManifest.xml 中配置權(quán)限 , 否則無(wú)法使用 ;
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"package="kim.hsl.easypermissions"><uses-permission android:name="android.permission.CAMERA" /><uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /><uses-permission android:name="android.permission.READ_CONTACTS" /><uses-permission android:name="android.permission.READ_SMS" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:roundIcon="@mipmap/ic_launcher_round"android:supportsRtl="true"android:theme="@style/AppTheme"><activity android:name=".MainActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>五、完整代碼示例
package kim.hsl.easypermissionsimport android.Manifest import android.content.Intent import android.os.Bundle import android.util.Log import android.view.View import android.widget.Toast import androidx.appcompat.app.AppCompatActivity import pub.devrel.easypermissions.AfterPermissionGranted import pub.devrel.easypermissions.AppSettingsDialog import pub.devrel.easypermissions.EasyPermissions import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks import pub.devrel.easypermissions.EasyPermissions.RationaleCallbacks/*** 權(quán)限申請(qǐng)碼, 作為權(quán)限申請(qǐng)的標(biāo)識(shí)* 注意 : const val 常量才是 Java 中的 public static final 對(duì)等的常量值* const val 常量只能定義在 Kotlin 文件中, 或 object 對(duì)象表達(dá)式中, 不能定義在類(lèi)中*/ const val PERMISSION_REQUEST_CODE : Int = 100;class MainActivity : AppCompatActivity(), PermissionCallbacks, RationaleCallbacks{val TAG = "MainActivity"/*** 當(dāng)做可變參數(shù)時(shí) , 前面加上 * 符號(hào) , 展開(kāi)數(shù)組* *PERMMISSIONS 等同于可變參數(shù)*/var PERMMISSIONS: Array<String> = arrayOf(Manifest.permission.CAMERA,Manifest.permission.ACCESS_FINE_LOCATION,Manifest.permission.READ_CONTACTS,Manifest.permission.READ_SMS,Manifest.permission.WRITE_EXTERNAL_STORAGE)override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}/*一 、 用戶點(diǎn)擊按鈕開(kāi)始申請(qǐng)權(quán)限*/fun onCLick(view : View){// 申請(qǐng)權(quán)限, 并在權(quán)限申請(qǐng)通過(guò)后 , 在執(zhí)行一次該方法doSomethingWithPermissions();}/*** AfterPermissionGranted 注解的作用是 , 當(dāng) 請(qǐng)求嗎 666 對(duì)應(yīng)的權(quán)限申請(qǐng)全部通過(guò)后* 再次回調(diào)一次該方法 . ( 相當(dāng)于調(diào)用了兩次該方法 )*/@AfterPermissionGranted( PERMISSION_REQUEST_CODE )fun doSomethingWithPermissions(){Log.i(TAG, "doSomethingWithPermissions")// 數(shù)組前加上 * 符號(hào) , 可以將數(shù)組展開(kāi) , 轉(zhuǎn)為可變數(shù)組// 調(diào)用 EasyPermissions.hasPermissions 方法判定是否已經(jīng)申請(qǐng)?jiān)摍?quán)限if(EasyPermissions.hasPermissions(this,*PERMMISSIONS)){// 如果有上述權(quán)限, 執(zhí)行該操作Toast.makeText(this, "權(quán)限申請(qǐng)通過(guò)", Toast.LENGTH_LONG).show()}else{// 如果沒(méi)有上述權(quán)限 , 那么申請(qǐng)權(quán)限EasyPermissions.requestPermissions(this,"權(quán)限申請(qǐng)?jiān)韺?duì)話框 : 描述申請(qǐng)權(quán)限的原理",PERMISSION_REQUEST_CODE,// 數(shù)組前加上 * 符號(hào) , 可以將數(shù)組展開(kāi) , 轉(zhuǎn)為可變數(shù)組*PERMMISSIONS)}}/*** 二 、 重寫(xiě) Activity 的 onRequestPermissionsResult 方法* 主要是在該方法中使用 EasyPermissions 進(jìn)一步處理權(quán)限申請(qǐng)后續(xù)結(jié)果*/override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray){super.onRequestPermissionsResult(requestCode, permissions, grantResults)Log.i(TAG, "onRequestPermissionsResult")// 進(jìn)一步使用 EasyPermissions 處理后續(xù)結(jié)果EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);}/*三 、 實(shí)現(xiàn) EasyPermissions.PermissionCallbacks 接口中的方法*//*** EasyPermissions.PermissionCallbacks 接口中實(shí)現(xiàn)的方法* 調(diào)用 EasyPermissions.requestPermissions() 方法申請(qǐng)權(quán)限 , 用戶點(diǎn)擊拒絕授權(quán)后會(huì)回調(diào)該方法*/override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {Log.i(TAG, "onPermissionsDenied 用戶拒絕權(quán)限申請(qǐng) , 請(qǐng)求碼 $requestCode , 拒絕的權(quán)限 : $perms")// 如果申請(qǐng)的權(quán)限中有任何一個(gè)權(quán)限存在 永久拒絕 的情況if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {// 設(shè)置 引導(dǎo)用戶前往設(shè)置界面 自行設(shè)置權(quán)限的引導(dǎo)對(duì)話框AppSettingsDialog.Builder(this).setTitle("需要手動(dòng)設(shè)置權(quán)限").setRationale("存在永久拒絕的權(quán)限 , 需要手動(dòng)前往設(shè)置界面為應(yīng)用進(jìn)行授權(quán)").setPositiveButton("前往設(shè)置界面").setNegativeButton("不使用該功能").build().show()}}/*** EasyPermissions.PermissionCallbacks 接口中實(shí)現(xiàn)的方法* 調(diào)用 EasyPermissions.requestPermissions() 方法申請(qǐng)權(quán)限 , 用戶點(diǎn)擊同意授權(quán)后會(huì)回調(diào)該方法*/override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {Log.i(TAG, "onPermissionsGranted 用戶同意權(quán)限申請(qǐng) , 請(qǐng)求碼 $requestCode , 拒絕的權(quán)限 : $perms")}/*四 、 實(shí)現(xiàn) EasyPermissions.RationaleCallbacks 接口中的方法*//*** EasyPermissions.RationaleCallbacks 接口中的方法**/override fun onRationaleDenied(requestCode: Int) {Log.i(TAG, "權(quán)限申請(qǐng)?jiān)韺?duì)話框中選擇 取消 , 請(qǐng)求碼 $requestCode")}/*** EasyPermissions.RationaleCallbacks 接口中的方法**/override fun onRationaleAccepted(requestCode: Int) {Log.i(TAG, "權(quán)限申請(qǐng)?jiān)韺?duì)話框中選擇 確定 , 請(qǐng)求碼 $requestCode")}/*五 、實(shí)現(xiàn)從 AppSettingsDialog 對(duì)話框返回的邏輯主要是檢查用戶永久拒絕后, 查看引導(dǎo)用戶設(shè)置權(quán)限的結(jié)果*//*** 從 AppSettingsDialog 界面中返回, 回調(diào)該方法*/override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE){// 判斷五種權(quán)限是否申請(qǐng)成功var hasPermissions =EasyPermissions.hasPermissions(this, *PERMMISSIONS)// 界面中顯示權(quán)限申請(qǐng)結(jié)果Toast.makeText(this, "設(shè)置界面用戶手動(dòng)申請(qǐng)權(quán)限結(jié)果 $hasPermissions",Toast.LENGTH_LONG).show()}}}
六、GitHub 地址
https://github.com/han1202012/EasyPermissions
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 )的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【Android 应用开发】Google
- 下一篇: 【Android 应用开发】Google