当前位置:   article > 正文

[Android]手把手带你写个权限请求工具_android requireactivity

android requireactivity

前言:

这是一个由kotlin编写的权限请求工具,调用只需要一段代码。支持协程式回调和函数式回调。如果你只是白嫖党,请直接划到最底下进入项目地址,添加依赖并开始你的摸鱼划水之旅!

背景:

        传统的权限申请存在许多弊端:

        1、在Activity中需要引入大量代码,各个模块之间藕断丝连,项目臃肿不堪。

2、在Activity接收到权限申请结果回调的时候,还要与调用的地方通信,真的是非常的麻烦。

实现原理:

Fragment也可以进行权限申请,虽然回调在Activity方,但是谷歌给我们提供了一套接口:registerForActivityResult。这套接口简 化了Fragment请求Activity数据回调的方法。我们生成一个空的Fragment放进Activity,再让这个空的Fragment去进行权限申请,接收到返回的数据后再回调给调用方。完事之后再移除这个Fragment。完美解决!

开始:

1.先把这个核心的Fragment实现了吧

PermissionFragment
  1. internal class PermissionFragment(private var mRequestInfo: Array<out String>) : Fragment() {
  2. /**
  3. * 对外的权限申请回调
  4. */
  5. var permissionCallBack: PermissionResultInterface? = null
  6. /**
  7. * 移除自己后的回调
  8. */
  9. var destroyedCallback: (() -> Unit)? = null
  10. private val mActivityLifecycleObserver = object : LifecycleEventObserver {
  11. override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
  12. if (event == Lifecycle.Event.ON_CREATE) {
  13. requireActivity().lifecycle.removeObserver(this)
  14. //注册权限请求回调
  15. val requester = registerForActivityResult(
  16. ActivityResultContracts.RequestMultiplePermissions(),
  17. mPermissionCallback
  18. )
  19. requester.launch(mRequestInfo)
  20. }
  21. }
  22. }
  23. /**
  24. * 注册的Activity申请到的权限的回调
  25. */
  26. private val mPermissionCallback = ActivityResultCallback<Map<String, Boolean>> { map ->
  27. val denied = mutableListOf<String>()
  28. val deniedPermanently = mutableListOf<String>()
  29. map.forEach {
  30. if (!it.value) {
  31. //被拒绝的权限
  32. denied.add(it.key)
  33. if (requireActivity().isPermissionDeniedPermanently(it.key)) {
  34. //被永久拒绝的权限
  35. deniedPermanently.add(it.key)
  36. }
  37. }
  38. }
  39. if (denied.isEmpty()) {
  40. //没有被拒绝的,那就是全部同意了
  41. permissionCallBack?.invoke(PermissionResult.Granted)
  42. } else {
  43. //有被拒绝的
  44. permissionCallBack?.invoke(
  45. PermissionResult.Denied(
  46. denied,
  47. deniedPermanently
  48. )
  49. )
  50. }
  51. removeThis()
  52. }
  53. override fun onAttach(context: Context) {
  54. super.onAttach(context)
  55. requireActivity().lifecycle.addObserver(mActivityLifecycleObserver)
  56. }
  57. /**
  58. * 权限申请完了过后就可以移除自己了
  59. */
  60. private fun removeThis() {
  61. requireActivity().lifecycle.removeObserver(mActivityLifecycleObserver)
  62. parentFragmentManager.beginTransaction().remove(this).commitAllowingStateLoss()
  63. mainThreadHandler.post {
  64. destroyedCallback?.invoke()
  65. }
  66. }
  67. }

onAttach:当这个Fragment被添加到Activity中去的时候会调用该方法。这个时候就需要注册Activity的权限申请回调了,实现逻辑放在mActivityLifecycleObserver 中。

接收到回调后,会进行分类,权限是同意了呢,还是拒绝了呢。

这里新建一个密封类

PermissionResult
  1. sealed class PermissionResult {
  2. /**
  3. * 全部通过
  4. */
  5. object Granted : PermissionResult()
  6. /**
  7. * 其中有被拒绝的权限
  8. * @param deniedPermissions 所有被拒绝的权限,包括被永久拒绝的,一定不是空的集合
  9. * @param deniedPermissionsPermanently 被永久拒绝的权限
  10. */
  11. class Denied(val deniedPermissions: List<String>, val deniedPermissionsPermanently: List<String>) : PermissionResult()
  12. /**
  13. * 已取消
  14. * @param causedByActivityFinished 是否是因为Activity结束而导致的取消请求
  15. */
  16. class Cancel(val causedByActivityFinished: Boolean = false) : PermissionResult()
  17. }

具体解释见注释。

结果的实体类有了,接下来就是往调用方回调了,现在Fragment这方面已经完成了,接下来需要有个类来实现Fragment的启动。

RequestLauncher
  1. internal object RequestLauncher {
  2. private const val FRAGMENT_TAG = "PermissionFragmentTag"
  3. /**
  4. * 调用此函数应直接传入还没有得到的权限
  5. */
  6. fun launch(
  7. permissions: Array<out String>,
  8. activity: FragmentActivity,
  9. callback: PermissionResultInterface
  10. ): RequestLauncher {
  11. if (activity.isFinishing || activity.isDestroyed) {
  12. callback(PermissionResult.Cancel(true))
  13. return this
  14. }
  15. val oldFragment =
  16. activity.supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as PermissionFragment?
  17. oldFragment?.let {
  18. //如果旧的Fragment已经存在,就等它消失之后再进行权限申请
  19. oldFragment.destroyedCallback = {
  20. launch(permissions, activity, callback)
  21. }
  22. } ?: launchFragment(permissions, activity, callback)
  23. return this
  24. }
  25. /**
  26. * 启动Fragment来进行权限申请
  27. */
  28. private fun launchFragment(
  29. permissions: Array<out String>,
  30. activity: FragmentActivity,
  31. callback: PermissionResultInterface
  32. ) {
  33. val newFragment = PermissionFragment(permissions)
  34. newFragment.permissionCallBack = callback
  35. activity.supportFragmentManager
  36. .beginTransaction()
  37. .add(newFragment, FRAGMENT_TAG)
  38. .commitNowAllowingStateLoss()
  39. }
  40. }

启动Fragment并为Fragment设置参数。

OK,启动Fragment的工具也写好了,最后要在最外层封装一层接口了。

通过这个方法就实现对RequestLauncher的调用

PermissionRequestExt.kt

  1. private fun requestPermissionsCore(
  2. activity: FragmentActivity,
  3. vararg permissions: String,
  4. resultCallback: PermissionResultInterface
  5. ) {
  6. //提前先检查一遍,如果所有权限都是已授权的,那就不去启动那个fragment了,直接进行回调
  7. //过滤出被拒绝的权限
  8. val deniedPermissions = activity.filterDeniedPermissions(permissions)
  9. if (deniedPermissions.isEmpty()) {
  10. //权限全都有那就直接回调了
  11. resultCallback(PermissionResult.Granted)
  12. } else {
  13. //有些权限是没有的,那就去申请
  14. RequestLauncher.launch(deniedPermissions, activity, resultCallback)
  15. }
  16. }

这就是一个内部的入口,作为启动RequestLauncher的。接口都基于这个方法实现。

比如接口可以这么写:

  1. fun FragmentActivity.requestPermissionsWithCallback(
  2. vararg permissions: String,
  3. resultCallback: PermissionResultInterface
  4. ) {
  5. requestPermissionsCore(this, *permissions) {
  6. resultCallback(it)
  7. }
  8. }

OK,以上就是全部的核心代码了。

最后贴一下项目地址和怎么去使用:

如何使用:

1、添加依赖

在项目根目录下的build.gradle和settings.gradle中添加 jitpack 库

  1. allprojects {
  2.     repositories {
  3.         ...
  4.         maven { url 'https://jitpack.io' }
  5.     }
  6. }

然后在app目录下的build.gradle添加依赖 

(最新版本号见项目地址)

  1. dependencies {
  2. implementation 'com.github.ldh-star:ClarityPermission:1.0.7'
  3. }

2、使用

在协程中使用:

  1. CoroutineScope(Dispatchers.Main).launch {
  2. val result = requestPermissionsWithCoroutine(WRITE_EXTERNAL_STORAGE)
  3. }
以回调函数的方式使用
  1. requestPermissionsWithCallback(Manifest.permission.CAMERA) { result ->
  2. }
 还有另一种形式
  1. requestPermissions(Manifest.permission.RECORD_AUDIO).granted {
  2. //权限被同意
  3. }.denied {
  4. //权限被拒绝
  5. }
返回结果 result
  1. when (result) {
  2. is PermissionResult.Granted -> {
  3. //权限全部同意
  4. }
  5. is PermissionResult.Denied -> {
  6. result.deniedPermissions//被拒绝的权限
  7. result.deniedPermissionsPermanently//被永久拒绝的权限
  8. }
  9. }

依赖的版本号在项目地址里面看,如下:

项目地址:

Github https://github.com/ldh-star/ClarityPermission

码云 https://gitee.com/liang_dh/ClarityPermission

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/253130
推荐阅读
相关标签
  

闽ICP备14008679号