【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 )(二)

简介: 【Android 应用开发】Google 官方 EasyPermissions 权限申请库 ( 完整代码示例 | 申请权限 | 申请权限原理对话框 | 引导用户手动设置权限对话框 )(二)

三、引导用户手动设置权限对话框


如果用户在 授权界面 选择了 “拒绝, 不要再询问” , 这事比上面的还要大 , 此时权限对话框根本就无法弹出 , 只能到设置界面取设置权限 ;

image.png


引导用户手动设置权限对话框 : 该对话框的作用就是 引导用户跳转到设置界面 , 设置需要的权限 ;


这个对话框需要自定义 , 但是 EasyPermission 库给提供了一个 AppSettingsDialog 对话框 , 其作用就是引导用户跳转到设置界面 , 设置对话框 ;


判定是否存在永久拒绝的权限 : 调用 EasyPermissions.somePermissionPermanentlyDenied 方法 , 判定是否存在被永久拒绝的权限 , 如果有 , 那么 创建 AppSettingsDialog 对话框 ,


弹出 引导用户手动设置权限对话框 代码示例 :


   

// 如果申请的权限中有任何一个权限存在 永久拒绝 的情况
        if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
            // 设置 引导用户前往设置界面 自行设置权限的引导对话框
            AppSettingsDialog.Builder(this)
                .setTitle("需要手动设置权限")
                .setRationale("存在永久拒绝的权限 , 需要手动前往设置界面为应用进行授权")
                .setPositiveButton("前往设置界面")
                .setNegativeButton("不使用该功能")
                .build().show()
        }


弹出的对话框样式 :

image.png



如果点击 “前往设置界面” , 就会跳转到 应用信息 设置界面 :


image.png


操作完毕返回操作 : 从该对话框返回 , 不管是点击哪个按钮 , 都会进入该方法中 , 此时判定是否授权成功 , 如果没有授权成功 , 给用户进行提示 ; 如果有授权成功 , 那么进行后续操作 ;


 

/**
     * 从 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 中配置权限


一定不要忘记在 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()
        }
    }
}







六、GitHub 地址


https://github.com/han1202012/EasyPermissions


目录
相关文章
|
29天前
|
安全 Android开发 Kotlin
Android经典实战之SurfaceView原理和实践
本文介绍了 `SurfaceView` 这一强大的 UI 组件,尤其适合高性能绘制任务,如视频播放和游戏。文章详细讲解了 `SurfaceView` 的原理、与 `Surface` 类的关系及其实现示例,并强调了使用时需注意的线程安全、生命周期管理和性能优化等问题。
71 8
|
5月前
|
Android开发 移动开发 小程序
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
binder机制原理面试,安卓app开发教程
|
11天前
|
ARouter 测试技术 API
Android经典面试题之组件化原理、优缺点、实现方法?
本文介绍了组件化在Android开发中的应用,详细阐述了其原理、优缺点及实现方式,包括模块化、接口编程、依赖注入、路由机制等内容,并提供了具体代码示例。
29 2
|
26天前
|
编解码 前端开发 Android开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
70 12
|
2月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
35 0
|
3月前
|
SQL 安全 Java
Android经典面试题之Kotlin中object关键字实现的是什么类型的单例模式?原理是什么?怎么实现双重检验锁单例模式?
Kotlin 单例模式概览 在 Kotlin 中,`object` 关键字轻松实现单例,提供线程安全的“饿汉式”单例。例如: 要延迟初始化,可使用 `companion object` 和 `lazy` 委托: 对于参数化的线程安全单例,结合 `@Volatile` 和 `synchronized`
43 6
|
4月前
|
安全 网络协议 算法
Android网络基础面试题之HTTPS的工作流程和原理
HTTPS简述 HTTPS基于TCP 443端口,通过CA证书确保服务器身份,使用DH算法协商对称密钥进行加密通信。流程包括TCP握手、证书验证(公钥解密,哈希对比)和数据加密传输(随机数加密,预主密钥,对称加密)。特点是安全但慢,易受特定攻击,且依赖可信的CA。每次请求可能复用Session ID以减少握手。
54 2
|
4月前
|
API Android开发
32. 【Android教程】对话框:AlertDialog
32. 【Android教程】对话框:AlertDialog
59 2
|
4月前
|
缓存 安全 Java
提升编程效率的利器: 解析Google Guava库之集合工具类-50个示例(八)
提升编程效率的利器: 解析Google Guava库之集合工具类-50个示例(八)
|
4月前
|
缓存 算法 Java
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
提升编程效率的利器: 解析Google Guava库之常用工具类-40个示例(七)
下一篇
无影云桌面