Ps: I plan to move to Denver from Jane book, Jane book did not discuss the atmosphere, posted for a long time, no one has discussed, or Denver popular, the atmosphere is good, remember 16 years just registered at that time also do not let the post, the application writer did not pass…
Have the wheels don’t make me wheels, this is generally recognized as an industry, I am not here from the beginning to write a permission to library, but again on open source components encapsulation in a unified company internal call, ready to replace the third party implementation, from open source libraries will encapsulate this Angle to write very little, I take you enjoy another scenery here, just say don’t like do not spray ah, I didn’t even graduate kindergarten at my level
Project address: BW_Libs
So let’s look at the Demo code
Don’t GIF, record this time is too long, GIF is too big page card. The idea of Demo is as follows: Normal permission judgment, there are three callbacks, the user confirms to grant permission, the user does not grant permission, and the user does not click the system permission popup. Here, we start the system permission setting page in the callback after the user does not display the popup window. After the user closes the permission setting page, we check whether the user has given permission or not. If the user has not given permission, we will display a popup window to prompt the user to close the page without giving permission
The Demo code is as follows:
class PermissionActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?). {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_permission)
btn_permission.setOnClickListener{
PermissionManage
.with(this)
.permission(Manifest.permission.CALL_PHONE)
.permission(Manifest.permission.CAMERA)
.permission(Manifest.permission.READ_PHONE_STATE)
.onSuccess { Toast.makeText(this@PermissionActivity."Successful application", Toast.LENGTH_SHORT).show() }
.onDenial { Toast.makeText(this@PermissionActivity."User rejected", Toast.LENGTH_SHORT).show() }
.onDontShow { IntentUtils.startSettingActivityForResult(this.200) }
.run()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int.data: Intent?). {
if (requestCode == 200) {
var permissions = listOf(Manifest.permission.CALL_PHONE, Manifest.permission.CAMERA, Manifest.permission.READ_PHONE_STATE)
if (PermissionManage.isHavePermissions(this, permissions)) {
Toast.makeText(this."Welcome your permission.", Toast.LENGTH_SHORT).show()
} else {
showDialog()
}
}
}
private fun showDialog(a) {
var build: AlertDialog.Builder = AlertDialog.Builder(this)
build.setMessage("Lack of permission. Request permission.")
build.setPositiveButton("Application permission".object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface? , which:Int) {
IntentUtils.startSettingActivityForResult(this@PermissionActivity.200) dialog? .dismiss()// dialog? .cancel()
}
})
build.setNegativeButton("No permission granted.".object : DialogInterface.OnClickListener {
override fun onClick(dialog: DialogInterface? , which:Int) {
Toast.makeText(this@PermissionActivity."Sorry, some permissions are mandatory, you can't run without permissions.", Toast.LENGTH_SHORT).show() dialog? .dismiss()this@PermissionActivity.finish()
}
})
build.show()
}
}
Copy the code
Component Encapsulation
1. Good-looking, responsive functional programming ideas, providing chain call
The Fresco API is not very good in this sense. Of course, Fresco is very complex. But Glide API, the other image loading buddy, is Nice
This is the API for the permissions component that I’ve encapsulated, which mimics functional programming and provides chain calls. This code is nice and easy to follow. Functional programming has a natural advantage in handling code with continuous complex logic, and its style is known for its clarity, making it the best way to encapsulate tool-like components
PermissionManage
.with(this)
.permission(Manifest.permission.CALL_PHONE)
.permission(Manifest.permission.CAMERA)
.permission(Manifest.permission.READ_PHONE_STATE)
.onSuccess { Toast.makeText(this@PermissionActivity."Successful application", Toast.LENGTH_SHORT).show() }
.onDenial { Toast.makeText(this@PermissionActivity."User rejected", Toast.LENGTH_SHORT).show() }
.onDontShow { IntentUtils.startSettingActivityForResult(this.200) }
.run()
Copy the code
2. Third party library height, no trace replaceable
I’m using the open source library AndPermission, so take a look at my wrapper around AndPermission
2.1 – Extraction interface third party permission library is what, is to provide permission to apply for verification, sobs its common function, is 1, give parameters and then execute, is so simple, why, because the function is single, even if the request to verify permission
interface IPermissionExecuter {
fun run(permissionConfig: PermissionConfig)
}
Copy the code
2.2 – Implement interfaces and wrap third party libraries
class AndPermissinExecuterImpl : IPermissionExecuter {
override fun run(permissionConfig: PermissionConfig) {
AndPermission.with(permissionConfig.context)
.permission(permissionConfig.permissions.toTypedArray())
// The user has given permission
.onGranted({ permissions: List<String> -> permissionConfig.onSuccessAction() })
// The user rejects permissions, including no longer displaying permissions pop-ups in this column
.onDenied({ permissions: List<String> ->
// Check whether the user no longer displays the permissions popup, if not, go to the permissions Settings page
if (AndPermission.hasAlwaysDeniedPermission(permissionConfig.context, permissions)) {
// Open the permission Settings page
permissionConfig.onDontShowAction()
return@onDenied
}
permissionConfig.onDenialAction()
})
.start()
}
}
Copy the code
The third party permission library needs the same parameters. Whatever it has, we wrap it in PermissionConfig and pass the parameters in through PermissionConfig so that when we want to replace the third party implementation, Just write another implementation class for IPermissionExecuter
2.3 – Provides a factory class for switch management
That goes without saying, factory mode, strike familiar routines
object ExecuterFactor {
@JvmField
val AND_PERMISSION = "AND_PERMISSION"
@JvmField
val RX_PERMISSION = "RX_PERMISSION"
@JvmField
val DEFAULT_EXECUTER = AND_PERMISSION
@JvmStatic
fun getInstance(a): IPermissionExecuter {
return getInstance(DEFAULT_EXECUTER)
}
@JvmStatic
private fun getInstance(type: String): IPermissionExecuter {
return when (type) {
AND_PERMISSION -> AndPermissinExecuterImpl()
DEFAULT_EXECUTER -> AndPermissinExecuterImpl()
else -> AndPermissinExecuterImpl()
}
}
}
Copy the code
3. Extract public parameters and use build
Let’s take a look at the class PermissionConfig, which wraps the parameters required by the third party
class PermissionConfig {
lateinit var context: Context
// The permission is successfully applied
var onSuccessAction: () -> Unit = {}
// Call back when permission application fails
var onDenialAction: () -> Unit = {}
// User Settings do not display the permission request callback window
var onDontShowAction: () -> Unit = {}
// Permission set
var permissions = mutableListOf<String>()
private var type: String = ExecuterFactor.DEFAULT_EXECUTER
/**
* 添加权限
*/
fun addPermission(permission: String) {
if(! permission.isEmpty()) permissions.add(permission) }/** * Set type */
fun setType(type: String): PermissionConfig {
if(! type.isEmpty())this.type = type
return this
}
/** * Perform the operation */
fun run(a) {
ExecuterFactor.getInstance().run(this)}}Copy the code
Extracted a few parameters, is easy to understand, the required parameters, use set to receive because there can be multiple, then the three callback, agree, disagree, closed access popup window, with the aid of kotlin language, we don’t like Java to write an interface, direct statement into an empty implementation, also is not null, Then provide methods to set these parameters
However, we can’t just use PermissionConfig, because it will change over time and we need a unified place to build parameter wrapper objects. This is the familiar build mode
class PermissionBuild(var context: Context) {
var permissionConfig: PermissionConfig = PermissionConfig()
init {
permissionConfig.context = this.context
}
/** * Set type */
fun type(type: String): PermissionBuild {
if(! type.isEmpty()) permissionConfig.setType(type)return this
}
/**
* 添加权限
*/
fun permission(permission: String): PermissionBuild {
if(! permission.isEmpty()) permissionConfig? .addPermission(permission)return this
}
/** * Succeeded in adding */
fun onSuccess(onSuccessAction: () -> Unit): PermissionBuild {
if(onSuccessAction ! =null) permissionConfig.onSuccessAction = onSuccessAction
return this
}
/** * Failed to add operation */
fun onDenial(onDenialAction: () -> Unit): PermissionBuild {
if(onDenialAction ! =null) permissionConfig.onDenialAction = onDenialAction
return this
}
/** * add no permissions popup operation */
fun onDontShow(onDontShowAction: () -> Unit): PermissionBuild {
if(onDontShowAction ! =null) permissionConfig.onDontShowAction = onDontShowAction
return this
}
/** * Perform the operation */
fun run(a) {
permissionConfig.run()
}
}
Copy the code
The build logic here is very simple, we can not write, in order to practice the principle of writing, or thanks to Kotlin syntax, methods can directly receive function parameters, and we do not need to write interface, it is really convenient, especially when we can write at one time, do not need to switch classes. It’s nice not to interrupt your train of thought
4. Provide unified entrance
As a utility class, there should be a unified entry, static or new object, here the recommended use of static methods, easy to understand
class PermissionManage {
/** * provides related static entry, like Glide with binding context ** /
companion object {
@JvmStatic
fun with(context: Context): PermissionBuild {
return PermissionBuild(context)
}
@JvmStatic
fun isHavePermission(context: Context, permission: String): Boolean {
return PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, permission)
}
@JvmStatic
fun isHavePermissions(context: Context, permissions: List<String>): Boolean {
for (it in permissions) {
if(! (PackageManager.PERMISSION_GRANTED == ContextCompat.checkSelfPermission(context, it)))return false
}
return true}}}Copy the code
Similar to Glide. With returns the PermissionBuild builder after adding context for adding data, and there are other utility methods for checking permissions
I go from back to front, the idea is based on step by step implementation, the middle class is based on my purpose to package the third party library step by step, simple function library is basically based on this perspective
Look at the class structure
This component is very simple, in fact, I have written this permission component in Java before, the same idea, the address is here: In the beginning, I wanted to change Java to Kotlin, but I changed the way I wrote it. In the end, I basically abandoned the old component and rewrote it. The old component now seems to be too much nonsense, I deleted almost half of the classes. This is the most difficult name in my opinion
New class structure:
Old class structure:
Simple, but well done, wrapping third-party components, providing a unified API implementation, and dynamically switching third-place implementations seamlessly
We used a few tricks to count:
-
Extract the same, abstract the different – the template pattern wraps third-party implementations, extracts run to perform the action, and wraps all parameters into a unified configuration class
-
Unified switching between different third party implementations – Factory mode
-
Build Unified build data-builder pattern
-
Provides unified interface – door panel mode
The above basic are routines, permissions this component function is single, we may not experience the magic of the above several routines, this thing can only rely on fantasy to understand deepening, have to write their own hand in order to have personal experience, in order to finally glory through, UML class diagram has time to put on it
One last joke
, when writing this component test nima I forget to declare the required permissions in the configuration file, I don’t how to debug how all right, I’ll find a lot of times the code also didn’t find the problem, the old blow, old depressed, let me the mood of a day old, poor waste more than two hours of time, later remembered, nima I am smoking his mouth for 5 minutes, too lost
Advise everyone to encounter problems must be calm ah, not calm consequences is a waste of life, it is very simple things, the code is also written very well, once, is to forget the configuration file this matter, other no problem, but it happened that good things turn bad, ah, calm, he must be normal heart, or their own really suffer
And fragmentation of this problem, millet, meizu, huawei mobile phone with a male version of the code is not open access Settings page, not to be fit, true his damned pain, I again take baidu, also good directly to look for, wrote a utility class, but consider, this tool is open system of the page, I haven’t put in authority component, IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils: IntentUtils