一个垃圾的Android权限框架

Posted 鲁迅认识的那只猹

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一个垃圾的Android权限框架相关的知识,希望对你有一定的参考价值。

一个垃圾的android权限框架

学习和参考

  • 简书 https://www.jianshu.com/p/2324a2bdb3d4

写在前头

今天突发奇想想要把Android申请权限的流程封装一下,为使得Android的权限申请更加容易一些。所以经过一番资料的查询和研究,做了一个小小的垃圾权限框架,不优雅也不高效。

项目信息

Github地址
https://github.com/littledavid-tech/GarbagePermission

技术分享图片

如何使用此框架

添加依赖

Step 1. Add the JitPack repository to your build file

Add it in your root build.gradle at the end of repositories:

allprojects {
        repositories {
            ...
            maven { url 'https://www.jitpack.io' }
        }
    }

Step 2. Add the dependency

dependencies {
            implementation 'com.github.littledavid-tech:GarbagePermission:V1.0.1'
    }

调用代码

//Way 1
GarbagePermission
        .with(this)
        .permissions(arrayOf(
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CALL_PHONE))
        .callback(object : OnPermissionRequestListener {
            //当权限被同意的时候,此方法被调用
            override fun onGranted(permission: String) {
                Log.e("TAG", "Granted")
            }
            //当权限被完全拒绝的时候(勾选了不再提醒复选框),此方法被调用
            override fun onDenied(permission: String) {
                Log.e("TAG", "Denied")
            }
            //当权限被拒绝的时候但并非完全拒绝的时候,此方法被调用
            override fun onRationale(permission: String) {
                Log.e("TAG", "Rationale")
            }
        })
        .request()
//Way 2
GarbagePermission
        .with(this)
        .permissions(arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE))
        .callback(object : SimpleOnPermissionRequestListener() {
            override fun onGranted(permission: String) {
                Log.e("TAG", "Granted")
            }
        })
        .request()

实现思路

只有在Android6.0以及之后的版本中,才需要进行动态权限的申请,在6.0之前是不用动态申请权限的。在申请权限的时候,我们习惯于在App首次运行的时候于启动界面将所有的界面都进行申请,并且在进行高危操作的使用,在进行检测权限,如果没有授权则进行权限的申请。

当我们申请权限后,我们必须调用Activity或者Fragment的 onRequestPermissionsResult 方法,所以我们的框架肯定是离不开Activity或者Fragment,又因为Activity比Fragment要独立,所以这里选择了Activity。

我们将所有请求权限的所有的业务逻辑都封装在一个Activity里面,当需要申请权限的时候就启动这个Activity进行权限的申请。


/**
 * 权限相关的回调接口
 * The callback interface for request permission
 * @see SimpleOnPermissionRequestListener
 */
interface OnPermissionRequestListener {
    /**
     * 当权限被同意的时候,此方法会被调用
     * */
    fun onGranted(permission: String)

    /**
     * 如果权限被完全拒绝(勾选了不再提示复选框) 此方法会被调用
     * */
    fun onDenied(permission: String)

    /**
     * 如果此方法没有被完全地拒绝(没有勾选不再提示复选框)此方法会被调用
     *
     * */
    fun onRationale(permission: String)
}

class PermissionActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_permission)

        //避免用户手动启动此Activity
        if (!intent.hasExtra(ACCESS_TOKEN)) {
            finish()
        }

        val permissions = intent.getStringArrayExtra("permissions")

        //判断SDK版本
        if (Build.VERSION.SDK_INT >= 23) {
            requestPermissions(permissions, REQUEST_CODE)
        }
    }

    @TargetApi(23)
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        if (requestCode != REQUEST_CODE) {
            return
        }
        //根据选项的不同,调用不同的回调
        for ((index, value) in permissions.withIndex()) {
            if (grantResults[index] == PackageManager.PERMISSION_GRANTED) {//接受
                mPermissionCallback?.onGranted(value)
            } else if (shouldShowRequestPermissionRationale(value)) {//拒绝,但没有完全拒绝
                mPermissionCallback?.onRationale(value)
            } else {//拒绝
                mPermissionCallback?.onDenied(value)
            }
        }

        finish()
    }

    override fun onDestroy() {
        mPermissionCallback = null
        super.onDestroy()
    }

    companion object {
        private var mPermissionCallback: OnPermissionRequestListener? = null
        /**
         * 通过这个标志位来避免用户手动地打开此Activity,而非调用show方法
         * */
        private const val ACCESS_TOKEN = "token_permission"

        private const val REQUEST_CODE = 10086

        /**
         * 显示此Activity
         * @param context 上下文
         * @param permissions 需要进行请求的权限数组
         * @param callback 处理权限问题的回调
         *
         * @see OnPermissionRequestListener
         * */
        fun show(context: Context, permissions: Array<String>, callback: OnPermissionRequestListener?) {
            mPermissionCallback = callback
            val intent = Intent(context, PermissionActivity::class.java)
            intent.putExtra(ACCESS_TOKEN, ACCESS_TOKEN)
            intent.putExtra("permissions", permissions)
            context.startActivity(intent)
        }
    }
}

但是这还不能够满足我们的要求,因为现在Activity还能够被用户感知到(废话,打开一个Activity,用户看不到就怪了),所以我们还需要对Activity进行一些特殊的设置。将Activity的背景等设置为不可见的状态。

    <!--定义一个透明的Activity的Style/Theme-->
<style name="Transparent" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowBackground">@color/colorTransparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="android:windowIsFloating">true</item>
    <item name="android:windowActionBar">false</item>
    <item name="android:backgroundDimEnabled">false</item>
    <item name="android:windowNoTitle">true</item>
</style>

为Activity设置上Style,在 Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.shycoder.gargabepermissionlibrary">

    <application>
        <activity
            android:name=".PermissionActivity"
            android:theme="@style/Transparent" />
    </application>

</manifest>

搞一个门面类

距离成功还差一点点,虽然我们通过上面建立的Activity就已经能够进行申请权限了,但是直接开启Activity请求权限太不雅观了啊 ?? ,所以我们需要把Activity启动的过程封装一下,建立一个门面类来进行调用,假装高大上一点。

/**
 * GarbagePermission 权限请求框架
 * */
class GarbagePermission private constructor(private val context: Context) {

    private var mPermissions: Array<String>? = null
    private var mCallback: OnPermissionRequestListener? = null

    /**
     * 设置你要请求的权限
     * */
    fun permissions(permissions: Array<String>): GarbagePermission {
        mPermissions = permissions
        return this
    }

    /**
     * 设置回调
     * */
    fun callback(onPermissionRequestListener: OnPermissionRequestListener): GarbagePermission {
        this.mCallback = onPermissionRequestListener
        return this
    }

    /**
     * 开始请求权限
     * */
    fun request() {
        if (mPermissions == null) {
            throw  IllegalArgumentException("Please request permission")
        }
        if (Build.VERSION.SDK_INT >= 23) {
            PermissionActivity.show(context, mPermissions!!, mCallback)
        }
    }

    /**
     * GarbagePermission 权限请求框架
     * */
    companion object {
        fun with(context: Context): GarbagePermission {
            return GarbagePermission(context)
        }
    }
}

总结

到这里,这个小小的框架就已经完成了,虽然网上已经有了很多的权限请求的框架,比我写的这个要优雅和高效很多并且代码量更少,但是,小的轮子还是非常值得我们自己动手造一造的。毕竟只写一写业务的代码进步是非常慢的,身为一个技术工作者,我们总要追寻更优雅的解决方案,OK到此结束,与诸君共勉。

以上是关于一个垃圾的Android权限框架的主要内容,如果未能解决你的问题,请参考以下文章

Django REST框架--认证和权限

如何使用Android片段管理器传递变量[重复]

片段中的Android webView显示空白页面

以编程方式将片段添加到android中的框架布局

什么是 android studio 中的片段活动?

在android活动中设置片段的形状和透明度