权限处理新范式:PermissionsDispatcher自定义权限处理器开发指南
你是否还在为Android运行时权限(Runtime Permissions)的复杂逻辑而头疼?从6.0系统引入动态权限以来,开发者需要处理权限请求、用户拒绝、不再询问等多种场景,代码往往变得臃肿不堪。本文将带你使用PermissionsDispatcher构建自定义权限处理器,通过声明式API将权限逻辑与业务代码解耦,实现优雅的权限管理。读完本文你将掌握:自定义权限请求流程、Kotlin扩展用法、特殊权限处理及完整的集成方案。
项目概述与核心优势
PermissionsDispatcher是一个专注于Android运行时权限管理的开源库,采用声明式API设计,通过注解处理器自动生成权限处理代码,避免手动编写重复的权限检查逻辑。项目核心模块包括:
- 注解模块:annotation/ 提供
@NeedsPermission、@OnShowRationale等核心注解 - 核心库:library/ 包含权限检查工具类PermissionUtils
- Kotlin扩展:ktx/ 提供协程支持和DSL风格API
- 示例代码:sample/ 和 ktx-sample/ 展示Java与Kotlin的使用方式
与原生API相比,PermissionsDispatcher的核心优势在于:
- 编译时安全检查,避免运行时异常
- 自动生成权限请求代码,减少模板代码
- 支持特殊权限(如SYSTEM_ALERT_WINDOW)处理
- 提供Kotlin协程和Flow适配
基础集成与配置
添加依赖
在项目级build.gradle中添加Maven仓库:
allprojects {
repositories {
maven { url "https://maven.aliyun.com/repository/public" }
mavenCentral()
}
}
在应用模块build.gradle中添加依赖:
dependencies {
implementation "com.github.permissions-dispatcher:permissionsdispatcher:4.1.0"
kapt "com.github.permissions-dispatcher:permissionsdispatcher-processor:4.1.0"
// Kotlin扩展(可选)
implementation "com.github.permissions-dispatcher:ktx:4.1.0"
}
配置AndroidManifest
在AndroidManifest.xml中声明所需权限:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<!-- 特殊权限 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
自定义权限处理器开发
核心注解与工作原理
PermissionsDispatcher通过注解标记需要权限的方法及对应的回调,编译时生成MainActivityPermissionsDispatcher等辅助类。核心注解包括:
| 注解 | 作用 | 必选 |
|---|---|---|
@RuntimePermissions | 标记需要处理权限的Activity/Fragment | ✓ |
@NeedsPermission | 标记需要权限才能执行的方法 | ✓ |
@OnShowRationale | 权限请求前展示 rationale | ✗ |
@OnPermissionDenied | 权限被拒绝时调用 | ✗ |
@OnNeverAskAgain | 用户选择"不再询问"时调用 | ✗ |
工作流程如下:
- 开发者使用注解标记权限需求
- 注解处理器生成包含权限逻辑的调度类
- 调用生成类的
withPermissionCheck方法触发权限请求 - 权限结果通过
onRequestPermissionsResult自动分发
自定义权限处理器实现
以相机权限为例,创建自定义权限处理器需要以下步骤:
1. 创建权限请求接口
定义权限请求回调接口,包含权限授予、拒绝等状态:
interface CameraPermissionHandler {
fun onCameraGranted()
fun onCameraDenied()
fun onCameraNeverAskAgain()
}
2. 实现权限调度器
使用PermissionsDispatcher注解处理器生成权限处理代码:
@RuntimePermissions
class CameraPermissionDispatcher(
private val activity: FragmentActivity,
private val handler: CameraPermissionHandler
) {
@NeedsPermission(Manifest.permission.CAMERA)
fun handleCameraPermission() {
handler.onCameraGranted()
}
@OnShowRationale(Manifest.permission.CAMERA)
fun showCameraRationale(request: PermissionRequest) {
AlertDialog.Builder(activity)
.setTitle("权限请求")
.setMessage("需要相机权限以拍摄照片")
.setPositiveButton("允许") { _, _ -> request.proceed() }
.setNegativeButton("拒绝") { _, _ -> request.cancel() }
.show()
}
@OnPermissionDenied(Manifest.permission.CAMERA)
fun onCameraDenied() {
handler.onCameraDenied()
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
fun onCameraNeverAskAgain() {
handler.onCameraNeverAskAgain()
}
fun requestCameraPermission() {
handleCameraPermissionWithPermissionCheck(activity)
}
}
3. 在Activity中集成
在MainActivity.kt中使用自定义处理器:
class MainActivity : AppCompatActivity(), CameraPermissionHandler {
private lateinit var cameraHandler: CameraPermissionDispatcher
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
cameraHandler = CameraPermissionDispatcher(this, this)
findViewById<Button>(R.id.button_camera).setOnClickListener {
cameraHandler.requestCameraPermission()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
cameraHandler.onRequestPermissionsResult(requestCode, grantResults)
}
override fun onCameraGranted() {
supportFragmentManager.beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment())
.commit()
}
override fun onCameraDenied() {
Toast.makeText(this, "相机权限被拒绝", Toast.LENGTH_SHORT).show()
}
override fun onCameraNeverAskAgain() {
AlertDialog.Builder(this)
.setMessage("相机权限已被禁用,请在设置中启用")
.setPositiveButton("前往设置") { _, _ ->
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}
.show()
}
}
4. 布局文件配置
activity_main.xml定义权限请求按钮:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/button_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="请求相机权限" />
<FrameLayout
android:id="@+id/sample_content_fragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
Kotlin扩展与高级特性
PermissionsDispatcher的ktx模块提供了丰富的Kotlin扩展,支持协程和DSL风格调用,使权限请求更简洁。
协程支持
使用registerForActivityResult结合协程实现异步权限请求:
private val cameraPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
if (granted) {
// 权限授予
} else {
// 权限拒绝
}
}
// 调用
lifecycleScope.launch {
cameraPermission.launch(Manifest.permission.CAMERA)
}
PermissionsRequester接口
PermissionsRequester.kt定义了权限请求接口,通过launch方法触发请求:
val cameraRequester = permissionsRequester(
Manifest.permission.CAMERA,
onShowRationale = { request ->
showRationaleDialog(request)
},
onPermissionDenied = {
Toast.makeText(context, "权限被拒绝", Toast.LENGTH_SHORT).show()
}
) {
// 权限授予后的操作
startCameraPreview()
}
// 触发请求
cameraRequester.launch()
特殊权限处理
对于SYSTEM_ALERT_WINDOW等特殊权限,PermissionsDispatcher提供了专门的处理机制。在processor/src/main/kotlin/permissions/dispatcher/processor/impl/java/SystemAlertWindowHelper.kt中实现了特殊权限的跳转逻辑。
处理系统弹窗权限的示例代码:
@RuntimePermissions
class SystemAlertWindowHandler(private val activity: Activity) {
@NeedsPermission(Manifest.permission.SYSTEM_ALERT_WINDOW)
fun showOverlayWindow() {
val windowManager = activity.getSystemService(Context.WINDOW_SERVICE) as WindowManager
// 创建悬浮窗视图
val overlayView = TextView(activity).apply {
text = "悬浮窗示例"
setBackgroundColor(Color.RED)
setPadding(16.dpToPx(), 16.dpToPx(), 16.dpToPx(), 16.dpToPx())
}
val params = WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
else
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT
)
windowManager.addView(overlayView, params)
}
fun requestOverlayPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(activity)) {
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:${activity.packageName}"))
activity.startActivityForResult(intent, REQUEST_OVERLAY_PERMISSION)
} else {
showOverlayWindowWithPermissionCheck(activity)
}
}
}
完整示例与最佳实践
相机权限请求流程
下图展示了使用自定义处理器的相机权限请求完整流程:
- 用户点击相机按钮触发权限请求
- 检查权限状态,未授予则显示请求对话框
- 用户允许后调用
onCameraGranted展示相机预览 - 用户拒绝且选择"不再询问"时引导至设置页面
常见问题解决方案
1. 权限请求结果不回调
确保在Activity/Fragment中正确重写onRequestPermissionsResult并调用生成类的对应方法:
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// 必须调用生成类的onRequestPermissionsResult方法
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults)
}
2. 特殊权限跳转失败
对于需要跳转到系统设置页面的权限,使用Settings.ACTION_MANAGE_OVERLAY_PERMISSION等特定Action:
fun startInstallUnknownSourcesSettings(packageName: String) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES,
Uri.parse("package:$packageName"))
startActivityForResult(intent, REQUEST_INSTALL_PERMISSION)
}
3. Kotlin协程集成
结合PermissionRequestViewModel.kt实现协程支持:
lifecycleScope.launch {
val permissionResult = withContext(Dispatchers.Main) {
runCatching {
PermissionsRequesterImpl(
arrayOf(Manifest.permission.CAMERA),
activity,
onShowRationale = { /* 显示 rationale */ },
onPermissionDenied = { /* 处理拒绝 */ },
requiresPermission = { /* 权限授予操作 */ },
onNeverAskAgain = { /* 处理不再询问 */ },
permissionRequestType = PermissionRequestType.NORMAL
).launch()
}
}
}
总结与进阶方向
通过本文的介绍,你已经掌握了使用PermissionsDispatcher构建自定义权限处理器的核心方法。项目地址:https://gitcode.com/gh_mirrors/per/PermissionsDispatcher。建议进一步学习以下内容:
- 源码解析:processor/ 目录下的注解处理器实现
- 测试用例:test/ 目录包含的权限场景测试
- 迁移指南:doc/migration_guide.md 介绍版本升级注意事项
权限管理是Android应用开发的重要环节,合理使用PermissionsDispatcher可以显著提升代码质量和开发效率。建议在项目中封装通用权限处理器,统一管理应用内所有权限请求,为用户提供一致的权限体验。
如果本文对你有帮助,请点赞收藏并关注后续更新,下期将带来"PermissionsDispatcher与Jetpack Compose集成"的深度教程。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



