• Android请求应用权限



    前言

    • 学习Android为什么需要动态申请危险权限
    • 学会Android应用危险权限申请的方式

    参考


    一、请求应用权限基本原则

    1、当用户开始与需要相关权限的功能互动时,在具体使用情境下请求权限。
    解释:在权限需要被使用的功能去申请。早期的应用基本都是把所有的权限放在应用启动去申请,用户不同意所有权限直接阻断了用户使用软件的权利,这是不可取的,因为一个应用中有很多功能是不需要某个特定权限就能够被使用的。
    2、不要阻止用户使用应用。始终提供选项供用户取消指导界面流程,例如说明请求权限理由的流程。
    解释:还是第一条解释的原因,不要因为用户不同意某一个单一功能的权限而阻止用户使用其他功能。
    3、如果用户拒绝或撤消某项功能所需的权限,请适当降级您的应用以便让用户可以继续使用您的应用(可能通过停用需要权限的功能来实现)。
    解释:用户如果拒绝了某个功能需要的权限,那就提醒用户此功能需要打开需要的权限才能被使用,用户不同意权限就不能使用当前功能。
    4、不要对系统行为做任何假设。例如,假设某些权限会出现在同一个权限组中。权限组的作用只是在应用请求密切相关的多个权限时,帮助系统尽可能减少向用户显示的系统对话框数量。
    解释:明确指定需要使用的特殊权限,比如读写sdcard权限,如果读写权限都需要,那就都需要动态申请。

    二、请求权限的流程(官网摘抄)

    1. 在应用的清单文件中,声明应用可能需要请求的权限

      如需声明应用可能请求的权限,请在应用的清单文件中添加相应的 元素。例如,如果应用需要访问相机,则应在 AndroidManifest.xml 中添加以下代码行:

    <manifest ...>
        <uses-permission android:name="android.permission.CAMERA"/>
        <application ...>
            ...
        application>
    manifest>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    1. 设计应用的用户体验,使应用中的特定操作与特定运行时权限相关联。告知用户哪些操作可能会要求他们向您的应用授予访问其私人数据的权限。

      设计UX告知用户我们可能需要申请的权限,以及为什么需要使用这些权限,应用在哪些功能

    2. 等待用户调用应用中需要访问特定用户私人数据的任务或操作。届时,您的应用可以请求访问相应数据所需的运行时权限。

      就是当用户调用特定的功能的时候再去申请权限,不要提前申请权限,因为有些需要权限的功能可能用户都不会用到,但是我们不能阻止用户使用其他功能

    3. 检查用户是否已授予应用所需的运行时权限。如果已授权,那么您的应用可以访问用户私人数据。如果没有,请继续执行下一步。每次执行需要该权限的操作时,您都必须检查自己是否具有该权限。

      通过Android的ContextCompat.checkSelfPermission()方法检测用户是否已经授权,每次执行都需要判断权限是否授予,因为用户可用通过应用信息主动关闭权限

    4. 检查您的应用是否应向用户显示理由,说明您的应用需要用户授予特定运行时权限的原因。如果系统确定您的应用不应显示理由,请继续直接执行下一步,无需显示界面元素。

      不过,如果系统确定您的应用应该显示一个理由,请在界面元素中向用户显示理由,明确说明您的应用试图访问哪些数据,以及应用获得运行时权限后可为用户提供哪些好处。用户确认理由后,请继续执行下一步

      就是当用户执行了拒绝之后,就会走到当前步骤,我们需要给用户展示为什么需要使用这个权限,并且引导用户去权限设置中打开当前权限

    5. 请求您的应用访问用户私人数据所需的运行时权限。系统会显示运行时权限提示,例如权限概览页面上显示的提示。

    调用申请权限的方法,系统弹出权限申请弹窗
    当应用请求运行时权限时显示的系统权限提示。

    7.检查用户的响应,他们可能会选择同意或拒绝授予运行时权限。

    用户可以在弹窗选择同意或者拒绝,或者只是同意当前一次权限

    1. 如果用户向您的应用授予权限,您就可以访问用户私人数据。如果用户拒绝授予该权限,请适当降低应用体验,使应用在未获得受该权限保护的信息时也能向用户提供功能。

      当用户选择不同意当前权限时候,我们不提供当前功能给用户使用

    官网Copy过来的,在 Android 上声明和请求运行时权限的工作流。
    在 Android 上声明和请求运行时权限的工作流。

    三、请求权限编码

    1.允许系统管理权限请求代码

    在模块的 build.gradle 文件中添加以下库的依赖项:

    • androidx.activity,版本 1.2.0 或更高版本
    • androidx.fragment,版本 1.3.0 或更高版本
    // Activity引入
    dependencies {
        val activity_version = "1.6.1"
        // Java language implementation
        implementation("androidx.activity:activity:$activity_version")
        // Kotlin
        implementation("androidx.activity:activity-ktx:$activity_version")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    // Fragment引入
    dependencies {
        val fragment_version = "1.5.4"
        // Java language implementation
        implementation("androidx.fragment:fragment:$fragment_version")
        // Kotlin
        implementation("androidx.fragment:fragment-ktx:$fragment_version")
        // Testing Fragments in Isolation
        debugImplementation("androidx.fragment:fragment-testing:$fragment_version")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用如下两个协定类进行权限申请:

    • 如需请求一项权限,请使用 RequestPermission。
    • 如需同时请求多项权限,请使用 RequestMultiplePermissions。

    例子使用RequestMultiplePermissions进行请求,RequestPermission是类似的,申请单一权限的例子官网上有,可以查看官网的例子

    1. 在 activity 或 fragment 的初始化逻辑中,将 ActivityResultCallback 的实现传入对 registerForActivityResult() 的调用。ActivityResultCallback 定义应用如何处理用户对权限请求的响应。

      保留对 registerForActivityResult()(类型为 ActivityResultLauncher)的返回值的引用。

    2. 如需在必要时显示系统权限对话框,请对您在上一步中保存的 ActivityResultLauncher 实例调用 launch() 方法。

      调用 launch() 之后,系统会显示系统权限对话框。当用户做出选择后,系统会异步调用您在上一步中定义的 ActivityResultCallback 实现。

    companion object {
        private val PERMISSION_ARR = arrayOf(
            Manifest.permission.RECORD_AUDIO,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.CAMERA
        )
    }
    
    private fun handlePermission() {
            PERMISSION_ARR.forEach { permission ->
                when {
                    ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED -> {
                        Log.d(TAG, "权限允许:: $permission")
                    }
                    shouldShowRequestPermissionRationale(permission) -> {
                        // 在此处给用户解释为甚么需要申请此权限
                        Log.d(TAG, "权限拒绝:: $permission")
                    }
                    else -> {
                        requestPermissionLauncher.launch(PERMISSION_ARR)
                    }
                }
            }
        }
    
        private val requestPermissionLauncher: ActivityResultLauncher<Array<String>> =
            registerForActivityResult(RequestMultiplePermissions()) { map ->
                map?.keys?.forEach { key ->
                    // key是权限,value是当前权限的是否被允许的boolean值
                    // 申请权限之后的操作就在此执行
                    Log.d(TAG, "permission key:: $key, isGranted:: ${map[key]}")
                }
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    2.自行管理权限请求代码

    companion object {
            private const val TAG = "MainActivity"
    
            private val PERMISSION_ARR = arrayOf(
                Manifest.permission.RECORD_AUDIO,
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA
            )
    
            private const val PERMISSION_REQUEST_CODE = 100
        }
    
    private fun handlePermission() {
            PERMISSION_ARR.forEach { permission ->
                when {
                    ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED -> {
                        Log.d(TAG, "权限允许:: $permission")
                    }
                    shouldShowRequestPermissionRationale(permission) -> {
                        Log.d(TAG, "权限拒绝:: $permission")
                    }
                    else -> {
                      // 请求权限
                        requestPermissions(arrayOf(permission), PERMISSION_REQUEST_CODE)
                    }
                }
            }
        }
    
        override fun onRequestPermissionsResult(
            requestCode: Int,
            permissions: Array<out String>,
            grantResults: IntArray
        ) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults)
            when (requestCode) {
                PERMISSION_REQUEST_CODE -> {
                    if ((grantResults.isNotEmpty() &&
                                grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                        // 权限允许 
                        
                    } else {
                        // 权限不允许,不能允许用户使用
                       
                    }
                    return
                }
                else -> {
                    // Ignore all other requests.
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    总结

    就是简单的自己使用总结,基本上的东西都是官网有的。
    建议使用第一种方式,因为在Fragment和Activity中都可以玩

  • 相关阅读:
    Ajax axios JSON Fastjson
    Flutter高仿微信-第31篇-单聊-表情
    渗透测试-最全Web 渗透测试信息搜集-CheckList
    Linux C应用编程-1-文件IO
    国际阿里云服务器到期多久会释放资源信息?
    【pointNet】基于pointNet的三维点云目标分类识别matlab仿真
    相似度系列-6:单维度方法:Evaluating Coherence in Dialogue Systems using Entailment
    【FAQ】接入HMS Core广告服务中的常见问题总结和解决方法
    了解LLVM、Clang编译过程
    仿真2. 离散事件仿真
  • 原文地址:https://blog.csdn.net/u013855006/article/details/128175884