权限处理新范式:PermissionsDispatcher自定义权限处理器开发指南

权限处理新范式:PermissionsDispatcher自定义权限处理器开发指南

【免费下载链接】PermissionsDispatcher A declarative API to handle Android runtime permissions. 【免费下载链接】PermissionsDispatcher 项目地址: https://gitcode.com/gh_mirrors/per/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用户选择"不再询问"时调用

工作流程如下:

  1. 开发者使用注解标记权限需求
  2. 注解处理器生成包含权限逻辑的调度类
  3. 调用生成类的withPermissionCheck方法触发权限请求
  4. 权限结果通过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)
        }
    }
}

完整示例与最佳实践

相机权限请求流程

下图展示了使用自定义处理器的相机权限请求完整流程:

  1. 用户点击相机按钮触发权限请求
  2. 检查权限状态,未授予则显示请求对话框
  3. 用户允许后调用onCameraGranted展示相机预览
  4. 用户拒绝且选择"不再询问"时引导至设置页面

常见问题解决方案

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。建议进一步学习以下内容:

权限管理是Android应用开发的重要环节,合理使用PermissionsDispatcher可以显著提升代码质量和开发效率。建议在项目中封装通用权限处理器,统一管理应用内所有权限请求,为用户提供一致的权限体验。

如果本文对你有帮助,请点赞收藏并关注后续更新,下期将带来"PermissionsDispatcher与Jetpack Compose集成"的深度教程。

【免费下载链接】PermissionsDispatcher A declarative API to handle Android runtime permissions. 【免费下载链接】PermissionsDispatcher 项目地址: https://gitcode.com/gh_mirrors/per/PermissionsDispatcher

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值