Android registerForActivityResult 处理权限问题(判断,允许,拒绝,永久拒绝,设置授权监听)

714 阅读3分钟

基于 registerForActivityResult 处理Android权限的一系列逻辑调用.

在项目中,使用系统的一些功能需要,用户手动授权一系列权限才能使用系统的功能,例如相机.定位等功能.个人基于AndroidX新的申请方式,记录一下权限申请,拒绝,永久拒绝的处理路径.

image.png

1:权限处理的核心方法

  • ContextCompat.checkSelfPermission(this, permission) 是否有权限
  • activity.houldShowRequestPermissionRationale(permission) 是否永久拒绝
  • activity.requestPermissions(permissions, REQUEST_CODE_CAMERA )请求权限

1.1:是否有权限

Android 6.0(Build.VERSION_CODES.M)版本开始了动态授权,以下版本是清单文件配置就表示申请了权限,以上版本需要动态授权,才能获取权限

核心代码:

判断权限是否授权
ContextCompat.checkSelfPermission(this, permission)

授权的结果:

PackageManager.PERMISSION_GRANTED = 0; //已授权

PackageManager.PERMISSION_DENIED = -1;//未授权

image.png

image.png

/**
 *是否拥有权限
 */
fun isGranted(permission: String?): Boolean {
    permission?.let {
        return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(
            this, permission
        ))
    }.apply {
        return false
    }
}

1.2:永久决绝权限

shouldShowRequestPermissionRationale(permission) //永久拒绝

  • true:用户之前拒绝过该权限且未勾选不再询问,此时应向用户解释权限用途。
  • false:用户永久拒绝权限(勾选不再询问)或从未申请过该权限

ContextCompat.checkSelfPermission(this, permission) //判断权限 没有被授权

/**
* 检测是否永久拒绝权限
 */
 private fun isPermissionPermanentlyDenied(permission: String): Boolean {
     return !shouldShowRequestPermissionRationale(permission)
             && ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED
 }

1.3:永久拒绝的权限需要跳转到设置页面手动开启

//跳转设置页面 手动设置权限
private fun openAppSettings() {
    val intent = Intent()
    intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
    val uri = Uri.fromParts("package", pagename, null)
    intent.data = uri
    openSettingsLauncher.launch(intent)
}

2: registerForActivityResult方式 申请权限以及处理权限的允许,拒绝,永久拒绝

注意: registerForActivityResult() 需要在onStart之前调用

image.png

2.1 创建权限申请的回调

/**
 * 注册Activity结果回调,用于处理多权限请求
 * 返回Map<String, Boolean>,包含每个权限的授权结果
 */
protected val requestPermissionsLauncher = registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
    // 分类处理不同状态的权限
    val grantedPermissions = mutableListOf<String>()       // 已授权的权限
    val deniedPermissions = mutableListOf<String>()       // 被拒绝的权限
    val permanentlyDeniedPermissions = mutableListOf<String>() // 被永久拒绝的权限

    // 遍历权限结果,根据授权状态分类
    permissions.entries.forEach { entry ->
        if (entry.value) {
            // 权限已授予
            grantedPermissions.add(entry.key)
        } else {
            // 权限被拒绝
            deniedPermissions.add(entry.key)
            // API 23+ 检查是否为永久拒绝(用户勾选了"不再询问")
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                if (isPermissionPermanentlyDenied(entry.key)) {
                    permanentlyDeniedPermissions.add(entry.key)
                }
            }
        }
    }

    // 根据权限申请结果执行不同操作
    if (deniedPermissions.isEmpty()) {
        // 所有权限都已授予,执行相应操作
        authorized(permissionType, deniedPermissions)
    } else {
        if (permanentlyDeniedPermissions.isNotEmpty()) {
            // 存在永久拒绝的权限,引导用户前往设置页面手动授权
            PopupUtil.createCommonPopupView(
                this, "权限申请", "以下权限被永久拒绝,是否前往设置页面进行授权?", "前往设置",
                object : CommonPopupListener {
                    override fun sureClick() {
                        // 前往系统设置
                        openAppSettings()
                    }

                    override fun cancelClick() {
                        // 用户取消操作的处理
                    }
                })
        } else {
            // 仅为临时拒绝,显示提示信息
            showToast("部分权限被拒绝: ${deniedPermissions.joinToString()}")
        }
    }
}

/**
 * 判断权限是否被永久拒绝(用户勾选了"不再询问")
 * @param permission 需要检查的权限
 * @return true: 永久拒绝,false: 临时拒绝或首次申请
 */
private fun isPermissionPermanentlyDenied(permission: String): Boolean {
    // 如果shouldShowRequestPermissionRationale返回false,表示用户勾选了"不再询问"
 return !shouldShowRequestPermissionRationale(permission)
                && ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED
}

/**
 * 打开应用设置页面,用于用户手动授予权限
 */
private fun openAppSettings() {
    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
        data = Uri.fromParts("package", packageName, null)
    }
    startActivity(intent)
}

2.2 申请权限


/**
 *获取权限
 */
fun requestPermissionsLauncher(type: Int, permissionList: Array<String>) {
    permissionType = type
    this.permissionList = permissionList
    requestPermissionsLauncher.launch(permissionList)
}

2.3 处理跳转设置页面的返回结果

/**
 * 注册Activity结果回调:用于处理从系统设置页面返回后的权限检查逻辑
 * 当用户从设置页面返回时,会检查所有需要的权限是否都已被授予
 */
private val openSettingsLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        // 初始化标志位,假设所有权限都已被授予
        var allPermissionsGranted = true
        
        // 遍历权限列表,检查每个权限的状态
        for (permission in permissionList) {
            if (ContextCompat.checkSelfPermission(
                    this, permission
                ) != PackageManager.PERMISSION_GRANTED
            ) {
                // 发现有未被授予的权限,更新标志位并跳出循环
                allPermissionsGranted = false
                break
            }
        }
        
        // 根据检查结果显示不同的提示信息
        if (allPermissionsGranted) {
            showToast("权限已在设置中开启")
            // 权限全部开启后,可以执行相关操作
            performActionRequiringPermissions()
        } else {
            showToast("权限仍未全部开启,请再次检查设置")
            // 可以选择再次引导用户进入设置页面或提供其他降级方案
            showPermissionReminderDialog()
        }
    }

/**
 * 执行需要权限的操作(示例方法,需根据实际需求实现)
 */
private fun performActionRequiringPermissions() {
    // 这里实现需要所有目标权限的核心功能
    // 例如:启动相机、访问通讯录等
}

/**
 * 显示权限提醒对话框(示例方法,需根据实际需求实现)
 */
private fun showPermissionReminderDialog() {
    AlertDialog.Builder(this)
        .setTitle("权限不足")
        .setMessage("部分必要权限未开启,可能影响功能使用。是否再次前往设置页面?")
        .setPositiveButton("前往设置") { _, _ -> openAppSettings() }
        .setNegativeButton("取消") { dialog, _ -> dialog.dismiss() }
        .show()
}


/**
*跳转设置页
*/
private fun openAppSettings() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
            data = Uri.fromParts("package", packageName, null)
        }
}

3. 权限基类

package com.qianrun.voice.basic.activity

import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.qianrun.voice.common.pop.PopupUtil
import com.qianrun.voice.common.pop.view.CommonPopupListener
import com.qianrun.voice.common.showToast


/**
 *
 *@Author: wkq
 *
 *@Time: 2025/5/27 13:48
 *
 *@Desc:  权限处理的Activity
 */
open class PermissionsActivity : AppCompatActivity() {

    private var permissionType = -1
    private var permissionList = mutableListOf<String>()




    protected val requestPermissionsLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        val grantedPermissions = mutableListOf<String>()
        val deniedPermissions = mutableListOf<String>()
        val permanentlyDeniedPermissions = mutableListOf<String>()
        permissions.entries.forEach { entry ->
            if (entry.value) {
                grantedPermissions.add(entry.key)
            } else {
                deniedPermissions.add(entry.key)
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    if (isPermissionPermanentlyDenied(entry.key)) {
                        permanentlyDeniedPermissions.add(entry.key)
                    }
                }

            }
        }
        if (deniedPermissions.isEmpty()) {
            authorized(permissionType, deniedPermissions)
        } else {
            if (permanentlyDeniedPermissions.isNotEmpty()) {
                PopupUtil.createCommonPopupView(
                    this, "权限申请", "以下权限被永久拒绝,是否前往设置页面进行授权?", "前往设置",
                    object : CommonPopupListener {
                        override fun sureClick() {
                            //前往系统设置
                            openAppSettings()
                        }

                        override fun cancelClick() {
                        }
                    })

            } else {
                showToast("部分权限被拒绝: ${deniedPermissions.joinToString()}")
            }
        }
    }

    private val openSettingsLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            var allPermissionsGranted = true
            for (permission in permissionList) {
                if (ContextCompat.checkSelfPermission(
                        this, permission
                    ) != PackageManager.PERMISSION_GRANTED
                ) {
                    allPermissionsGranted = false
                    break
                }
            }
            if (allPermissionsGranted) {
                showToast("权限已在设置中开启")
            } else {
                showToast("权限仍未全部开启,请再次检查设置")
            }
        }


    private fun openAppSettings() {
        val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
            data = Uri.fromParts("package", packageName, null)
        }
        openSettingsLauncher.launch(intent)
    }

    /**
     * 判断权限是否被永久拒绝(用户勾选了"不再询问")
     * @param permission 需要检查的权限
     * @return true: 永久拒绝,false: 临时拒绝或首次申请
     */
    private fun isPermissionPermanentlyDenied(permission: String): Boolean {
        return !shouldShowRequestPermissionRationale(
            permission
        ) && ContextCompat.checkSelfPermission(
            this, permission
        ) != PackageManager.PERMISSION_GRANTED
    }

    /**
     *获取权限
     */
    fun requestPermissionsLauncher(type: Int, permissionList: MutableList<String>) {
        permissionType = type
        this.permissionList = permissionList

        requestPermissionsLauncher.launch(permissionList.toTypedArray())
    }



    /**
     *是否拥有权限
     */

    fun isGranted(permissions: List<String>?): Boolean {
        // Android 6.0 以下无需运行时权限
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) return true

        // 空权限列表默认返回 false
        return permissions?.all { isGrantedOne(it) } ?: false
    }

    // 检查单个权限的辅助函数
    private fun isGrantedOne(permission: String): Boolean {
        return ContextCompat.checkSelfPermission(
            this,
            permission
        ) == PackageManager.PERMISSION_GRANTED
    }


    // 获取适配当前系统的媒体权限
     fun getMediaPermissions(): MutableList<String> {
        return if (Build.VERSION.SDK_INT >= 34) {
            // Android 14+ 需要全部三个权限
            mutableListOf<String>(
                android.Manifest.permission.READ_MEDIA_IMAGES,
                android.Manifest.permission.READ_MEDIA_VIDEO,
                "android.permission.READ_MEDIA_VISUAL_USER_SELECTED"
            )
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            // Android 13-14 需要两个细分权限
            mutableListOf<String>(
                android.Manifest.permission.READ_MEDIA_IMAGES,
                android.Manifest.permission.READ_MEDIA_VIDEO
            )
        } else {
            // Android 12 及以下只需旧权限
            mutableListOf<String>(android.Manifest.permission.READ_EXTERNAL_STORAGE)
        }
    }


    /**
     *已授权
     */
    open fun authorized(permissionType: Int, permissionList: MutableList<String>) {}

}

总结

权限处理分为判断,申请,拒绝,永久拒绝,设置页授权这几种情况,日常项目中根据这几种状况处理权限问题就可以了.