基于 registerForActivityResult 处理Android权限的一系列逻辑调用.
在项目中,使用系统的一些功能需要,用户手动授权一系列权限才能使用系统的功能,例如相机.定位等功能.个人基于AndroidX新的申请方式,记录一下权限申请,拒绝,永久拒绝的处理路径.
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;//未授权
/**
*是否拥有权限
*/
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之前调用
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>) {}
}
总结
权限处理分为判断,申请,拒绝,永久拒绝,设置页授权这几种情况,日常项目中根据这几种状况处理权限问题就可以了.