Android 权限申请总结

463 阅读2分钟
1、默认权限申请
  1. 申请:
requestPermissions(arrayOf(Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STORAGE), 45)
  1. 回调:
override fun onRequestPermissionsResult(
    requestCode: Int,
    permissions: Array<String>,
    grantResults: IntArray
) {}
2、 之前用的优秀三方 RxPermissions
rxPermissions
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { // Always true pre-M
           // I can control the camera now
        } else {
           // Oups permission denied
        }
    });

由于上面库用的rxJava, 而项目目前使用的协程那一套,没接入rxJava, 所以参照上面自己封装了一下

3、flow 实现的 FlowPermissions
  1. FlowPermissions
class FlowPermissions {
    val TAG: String = FlowPermissions::class.java.simpleName

    @VisibleForTesting
    var mFlowPermissionsFragment: Lazy<FlowPermissionsFragment>? = null

    constructor(activity: FragmentActivity) {
        mFlowPermissionsFragment = getLazySingleton(activity.supportFragmentManager)
    }

    constructor(fragment: Fragment) {
        mFlowPermissionsFragment = getLazySingleton(fragment.childFragmentManager)
    }

    private fun getLazySingleton(fragmentManager: FragmentManager): Lazy<FlowPermissionsFragment> {
        return object : Lazy<FlowPermissionsFragment> {
            private var flowPermissionsFragment: FlowPermissionsFragment? = null
            override val value: FlowPermissionsFragment
                get() = getRxPermissionsFragment(fragmentManager)

            override fun isInitialized(): Boolean {
                return flowPermissionsFragment != null
            }
        }
    }

    private fun getRxPermissionsFragment(fragmentManager: FragmentManager): FlowPermissionsFragment {
        var rxPermissionsFragment = flowPermissionsFragment(fragmentManager)
        val isNewInstance = rxPermissionsFragment == null
        if (isNewInstance) {
            rxPermissionsFragment = FlowPermissionsFragment()
            fragmentManager
                .beginTransaction()
                .add(rxPermissionsFragment, TAG)
                .commitNow()
        }
        return rxPermissionsFragment!!
    }

    private fun flowPermissionsFragment(fragmentManager: FragmentManager): FlowPermissionsFragment? {
        return if (fragmentManager.findFragmentByTag(TAG) != null) {
            fragmentManager.findFragmentByTag(TAG) as FlowPermissionsFragment
        } else {
            null
        }
    }

    fun request(vararg permissions: String): FlowPermissions {
        mFlowPermissionsFragment?.value?.requestPermissions2(*permissions)
        return this
    }

    fun getFlows(): Flow<Boolean> {
        return mFlowPermissionsFragment?.value?.onRequestPermissionsResults!!
    }
}
  1. FlowPermissionsFragment
class FlowPermissionsFragment : Fragment() {
    private val _effect: Channel<Boolean> = Channel()
    var onRequestPermissionsResults: Flow<Boolean> = _effect.receiveAsFlow()

    @TargetApi(Build.VERSION_CODES.M)
    fun requestPermissions2(vararg permissions: String) {
        val permissionList = ArrayList<String>()
        permissions.forEach {
            val b = ContextCompat.checkSelfPermission(this@FlowPermissionsFragment.requireContext(), it) != PackageManager.PERMISSION_GRANTED
            if (b) {
                permissionList.add(it)
            }
        }
        if (permissionList.isNotEmpty()) {
            this@FlowPermissionsFragment.requestPermissions(permissionList.toTypedArray(), PERMISSIONS_REQUEST_CODE)
        }
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode != PERMISSIONS_REQUEST_CODE) return
        val shouldShowRequestPermissionRationale = BooleanArray(permissions.size)
        for (i in permissions.indices) {
            shouldShowRequestPermissionRationale[i] = shouldShowRequestPermissionRationale(
                permissions[i]
            )
        }
        onRequestPermissions(
            permissions,
            grantResults,
            shouldShowRequestPermissionRationale
        )
    }

    private fun onRequestPermissions(
        permissions: Array<String>,
        grantResults: IntArray,
        shouldShowRequestPermissionRationale: BooleanArray
    ) {
        var granted = true
        grantResults.forEach {
            if (it != PackageManager.PERMISSION_GRANTED) {
                granted = false
            }
        }
        lifecycleScope.launch {
            _effect.send(granted)
        }
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun isGranted(permission: String?): Boolean {
        val fragmentActivity = activity
            ?: throw IllegalStateException("This fragment must be attached to an activity.")
        return fragmentActivity.checkSelfPermission(permission!!) == PackageManager.PERMISSION_GRANTED
    }

    @TargetApi(Build.VERSION_CODES.M)
    fun isRevoked(permission: String?): Boolean {
        val fragmentActivity = activity
            ?: throw IllegalStateException("This fragment must be attached to an activity.")
        return fragmentActivity.packageManager.isPermissionRevokedByPolicy(
            permission!!,
            requireActivity().packageName
        )
    }

    companion object {
        private const val PERMISSIONS_REQUEST_CODE = 42
    }
}
  1. 使用
lifecycleScope.launch {
    FlowPermissions(this@MainActivity)
        .request(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_FINE_LOCATION)
        .getFlows()
        .collectLatest { granted ->
            Log.d("granted", "$granted")
        }
}

这边只是做了简单的判断, 就是申请的权限,全部都允许了,才会granted==true。如果想要做定制修改。只需要 修改 FlowPermissionsFragment类下的 onRequestPermissions方法中的 _effect.send(granted),自己定义实体类。就可以在 collectLatest中获取。

4、 官方给了新的权限申请方式,也是特别好用的
  1. 声明回调
private val activityResultLauncher =
    registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        // Handle Permission granted/rejected
        permissions.entries.forEach {
            val permissionName = it.key
            val isGranted = it.value
            if (isGranted) {
                // Permission is granted
            } else {
                // Permission is denied
            }
        }
    }
  1. 申请权限
activityResultLauncher.launch(
    arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE
    )
)
4.1、虽然不是链式,但是也是相当的简单明了。 简单封装一下:
  1. 封装
class PermissionTool private constructor() {
    companion object {
        private lateinit var requestMultiplePermissions: ActivityResultLauncher<Array<String>>
        private var tool: PermissionTool? = null
            get() {
                if (field == null) field = PermissionTool()
                return field
            }

        @Synchronized
        fun getInstance(activity: ComponentActivity): PermissionTool {
            requestMultiplePermissions = activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { map ->
                mCallback.invoke(!map.containsValue(false))
            }
            return tool!!
        }

        var mCallback: (success: Boolean) -> Unit = {}
    }

    fun requestMultiplePermissions(activity: ComponentActivity, permission: Array<String>, callback: (success: Boolean) -> Unit) {
        mCallback = callback
        if (permission.all { ActivityCompat.checkSelfPermission(activity.baseContext, it) == PackageManager.PERMISSION_GRANTED }) {
            callback.invoke(true)
        } else {
            requestMultiplePermissions.launch(permission)
        }
    }
}
  1. 使用,一定要在start方法之前调用getInstance(),
//声明
private lateinit var permissionTool: PermissionTool

//oncreate方法中调用:
permissionTool = PermissionTool.getInstance(this@MainActivity)

// 调用
permissionTool.requestMultiplePermissions(
    this@MainActivity,
    arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
) { isGranted ->
    
}

4.2、扩展式封装,不像上面那样麻烦
  1. 新建扩展类
fun FragmentActivity.requestPermission(permissions: Array<String>, callBack: (granted: Boolean) -> Unit) {
    lateinit var requestMultiplePermissions: ActivityResultLauncher<Array<String>>
    requestMultiplePermissions = this.activityResultRegistry.register("registry", ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
        callBack(!permissions.containsValue(false))
        requestMultiplePermissions.unregister()//unregister()是关键,由于不是在onCreate方法中注册的,不加上它,在使用时会发生重复监听的情况。
    }
    requestMultiplePermissions.launch(permissions)
}
  1. 使用
requestPermission(
    arrayOf(
        Manifest.permission.CAMERA,
        Manifest.permission.READ_EXTERNAL_STORAGE,
        Manifest.permission.WRITE_EXTERNAL_STORAGE
    )
) { isGranted ->
}