MST

星途 面试题库

面试题:Kotlin动态权限请求的异常处理

在Kotlin动态权限请求过程中,可能会遇到用户拒绝权限请求的情况,甚至多次拒绝后勾选不再提示。请阐述如何在代码中优雅地处理这些情况,以提升用户体验并确保应用功能正常。
23.6万 热度难度
编程语言Kotlin

知识考点

AI 面试

面试题答案

一键面试
  1. 检测权限状态
    • 使用ContextCompat.checkSelfPermission方法检查权限是否已授予。例如,检查读写存储权限:
    val permissionCheck = ContextCompat.checkSelfPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)
    if (permissionCheck == PackageManager.PERMISSION_GRANTED) {
        // 权限已授予,执行相关操作
    } else {
        // 权限未授予,发起权限请求
    }
    
  2. 发起权限请求
    • 使用ActivityCompat.requestPermissions方法发起权限请求。在Activity中:
    ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), READ_STORAGE_PERMISSION_REQUEST_CODE)
    
    • 这里READ_STORAGE_PERMISSION_REQUEST_CODE是自定义的请求码,用于在回调中识别请求。
  3. 处理权限请求结果
    • 重写onRequestPermissionsResult方法。
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        if (requestCode == READ_STORAGE_PERMISSION_REQUEST_CODE) {
            if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 权限授予,执行相关操作
            } else {
                // 权限拒绝处理
                if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
                    // 用户拒绝了权限,但未勾选不再提示,可再次弹窗解释权限用途
                    AlertDialog.Builder(this)
                       .setTitle("权限申请")
                       .setMessage("应用需要读写存储权限才能正常工作,请授予权限。")
                       .setPositiveButton("确定") { _, _ ->
                            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), READ_STORAGE_PERMISSION_REQUEST_CODE)
                        }
                       .show()
                } else {
                    // 用户拒绝且勾选了不再提示,引导用户到设置页面开启权限
                    AlertDialog.Builder(this)
                       .setTitle("权限申请")
                       .setMessage("应用需要读写存储权限才能正常工作,您可以在设置中手动开启权限。")
                       .setPositiveButton("设置") { _, _ ->
                            val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
                            val uri = Uri.fromParts("package", packageName, null)
                            intent.data = uri
                            startActivity(intent)
                        }
                       .show()
                }
            }
        }
    }
    
  4. 在Fragment中处理权限请求
    • Activity类似,但在Fragment中使用requestPermissions方法。
    requestPermissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE), READ_STORAGE_PERMISSION_REQUEST_CODE)
    
    • 重写onRequestPermissionsResult方法与Activity中的处理逻辑类似。
  5. 封装权限请求逻辑
    • 可以将权限请求和处理逻辑封装成一个工具类或扩展函数,提高代码复用性。例如:
    fun Context.hasPermission(permission: String): Boolean {
        return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
    }
    
    fun Fragment.requestPermission(permission: String, requestCode: Int, rationaleMessage: String? = null) {
        if (shouldShowRequestPermissionRationale(permission)) {
            rationaleMessage?.let {
                AlertDialog.Builder(requireContext())
                   .setTitle("权限申请")
                   .setMessage(it)
                   .setPositiveButton("确定") { _, _ ->
                        requestPermissions(arrayOf(permission), requestCode)
                    }
                   .show()
            }
        } else {
            requestPermissions(arrayOf(permission), requestCode)
        }
    }
    
    • 使用时:
    if (!requireContext().hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE)) {
        requestPermission(Manifest.permission.READ_EXTERNAL_STORAGE, READ_STORAGE_PERMISSION_REQUEST_CODE, "应用需要读写存储权限才能正常工作,请授予权限。")
    }