XXPermissions与Kotlin扩展:简化权限请求代码

XXPermissions与Kotlin扩展:简化权限请求代码

【免费下载链接】XXPermissions Android 权限请求框架,已适配 Android 14 【免费下载链接】XXPermissions 项目地址: https://gitcode.com/GitHub_Trending/xx/XXPermissions

你是否还在为Android权限申请的繁琐代码而头疼?是否觉得Java版本的权限请求逻辑冗长且可读性差?本文将带你探索如何通过Kotlin扩展功能,结合XXPermissions框架,用更简洁、更优雅的方式处理Android权限请求,让你的代码量减少50%以上,同时提升可读性和可维护性。读完本文后,你将能够:掌握XXPermissions的核心API使用、编写自定义Kotlin扩展函数、处理复杂权限场景的最佳实践。

框架简介与核心优势

XXPermissions是一款专为Android平台设计的权限请求框架,已全面适配至Android 14,提供了简洁的API和强大的功能。相比其他权限框架,它具有以下核心优势:

  • 全面的权限支持:覆盖从普通危险权限到特殊权限(如悬浮窗、安装包、画中画等)的所有权限类型,具体可参考README.md中的权限对比表格。
  • 自动版本适配:新权限在旧系统上自动适配,无需开发者手动判断Android版本。
  • 错误检测机制:在Debug模式下自动检测常见的权限申请错误,如未在Manifest中注册权限、TargetSdkVersion不匹配等。
  • 内存泄漏修复:针对Android 12及以上系统的权限申请内存泄漏问题进行了专门优化。

XXPermissions功能展示

图1:XXPermissions支持的多种权限请求场景,包括单权限、组权限等

Kotlin扩展的力量:从繁琐到简洁

Kotlin的扩展函数(Extension Functions)允许我们为现有类添加新的函数,而无需继承该类或使用设计模式(如装饰器模式)。这一特性非常适合简化XXPermissions的调用方式。

标准用法对比

Java标准用法

XXPermissions.with(this)
    .permission(PermissionLists.getCameraPermission())
    .permission(PermissionLists.getRecordAudioPermission())
    .request(new OnPermissionCallback() {
        @Override
        public void onResult(@NonNull List<IPermission> grantedList, @NonNull List<IPermission> deniedList) {
            if (deniedList.isEmpty()) {
                // 权限全部授予
                startCamera();
            } else {
                // 处理权限被拒绝的情况
                showPermissionDeniedTip(deniedList);
            }
        }
    });

Kotlin扩展后的用法

// 扩展函数定义
fun Activity.requestCameraAndRecordPermissions(
    onGranted: () -> Unit,
    onDenied: (List<IPermission>) -> Unit
) {
    XXPermissions.with(this)
        .permission(PermissionLists.getCameraPermission())
        .permission(PermissionLists.getRecordAudioPermission())
        .request(object : OnPermissionCallback {
            override fun onResult(grantedList: MutableList<IPermission>, deniedList: MutableList<IPermission>) {
                if (deniedList.isEmpty()) {
                    onGranted()
                } else {
                    onDenied(deniedList)
                }
            }
        })
}

// 调用处代码
requestCameraAndRecordPermissions(
    onGranted = { startCamera() },
    onDenied = { showPermissionDeniedTip(it) }
)

通过对比可以明显看出,使用Kotlin扩展后,调用处的代码变得极为简洁,将重复的模板代码封装到扩展函数中,大幅提升了代码可读性。

核心API与扩展实现

基础扩展函数编写

要创建有效的Kotlin扩展,首先需要熟悉XXPermissions的核心API。XXPermissions的入口类是library/src/main/java/com/hjq/permissions/XXPermissions.java,主要提供以下关键方法:

  • with(activity: Activity): 创建权限请求实例
  • permission(permission: IPermission): 添加需要请求的权限
  • request(callback: OnPermissionCallback): 发起权限请求

基于这些API,我们可以编写基础的扩展函数。例如,为Activity添加一个通用的权限请求扩展:

// 通用权限请求扩展
fun Activity.requestPermissions(
    vararg permissions: IPermission,
    onAllGranted: () -> Unit,
    onDenied: (List<IPermission>) -> Unit,
    onDoNotAskAgain: (List<IPermission>) -> Unit = { 
        // 默认实现,可根据需求重写
        XXPermissions.startPermissionActivity(this, it)
    }
) {
    XXPermissions.with(this)
        .permission(permissions.toList())
        .request(object : OnPermissionCallback {
            override fun onResult(grantedList: MutableList<IPermission>, deniedList: MutableList<IPermission>) {
                when {
                    deniedList.isEmpty() -> onAllGranted()
                    XXPermissions.isDoNotAskAgainPermissions(this@requestPermissions, deniedList) -> 
                        onDoNotAskAgain(deniedList)
                    else -> onDenied(deniedList)
                }
            }
        })
}

这个扩展函数封装了权限请求的三种常见结果:全部授予、部分拒绝、被勾选"不再询问"。使用时只需关注具体的业务逻辑,无需重复编写权限请求模板代码。

常见权限场景的扩展实现

针对不同的权限使用场景,我们可以编写更具体的扩展函数,使代码更加简洁。

1. 相机权限请求

相机权限是应用中常见的权限需求,通常还需要同时请求录音权限(如视频拍摄场景)。我们可以创建一个专用的扩展函数:

// 相机和录音权限扩展
fun Activity.requestCameraAndAudioPermissions(
    onGranted: () -> Unit,
    onDenied: (List<IPermission>) -> Unit,
    onDoNotAskAgain: (List<IPermission>) -> Unit
) {
    requestPermissions(
        PermissionLists.getCameraPermission(),
        PermissionLists.getRecordAudioPermission(),
        onAllGranted = onGranted,
        onDenied = onDenied,
        onDoNotAskAgain = onDoNotAskAgain
    )
}

// 使用示例
requestCameraAndAudioPermissions(
    onGranted = { startVideoRecording() },
    onDenied = { showToast("需要相机和录音权限才能录制视频") },
    onDoNotAskAgain = { permissions ->
        showDialog("请在应用设置中开启相机和录音权限", 
            positiveAction = { XXPermissions.startPermissionActivity(this, permissions) })
    }
)

相机权限请求界面

图2:使用XXPermissions请求相机权限的界面效果

2. 存储权限请求

存储权限在不同Android版本中有较大差异,XXPermissions已经处理了这些差异,我们可以通过扩展函数进一步简化:

// 存储权限请求扩展
fun Activity.requestStoragePermissions(
    onGranted: () -> Unit,
    onDenied: (List<IPermission>) -> Unit
) {
    val storagePermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        PermissionLists.getManageExternalStoragePermission()
    } else {
        PermissionLists.getWriteExternalStoragePermission()
    }
    
    requestPermissions(
        storagePermission,
        onAllGranted = onGranted,
        onDenied = onDenied
    )
}

这个扩展函数自动根据系统版本选择合适的存储权限,对于Android 11及以上使用MANAGE_EXTERNAL_STORAGE,以下版本使用WRITE_EXTERNAL_STORAGE。XXPermissions会自动处理版本适配,开发者无需关心底层实现细节。

存储权限请求界面

图3:Android 11+系统的存储权限请求界面

高级扩展技巧

1. 协程支持

结合Kotlin协程,我们可以将回调式的权限请求转换为 suspend 函数,进一步提升代码可读性。首先需要创建一个协程适配扩展:

// 协程支持扩展
suspend fun Activity.awaitPermissions(
    vararg permissions: IPermission
): PermissionResult {
    return suspendCancellableCoroutine { continuation ->
        requestPermissions(
            *permissions,
            onAllGranted = { 
                continuation.resume(PermissionResult.Granted) 
            },
            onDenied = { denied -> 
                continuation.resume(PermissionResult.Denied(denied)) 
            },
            onDoNotAskAgain = { denied -> 
                continuation.resume(PermissionResult.DoNotAskAgain(denied)) 
            }
        )
    }
}

// 权限结果密封类
sealed class PermissionResult {
    object Granted : PermissionResult()
    data class Denied(val permissions: List<IPermission>) : PermissionResult()
    data class DoNotAskAgain(val permissions: List<IPermission>) : PermissionResult()
}

使用时,在ViewModel或协程作用域中调用:

viewModelScope.launch {
    when (val result = requireActivity().awaitPermissions(
        PermissionLists.getCameraPermission()
    )) {
        is PermissionResult.Granted -> startCamera()
        is PermissionResult.Denied -> showDeniedMessage(result.permissions)
        is PermissionResult.DoNotAskAgain -> showSettingDialog(result.permissions)
    }
}

2. 自定义权限描述

XXPermissions支持自定义权限申请前的说明对话框,通过扩展函数可以轻松实现:

// 带权限说明的扩展
fun Activity.requestPermissionWithRationale(
    permission: IPermission,
    rationale: String,
    onGranted: () -> Unit,
    onDenied: () -> Unit
) {
    if (XXPermissions.isGrantedPermission(this, permission)) {
        onGranted()
        return
    }
    
    if (XXPermissions.shouldShowRequestPermissionRationale(this, permission)) {
        AlertDialog.Builder(this)
            .setTitle("权限申请")
            .setMessage(rationale)
            .setPositiveButton("确定") { _, _ ->
                requestPermissions(permission, 
                    onAllGranted = onGranted, 
                    onDenied = { onDenied() })
            }
            .setNegativeButton("取消", null)
            .show()
    } else {
        requestPermissions(permission, 
            onAllGranted = onGranted, 
            onDenied = { onDenied() })
    }
}

使用时,只需提供权限和对应的说明文本:

requestPermissionWithRationale(
    permission = PermissionLists.getLocationPermission(),
    rationale = "为了提供精准的位置服务,需要获取您的位置信息",
    onGranted = { startLocationService() },
    onDenied = { showLocationDeniedTip() }
)

最佳实践与注意事项

1. 权限结果处理

权限请求的结果处理需要考虑多种情况,包括:权限全部授予、部分授予、被拒绝、被勾选"不再询问"等。通过Kotlin扩展,我们可以统一处理这些情况,确保代码的一致性。建议的做法是创建一个基础的权限结果处理扩展:

// 权限结果处理扩展
fun Activity.handlePermissionResult(
    grantedList: List<IPermission>,
    deniedList: List<IPermission>,
    onAllGranted: () -> Unit,
    onPartialGranted: (List<IPermission>, List<IPermission>) -> Unit = { _, _ -> },
    onDenied: (List<IPermission>) -> Unit = { 
        Toast.makeText(this, "部分权限被拒绝,功能可能受限", Toast.LENGTH_SHORT).show()
    },
    onDoNotAskAgain: (List<IPermission>) -> Unit = { permissions ->
        AlertDialog.Builder(this)
            .setTitle("权限申请")
            .setMessage("需要以下权限才能正常使用功能:${permissions.joinToString { it.name }},请在设置中开启")
            .setPositiveButton("去设置") { _, _ ->
                XXPermissions.startPermissionActivity(this, permissions)
            }
            .setNegativeButton("取消", null)
            .show()
    }
) {
    when {
        deniedList.isEmpty() -> onAllGranted()
        XXPermissions.isDoNotAskAgainPermissions(this, deniedList) -> onDoNotAskAgain(deniedList)
        else -> {
            onPartialGranted(grantedList, deniedList)
            onDenied(deniedList)
        }
    }
}

2. 避免内存泄漏

在使用Kotlin扩展时,需要注意避免常见的内存泄漏问题:

  • 避免在扩展函数中持有Activity的强引用,特别是在回调中。
  • 对于需要在Fragment中使用的扩展,建议同时提供Fragment版本的扩展函数。
  • 当Activity或Fragment销毁时,取消正在进行的权限请求。

3. 与ViewModel结合使用

在MVVM架构中,建议将权限请求的逻辑放在ViewModel中处理,通过LiveData或StateFlow将结果通知给UI层。可以创建专门的扩展函数支持ViewModel:

// ViewModel扩展
fun ViewModel.requestPermissions(
    activity: Activity,
    vararg permissions: IPermission,
    result: MutableLiveData<PermissionResult>
) {
    XXPermissions.with(activity)
        .permission(permissions.toList())
        .request(object : OnPermissionCallback {
            override fun onResult(grantedList: MutableList<IPermission>, deniedList: MutableList<IPermission>) {
                when {
                    deniedList.isEmpty() -> result.value = PermissionResult.Granted
                    XXPermissions.isDoNotAskAgainPermissions(activity, deniedList) -> 
                        result.value = PermissionResult.DoNotAskAgain(deniedList)
                    else -> result.value = PermissionResult.Denied(deniedList)
                }
            }
        })
}

总结与展望

通过Kotlin扩展功能,XXPermissions的使用体验得到了极大的提升,代码量显著减少,可读性和可维护性大幅提高。本文介绍的扩展技巧可以应用于各种权限请求场景,从简单的单权限请求到复杂的多权限组合场景。

XXPermissions框架仍在持续发展中,未来可能会加入更多高级功能,如权限请求的优先级管理、动态权限组等。作为开发者,我们应该充分利用Kotlin的语言特性,结合框架提供的API,编写更加简洁、高效的代码。

最后,建议大家在实际项目中根据具体需求,创建一套适合自己团队的权限扩展函数库,统一权限请求的处理方式,提升开发效率和代码质量。如果你有更好的扩展实践或想法,欢迎在项目的Issue中分享交流。

本文示例代码基于XXPermissions 26.5版本编写,不同版本间可能存在API差异,请以实际使用的版本为准。完整的权限扩展示例可参考项目的帮助文档

【免费下载链接】XXPermissions Android 权限请求框架,已适配 Android 14 【免费下载链接】XXPermissions 项目地址: https://gitcode.com/GitHub_Trending/xx/XXPermissions

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

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

抵扣说明:

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

余额充值