手把手教你搭建android模块化项目框架(五)权限工具封装

2023-09-01 14:02:19 浏览数 (4)

废话不多说,先看效果

代码语言:text复制
  override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_act)
        //单个权限
        requestPermission(Manifest.permission.READ_PHONE_STATE) { g, d, ad ->
            Log.v("granted", "READ_PHONE_STATEis granted $g")
        }
        //组合权限
        requestPermission(
            Manifest.permission.READ_PHONE_STATE,
            Manifest.permission.READ_CONTACTS
        ) { g, d, ad ->
            Log.v("granted", "READ_PHONE_STATE READ_CONTACTS is granted $g")
        }
    }

android6.0以上需要动态请求权限,这里不多废话了,想达到一个简单高效的权限使用方式,就跟我一步一步去封装。

之前比较好用的权限库是rxPermissions,但是由于目前的项目都不太想引入rxjava使用,因此我们用Kotlin封装一个属于自己的权限库。

首先我们可以参考下rxPermissions库,代码如下:

代码语言:text复制
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
        RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
        boolean isNewInstance = rxPermissionsFragment == null;
        if (isNewInstance) {
            rxPermissionsFragment = new RxPermissionsFragment();
            FragmentManager fragmentManager = activity.getFragmentManager();
            fragmentManager
                    .beginTransaction()
                    .add(rxPermissionsFragment, TAG)
                    .commitAllowingStateLoss();
            fragmentManager.executePendingTransactions();
        }
        return rxPermissionsFragment;
    }

这里我们发现他使用了一个fragment作为媒介接收请求结果,无论在activity或者在fragment中请求时,都会将这个fragment添加到当前页面进行处理,这个思路有点类似glide的生命周期监控,我们可以参考这个思路也创建一个fragment进行操作。

整个fragment中代码部分仅有权限申请回调处理和对rxjava的生命周期处理,这里我们借用这个思路创建自己的permissionFragment即可。

由于lifecycle库拥有自带的生命周期处理,因此我们仅需要写出申请权限的回调即可。

代码如下:

代码语言:text复制
class PermissionFragment : Fragment() {
    companion object {
        private const val TAG = "PermissionFragment"
        fun getPermissionFragment(
            activity: FragmentActivity,
            block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
        ): PermissionFragment {
            var permissionFragment = findPermissionsFragment(activity)
            if (permissionFragment == null) {
                permissionFragment = PermissionFragment()
                activity.supportFragmentManager.commit(true) {
                    add(permissionFragment, TAG)
                }
            }
            permissionFragment.block = block
            return permissionFragment
        }

        private fun findPermissionsFragment(activity: FragmentActivity): PermissionFragment? {
            return activity.supportFragmentManager.findFragmentByTag(TAG) as? PermissionFragment
        }
    }

    //参数说明
    //granted :申请的权限是否都成功了
   //deniedList:被拒绝的权限
  //alwaysDeniedList:被点了不再询问并拒绝的权限
   //这里的参数回调可以根据需求自行封装。
    private var block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit =
        { _, _, _ -> }

    private val launcher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { result ->
        lifecycleScope.launchWhenResumed {
            dealResult(requireActivity(), result, block)
            requireActivity().supportFragmentManager.commit(true) {
                remove(this@PermissionFragment)
            }
        }
    }

    fun requestPermission(
        permissions: Array<String>
    ) {
        lifecycleScope.launchWhenResumed {
            launcher.launch(permissions)
        }
    }

    /**
     * 处理请求权限结果
     */
    private suspend fun dealResult(
        activity: FragmentActivity,
        result: Map<String, Boolean>,
        block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit,
    ) = withContext(Dispatchers.IO) {
        val allDeniedList = result.filterValues { !it }.mapNotNull { it.key }
        val alwaysDeniedList =
            allDeniedList.filter {
                ActivityCompat.shouldShowRequestPermissionRationale(
                    activity,
                    it
                )
            }
        val deniedList = allDeniedList - alwaysDeniedList.toSet()
        var granted = true
        if (allDeniedList.isNotEmpty()) {
            granted = false
        }
        withContext(Dispatchers.Main) {
            block(granted, deniedList.toTypedArray(), alwaysDeniedList.toTypedArray())
        }
    }
}

到这一步,我们完成了fragment的开发,但是想要更简单的使用,我们需要借助kotlin扩展方法来使用,我们封装一个更方便的扩展方法以便调用,代码如下:

代码语言:text复制
fun LifecycleOwner.requestPermission(
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit,
    permissions: Array<String>
) {
    runCatching {
        when (this@requestPermission) {
            is FragmentActivity -> {
                PermissionFragment.getPermissionFragment(this@requestPermission, block)
                    .requestPermission(permissions)
            }

            is Fragment -> {
                PermissionFragment.getPermissionFragment(
                    this@requestPermission.requireActivity(),
                    block
                )
                    .requestPermission(permissions)
            }

            else -> {
                throw RuntimeException("requestPermission LifecycleOwner必须是activity或fragment")
            }
        }
    }.onFailure {
        block(false, permissions, arrayOf())
    }
}

上述封装了一个初步可用的扩展方法,但是为了更方便使用,我们进一步封装,单个,两个组合,三个组合的方法,更方便使用,代码如下:

代码语言:text复制
//单个权限申请
fun LifecycleOwner.requestPermission(
    p1: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1))
}
//两个个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2))
}

//三个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    p3: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2, p3))
}
//四个权限组合申请
fun LifecycleOwner.requestPermission(
    p1: String,
    p2: String,
    p3: String,
    p4: String,
    block: (granted: Boolean, deniedList: Array<String>, alwaysDeniedList: Array<String>) -> Unit
) {
    requestPermission(block, arrayOf(p1, p2, p3, p4))
}

至此,权限Util已经能达到文章开头的使用效果。

//本代码均未完整测试,建议自行测试后使用。

项目地址

1 人点赞