在 Android 开发中,动态权限管理是一个常见的需求,尤其是在高版本 Android 系统中,权限管理变得更加严格和复杂。为了简化权限申请的流程,减少重复代码,本文将介绍如何使用 Kotlin 封装一个高效、易用的权限工具类。
权限工具类封装
- 检查权限
- 请求权限
- 处理权限请求结果
- 显示权限请求理由
- 跳转到应用设置
使用示例
- 在 Activity 中使用
- 在 Fragment 中使用
适配高版本 Android
- Android 12 及以上版本的权限适配
- 后台权限处理
扩展功能
- 批量检查权限
- 自动处理权限请求理由
回调接口定义
定义一个回调接口,用于返回权限请求的结果。
interface PermissionResultCallback {
fun onPermissionsGranted() // 所有权限已授予
fun onPermissionsDenied() // 部分或全部权限被拒绝
}
权限工具类封装
将权限相关的逻辑封装在工具类 PermissionUtils 中。
import android.Manifest
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.provider.Settings
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.ActivityResultRegistry
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.lifecycle.LifecycleOwner
object PermissionUtils {
/**
* 请求权限
*
* @param lifecycleOwner LifecycleOwner(Activity 或 Fragment)
* @param registry ActivityResultRegistry
* @param permissions 需要请求的权限数组
* @param callback 权限请求结果回调
*/
fun requestPermissions(
lifecycleOwner: LifecycleOwner,
registry: ActivityResultRegistry,
permissions: Array<String>,
callback: PermissionResultCallback
) {
val launcher = registry.register(
"permission_request_key", // 唯一的 key
lifecycleOwner,
ActivityResultContracts.RequestMultiplePermissions()
) { results ->
if (results.all { it.value }) {
// 所有权限已授予
callback.onPermissionsGranted()
} else {
// 部分或全部权限被拒绝
callback.onPermissionsDenied()
}
}
// 启动权限请求
launcher.launch(permissions)
}
/**
* 检查单个权限是否已授予
*
* @param permission 需要检查的权限
* @return 是否已授予
*/
fun Context.isPermissionGranted(permission: String): Boolean {
return ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED
}
/**
* 检查多个权限是否已全部授予
*
* @param permissions 需要检查的权限数组
* @return 是否全部已授予
*/
fun Context.arePermissionsGranted(permissions: Array<String>): Boolean {
return permissions.all { isPermissionGranted(it) }
}
/**
* 显示权限请求理由弹窗
*
* @param permission 需要请求的权限
* @param message 弹窗提示信息
* @param onRequestAgain 用户点击“确定”后的回调
*/
fun Activity.showPermissionRationale(
permission: String,
message: String,
onRequestAgain: () -> Unit
) {
AlertDialog.Builder(this)
.setTitle("Permission Required")
.setMessage(message)
.setPositiveButton("OK") { _, _ -> onRequestAgain() }
.setNegativeButton("Cancel", null)
.show()
}
/**
* 跳转到应用设置页面
*/
fun Activity.openAppSettings() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}
}
3. 在 Activity 中使用
在 Activity 中调用工具类,并实现回调接口。
import android.Manifest
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity(), PermissionResultCallback {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 定义需要请求的权限
val permissions = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE
)
// 检查权限是否已授予
if (PermissionUtils.arePermissionsGranted(this, permissions)) {
onPermissionsGranted()
} else {
// 请求权限
PermissionUtils.requestPermissions(
this, // LifecycleOwner
activityResultRegistry, // ActivityResultRegistry
permissions,
this // PermissionResultCallback
)
}
}
override fun onPermissionsGranted() {
// 权限已授予的逻辑
Toast.makeText(this, "All permissions granted!", Toast.LENGTH_SHORT).show()
}
override fun onPermissionsDenied() {
// 权限被拒绝的逻辑
Toast.makeText(this, "Some permissions denied!", Toast.LENGTH_SHORT).show()
}
}
4. 在 Fragment 中使用
在 Fragment 中调用工具类,并实现回调接口。
import android.Manifest
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
class MyFragment : Fragment(), PermissionResultCallback {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// 定义需要请求的权限
val permissions = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.READ_EXTERNAL_STORAGE
)
// 检查权限是否已授予
if (PermissionUtils.arePermissionsGranted(requireContext(), permissions)) {
onPermissionsGranted()
} else {
// 请求权限
PermissionUtils.requestPermissions(
viewLifecycleOwner, // LifecycleOwner
requireActivity().activityResultRegistry, // ActivityResultRegistry
permissions,
this // PermissionResultCallback
)
}
}
override fun onPermissionsGranted() {
// 权限已授予的逻辑
Toast.makeText(requireContext(), "All permissions granted!", Toast.LENGTH_SHORT).show()
}
override fun onPermissionsDenied() {
// 权限被拒绝的逻辑
Toast.makeText(requireContext(), "Some permissions denied!", Toast.LENGTH_SHORT).show()
}
}
5. 总结
工具类封装:将权限检查、请求、弹窗和设置跳转逻辑封装在 PermissionUtils 中。
**回调机制:**通过 PermissionResultCallback 接口返回权限请求结果。
**灵活调用:**支持在 Activity 和 Fragment 中调用工具类。
通过这种方式,代码结构清晰,逻辑复用性强,且与 Activity 和 Fragment 解耦。如果有其他需求或问题,欢迎继续讨论!