赞
踩
这是一个由kotlin编写的权限请求工具,调用只需要一段代码。支持协程式回调和函数式回调。如果你只是白嫖党,请直接划到最底下进入项目地址,添加依赖并开始你的摸鱼划水之旅!
传统的权限申请存在许多弊端:
1、在Activity中需要引入大量代码,各个模块之间藕断丝连,项目臃肿不堪。
2、在Activity接收到权限申请结果回调的时候,还要与调用的地方通信,真的是非常的麻烦。
Fragment也可以进行权限申请,虽然回调在Activity方,但是谷歌给我们提供了一套接口:registerForActivityResult。这套接口简 化了Fragment请求Activity数据回调的方法。我们生成一个空的Fragment放进Activity,再让这个空的Fragment去进行权限申请,接收到返回的数据后再回调给调用方。完事之后再移除这个Fragment。完美解决!
1.先把这个核心的Fragment实现了吧
PermissionFragment
- internal class PermissionFragment(private var mRequestInfo: Array<out String>) : Fragment() {
-
- /**
- * 对外的权限申请回调
- */
- var permissionCallBack: PermissionResultInterface? = null
-
- /**
- * 移除自己后的回调
- */
- var destroyedCallback: (() -> Unit)? = null
-
- private val mActivityLifecycleObserver = object : LifecycleEventObserver {
- override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
- if (event == Lifecycle.Event.ON_CREATE) {
- requireActivity().lifecycle.removeObserver(this)
- //注册权限请求回调
- val requester = registerForActivityResult(
- ActivityResultContracts.RequestMultiplePermissions(),
- mPermissionCallback
- )
- requester.launch(mRequestInfo)
- }
- }
- }
-
- /**
- * 注册的Activity申请到的权限的回调
- */
- private val mPermissionCallback = ActivityResultCallback<Map<String, Boolean>> { map ->
- val denied = mutableListOf<String>()
- val deniedPermanently = mutableListOf<String>()
- map.forEach {
- if (!it.value) {
- //被拒绝的权限
- denied.add(it.key)
- if (requireActivity().isPermissionDeniedPermanently(it.key)) {
- //被永久拒绝的权限
- deniedPermanently.add(it.key)
- }
- }
- }
- if (denied.isEmpty()) {
- //没有被拒绝的,那就是全部同意了
- permissionCallBack?.invoke(PermissionResult.Granted)
- } else {
- //有被拒绝的
- permissionCallBack?.invoke(
- PermissionResult.Denied(
- denied,
- deniedPermanently
- )
- )
- }
- removeThis()
- }
-
- override fun onAttach(context: Context) {
- super.onAttach(context)
- requireActivity().lifecycle.addObserver(mActivityLifecycleObserver)
- }
-
- /**
- * 权限申请完了过后就可以移除自己了
- */
- private fun removeThis() {
- requireActivity().lifecycle.removeObserver(mActivityLifecycleObserver)
- parentFragmentManager.beginTransaction().remove(this).commitAllowingStateLoss()
- mainThreadHandler.post {
- destroyedCallback?.invoke()
- }
- }
-
- }

onAttach:当这个Fragment被添加到Activity中去的时候会调用该方法。这个时候就需要注册Activity的权限申请回调了,实现逻辑放在mActivityLifecycleObserver 中。
接收到回调后,会进行分类,权限是同意了呢,还是拒绝了呢。
这里新建一个密封类
PermissionResult
- sealed class PermissionResult {
- /**
- * 全部通过
- */
- object Granted : PermissionResult()
-
- /**
- * 其中有被拒绝的权限
- * @param deniedPermissions 所有被拒绝的权限,包括被永久拒绝的,一定不是空的集合
- * @param deniedPermissionsPermanently 被永久拒绝的权限
- */
- class Denied(val deniedPermissions: List<String>, val deniedPermissionsPermanently: List<String>) : PermissionResult()
-
- /**
- * 已取消
- * @param causedByActivityFinished 是否是因为Activity结束而导致的取消请求
- */
- class Cancel(val causedByActivityFinished: Boolean = false) : PermissionResult()
-
-
- }

具体解释见注释。
结果的实体类有了,接下来就是往调用方回调了,现在Fragment这方面已经完成了,接下来需要有个类来实现Fragment的启动。
RequestLauncher
- internal object RequestLauncher {
-
- private const val FRAGMENT_TAG = "PermissionFragmentTag"
-
- /**
- * 调用此函数应直接传入还没有得到的权限
- */
- fun launch(
- permissions: Array<out String>,
- activity: FragmentActivity,
- callback: PermissionResultInterface
- ): RequestLauncher {
- if (activity.isFinishing || activity.isDestroyed) {
- callback(PermissionResult.Cancel(true))
- return this
- }
-
- val oldFragment =
- activity.supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as PermissionFragment?
- oldFragment?.let {
- //如果旧的Fragment已经存在,就等它消失之后再进行权限申请
- oldFragment.destroyedCallback = {
- launch(permissions, activity, callback)
- }
- } ?: launchFragment(permissions, activity, callback)
- return this
- }
-
-
- /**
- * 启动Fragment来进行权限申请
- */
- private fun launchFragment(
- permissions: Array<out String>,
- activity: FragmentActivity,
- callback: PermissionResultInterface
- ) {
- val newFragment = PermissionFragment(permissions)
- newFragment.permissionCallBack = callback
- activity.supportFragmentManager
- .beginTransaction()
- .add(newFragment, FRAGMENT_TAG)
- .commitNowAllowingStateLoss()
- }
-
- }

启动Fragment并为Fragment设置参数。
OK,启动Fragment的工具也写好了,最后要在最外层封装一层接口了。
通过这个方法就实现对RequestLauncher的调用
PermissionRequestExt.kt
- private fun requestPermissionsCore(
- activity: FragmentActivity,
- vararg permissions: String,
- resultCallback: PermissionResultInterface
- ) {
- //提前先检查一遍,如果所有权限都是已授权的,那就不去启动那个fragment了,直接进行回调
- //过滤出被拒绝的权限
- val deniedPermissions = activity.filterDeniedPermissions(permissions)
- if (deniedPermissions.isEmpty()) {
- //权限全都有那就直接回调了
- resultCallback(PermissionResult.Granted)
- } else {
- //有些权限是没有的,那就去申请
- RequestLauncher.launch(deniedPermissions, activity, resultCallback)
- }
- }

这就是一个内部的入口,作为启动RequestLauncher的。接口都基于这个方法实现。
比如接口可以这么写:
- fun FragmentActivity.requestPermissionsWithCallback(
- vararg permissions: String,
- resultCallback: PermissionResultInterface
- ) {
- requestPermissionsCore(this, *permissions) {
- resultCallback(it)
- }
- }
OK,以上就是全部的核心代码了。
最后贴一下项目地址和怎么去使用:
1、添加依赖
在项目根目录下的build.gradle和settings.gradle中添加 jitpack 库
- allprojects {
- repositories {
- ...
- maven { url 'https://jitpack.io' }
- }
- }
然后在app目录下的build.gradle添加依赖
(最新版本号见项目地址)
- dependencies {
- implementation 'com.github.ldh-star:ClarityPermission:1.0.7'
- }
2、使用
在协程中使用:
- CoroutineScope(Dispatchers.Main).launch {
- val result = requestPermissionsWithCoroutine(WRITE_EXTERNAL_STORAGE)
- }
以回调函数的方式使用
- requestPermissionsWithCallback(Manifest.permission.CAMERA) { result ->
-
- }
还有另一种形式
- requestPermissions(Manifest.permission.RECORD_AUDIO).granted {
- //权限被同意
- }.denied {
- //权限被拒绝
- }
返回结果 result
- when (result) {
- is PermissionResult.Granted -> {
- //权限全部同意
- }
- is PermissionResult.Denied -> {
- result.deniedPermissions//被拒绝的权限
- result.deniedPermissionsPermanently//被永久拒绝的权限
- }
- }
依赖的版本号在项目地址里面看,如下:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。