申请权限 步骤 :
权限判定 : 首先要判定是否已经授权指定的权限数组 ; 调用 EasyPermissions.hasPermissions 方法 , 进行判定 ;
/**
* 检查当前的上下文对象 ( 应用 ) 是否被授权指定的权限集合
*
* @param context 调用方法的上下文对象.
* @param perms 一个或多个权限, 如 {@link Manifest.permission#CAMERA}.
* @return true 如果所有的权限都被授权了返回 true, 如果有一个权限没有被授予就会返回 false
* yet granted.
* @see Manifest.permission
*/
public static boolean hasPermissions(@NonNull Context context,
@Size(min = 1) @NonNull String... perms)
权限判定分支 : 如果有要求的权限 , 就开始执行实际的逻辑 , 如果没有权限 , 就需要申请权限 ;
申请权限 : 调用 EasyPermissions.requestPermissions 方法 , 申请权限 ;
/**
* 申请一组权限, 如果系统要求 ( 用户之前拒绝过 ) , 显示 权限申请原理对话框 ,
* 向用户表明申请该权限的原因 .
*
* @param host 上下文对象 , 一般是 Activity.
* @param rationale 解释为什么申请改组权限的原因的信息;
* 这些信息会在用户第一次拒绝权限申请后显示在 权限申请原理对话框 中.
* @param requestCode 追踪本次权限申请的申请码 , 必须小于 256.
* @param perms 本次申请的权限 , 这是一个可变参数 .
* @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 对等的常量值
* const val 常量只能定义在 Kotlin 文件中, 或 object 对象表达式中, 不能定义在类中
*/
const val PERMISSION_REQUEST_CODE : Int = 100;
数组转为可变参数 : Kotlin 中可以使用 Array<String> 数组作为可变参数 , 数组前加上 * 符号 , 可以将数组展开 , 转为可变数组 , 如 *PERMMISSIONS ;
/**
* 当做可变参数时 , 前面加上 * 符号 , 展开数组
* *PERMMISSIONS 等同于可变参数
*/
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)
申请权限代码示例 :
/**
* AfterPermissionGranted 注解的作用是 , 当 请求吗 666 对应的权限申请全部通过后
* 再次回调一次该方法 . ( 相当于调用了两次该方法 )
*/
@AfterPermissionGranted( PERMISSION_REQUEST_CODE )
fun doSomethingWithPermissions(){
Log.i(TAG, "doSomethingWithPermissions")
// 数组前加上 * 符号 , 可以将数组展开 , 转为可变数组
// 调用 EasyPermissions.hasPermissions 方法判定是否已经申请该权限
if(EasyPermissions.hasPermissions(this,
*PERMMISSIONS)){
// 如果有上述权限, 执行该操作
Toast.makeText(this, "权限申请通过", Toast.LENGTH_LONG).show()
}else{
// 如果没有上述权限 , 那么申请权限
EasyPermissions.requestPermissions(
this,
"权限申请原理对话框 : 描述申请权限的原理",
PERMISSION_REQUEST_CODE,
// 数组前加上 * 符号 , 可以将数组展开 , 转为可变数组
*PERMMISSIONS
)
}
}
申请权限结果响应操作 : 重写 Activity 的 onRequestPermissionsResult 方法 , 申请权限完成后 , 不管成功还是失败 , 都会回调 该方法 , 在此处将后续操作全部交给 EasyPermissions 操作 ;
/**
* 二 、 重写 Activity 的 onRequestPermissionsResult 方法
* 主要是在该方法中使用 EasyPermissions 进一步处理权限申请后续结果
*/
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<out String>, grantResults: IntArray){
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Log.i(TAG, "onRequestPermissionsResult")
// 进一步使用 EasyPermissions 处理后续结果
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
调用 EasyPermissions.onRequestPermissionsResult 的结果就是 , 如果用户同意了权限申请 , 就会回调 onPermissionsGranted 方法 , 如果用户拒绝了权限申请 , 就会回调 onPermissionsDenied 方法 ;
如果选择了 “拒绝” 选项 , 那就摊上事了 , 后面连带一大堆操作 , 处理后续权限管理的问题 ;
之前用户选择了拒绝 , 再次申请 , 就会自动弹出 权限申请原理对话框 , 该对话框的主要作用是 描述 申请权限的原理 ;
如果第一次申请权限 , 拒绝了某些权限的申请 , 第二次就会自动弹出 申请权限原理对话框 , 在这个对话框中 , 开发者需要给出为什么申请这些权限 , 说服用户同意这些权限的申请 ;
申请权限原理对话框 中的内容是在 EasyPermissions.requestPermissions 方法的参数中设定的 ;
回调函数 : 在 Activity 中实现 EasyPermissions.RationaleCallbacks 接口 , 在本 Activity 中调用 EasyPermissions.requestPermissions 方法申请权限时 , 就会自动应用上述机制 ,
/**
* 申请权限原理对话框操作对应的回调函数
*/
public interface RationaleCallbacks {
void onRationaleAccepted(int requestCode);
void onRationaleDenied(int requestCode);
}
申请权限原理对话框 : 用户申请权限 , 如果是首次申请 , 该对话框不弹出 , 如果不是首次申请 , 并且之前拒绝过某些权限申请 , 就会弹出该对话框 , 用户进行以下操作 :
代码示例 :
/*
四 、 实现 EasyPermissions.RationaleCallbacks 接口中的方法
*/
/**
* EasyPermissions.RationaleCallbacks 接口中的方法
*
*/
override fun onRationaleDenied(requestCode: Int) {
Log.i(TAG, "权限申请原理对话框中选择 取消 , 请求码 $requestCode")
}
/**
* EasyPermissions.RationaleCallbacks 接口中的方法
*
*/
override fun onRationaleAccepted(requestCode: Int) {
Log.i(TAG, "权限申请原理对话框中选择 确定 , 请求码 $requestCode")
}
如果用户在 授权界面 选择了 “拒绝, 不要再询问” , 这事比上面的还要大 , 此时权限对话框根本就无法弹出 , 只能到设置界面取设置权限 ;
引导用户手动设置权限对话框 : 该对话框的作用就是 引导用户跳转到设置界面 , 设置需要的权限 ;
这个对话框需要自定义 , 但是 EasyPermission 库给提供了一个 AppSettingsDialog 对话框 , 其作用就是引导用户跳转到设置界面 , 设置对话框 ;
判定是否存在永久拒绝的权限 : 调用 EasyPermissions.somePermissionPermanentlyDenied 方法 , 判定是否存在被永久拒绝的权限 , 如果有 , 那么 创建 AppSettingsDialog 对话框 ,
弹出 引导用户手动设置权限对话框 代码示例 :
// 如果申请的权限中有任何一个权限存在 永久拒绝 的情况
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
// 设置 引导用户前往设置界面 自行设置权限的引导对话框
AppSettingsDialog.Builder(this)
.setTitle("需要手动设置权限")
.setRationale("存在永久拒绝的权限 , 需要手动前往设置界面为应用进行授权")
.setPositiveButton("前往设置界面")
.setNegativeButton("不使用该功能")
.build().show()
}
弹出的对话框样式 :
如果点击 “前往设置界面” , 就会跳转到 应用信息 设置界面 :
操作完毕返回操作 : 从该对话框返回 , 不管是点击哪个按钮 , 都会进入该方法中 , 此时判定是否授权成功 , 如果没有授权成功 , 给用户进行提示 ; 如果有授权成功 , 那么进行后续操作 ;
/**
* 从 AppSettingsDialog 界面中返回, 回调该方法
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE){
// 判断五种权限是否申请成功
var hasPermissions =
EasyPermissions.hasPermissions(this, *PERMMISSIONS)
// 界面中显示权限申请结果
Toast.makeText(this, "设置界面用户手动申请权限结果 $hasPermissions",
Toast.LENGTH_LONG).show()
}
}
一定不要忘记在 AndroidManifest.xml 中配置权限 , 否则无法使用 ;
<?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" />
<application
android: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.easypermissions
import 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
/**
* 权限申请码, 作为权限申请的标识
* 注意 : const val 常量才是 Java 中的 public static final 对等的常量值
* const val 常量只能定义在 Kotlin 文件中, 或 object 对象表达式中, 不能定义在类中
*/
const val PERMISSION_REQUEST_CODE : Int = 100;
class MainActivity : AppCompatActivity(), PermissionCallbacks, RationaleCallbacks{
val TAG = "MainActivity"
/**
* 当做可变参数时 , 前面加上 * 符号 , 展开数组
* *PERMMISSIONS 等同于可变参数
*/
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)
}
/*
一 、 用户点击按钮开始申请权限
*/
fun onCLick(view : View){
// 申请权限, 并在权限申请通过后 , 在执行一次该方法
doSomethingWithPermissions();
}
/**
* AfterPermissionGranted 注解的作用是 , 当 请求吗 666 对应的权限申请全部通过后
* 再次回调一次该方法 . ( 相当于调用了两次该方法 )
*/
@AfterPermissionGranted( PERMISSION_REQUEST_CODE )
fun doSomethingWithPermissions(){
Log.i(TAG, "doSomethingWithPermissions")
// 数组前加上 * 符号 , 可以将数组展开 , 转为可变数组
// 调用 EasyPermissions.hasPermissions 方法判定是否已经申请该权限
if(EasyPermissions.hasPermissions(this,
*PERMMISSIONS)){
// 如果有上述权限, 执行该操作
Toast.makeText(this, "权限申请通过", Toast.LENGTH_LONG).show()
}else{
// 如果没有上述权限 , 那么申请权限
EasyPermissions.requestPermissions(
this,
"权限申请原理对话框 : 描述申请权限的原理",
PERMISSION_REQUEST_CODE,
// 数组前加上 * 符号 , 可以将数组展开 , 转为可变数组
*PERMMISSIONS
)
}
}
/**
* 二 、 重写 Activity 的 onRequestPermissionsResult 方法
* 主要是在该方法中使用 EasyPermissions 进一步处理权限申请后续结果
*/
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<out String>, grantResults: IntArray){
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
Log.i(TAG, "onRequestPermissionsResult")
// 进一步使用 EasyPermissions 处理后续结果
EasyPermissions.onRequestPermissionsResult(
requestCode, permissions, grantResults, this);
}
/*
三 、 实现 EasyPermissions.PermissionCallbacks 接口中的方法
*/
/**
* EasyPermissions.PermissionCallbacks 接口中实现的方法
* 调用 EasyPermissions.requestPermissions() 方法申请权限 , 用户点击拒绝授权后会回调该方法
*/
override fun onPermissionsDenied(requestCode: Int, perms: MutableList<String>) {
Log.i(TAG, "onPermissionsDenied 用户拒绝权限申请 , 请求码 $requestCode , 拒绝的权限 : $perms")
// 如果申请的权限中有任何一个权限存在 永久拒绝 的情况
if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
// 设置 引导用户前往设置界面 自行设置权限的引导对话框
AppSettingsDialog.Builder(this)
.setTitle("需要手动设置权限")
.setRationale("存在永久拒绝的权限 , 需要手动前往设置界面为应用进行授权")
.setPositiveButton("前往设置界面")
.setNegativeButton("不使用该功能")
.build().show()
}
}
/**
* EasyPermissions.PermissionCallbacks 接口中实现的方法
* 调用 EasyPermissions.requestPermissions() 方法申请权限 , 用户点击同意授权后会回调该方法
*/
override fun onPermissionsGranted(requestCode: Int, perms: MutableList<String>) {
Log.i(TAG, "onPermissionsGranted 用户同意权限申请 , 请求码 $requestCode , 拒绝的权限 : $perms")
}
/*
四 、 实现 EasyPermissions.RationaleCallbacks 接口中的方法
*/
/**
* EasyPermissions.RationaleCallbacks 接口中的方法
*
*/
override fun onRationaleDenied(requestCode: Int) {
Log.i(TAG, "权限申请原理对话框中选择 取消 , 请求码 $requestCode")
}
/**
* EasyPermissions.RationaleCallbacks 接口中的方法
*
*/
override fun onRationaleAccepted(requestCode: Int) {
Log.i(TAG, "权限申请原理对话框中选择 确定 , 请求码 $requestCode")
}
/*
五 、实现从 AppSettingsDialog 对话框返回的逻辑
主要是检查用户永久拒绝后, 查看引导用户设置权限的结果
*/
/**
* 从 AppSettingsDialog 界面中返回, 回调该方法
*/
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == AppSettingsDialog.DEFAULT_SETTINGS_REQ_CODE){
// 判断五种权限是否申请成功
var hasPermissions =
EasyPermissions.hasPermissions(this, *PERMMISSIONS)
// 界面中显示权限申请结果
Toast.makeText(this, "设置界面用户手动申请权限结果 $hasPermissions",
Toast.LENGTH_LONG).show()
}
}
}