PermissionX
一,预备知识
SDK——开源库
- 没有界面
- 是逻辑功能
- 做好的工具库SDK是被其他项目引用
- 面向其他开发者做的
- 稳定工作,提供简单的接口给其他开发者
PermissionX
简化获取运行时权限的资源库
二,怎么写自己的SDK?
1. 新建一个 Android 项目,名字是你想给这个开源库的名字
2. 加一个模块
之前我们都在app下面写,写出来的都是app
现在我们自己开一个library,写开源库
3. 库模块和app模块的区别
4. 实现设想
运行时权限API封装一般要特定上下文依赖,且还要回调处理
市面的解决办法:
- BaseActivity
- 透明的Activity
- Fragment中申请运行时权限
why?
优势:不像Activity那样要界面,可以搞个隐藏的Fragment然后在他里面去对运行时权限的API进行封装。且对本来的Activity性能没有影响。
5. 代码实现
InvisibleFragment-隐形Fragment
第一版:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| package com.lmc.mylibrary
import android.content.pm.PackageManager import androidx.fragment.app.Fragment
class InvisibleFragment : Fragment() { private var callback: ((Boolean, List<String>) -> Unit)? = null fun requestNow(cb: (Boolean, List<String>) -> Unit, vararg permissions: String) { callback = cb requestPermissions(permissions, 1) } @Deprecated("Deprecated in Java") override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { if (requestCode == 1) { val deniedList = ArrayList<String>() for ((index, result) in grantResults.withIndex()) { if (result != PackageManager.PERMISSION_GRANTED) { deniedList.add(permissions[index]) } } val allGranted = deniedList.isEmpty() callback?.let { it(allGranted, deniedList) } } } }
|
第二版,优化函数类型参数写的复杂冗余后
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| package com.lmc.mylibrary
import android.content.pm.PackageManager import androidx.fragment.app.Fragment
typealias PermissionCallback = (Boolean, List<String>) -> Unit
class InvisibleFragment : Fragment() { private var callback: PermissionCallback? = null fun requestNow(cb: PermissionCallback, vararg permissions: String) { callback = cb requestPermissions(permissions, 1) } @Deprecated("Deprecated in Java") override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) { if (requestCode == 1) { val deniedList = ArrayList<String>() for ((index, result) in grantResults.withIndex()) { if (result != PackageManager.PERMISSION_GRANTED) { deniedList.add(permissions[index]) } } val allGranted = deniedList.isEmpty() callback?.let { it(allGranted, deniedList) } } } }
|
PermissionX-对外接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com.lmc.mylibrary
import androidx.fragment.app.FragmentActivity
object PermissionX { private const val TAG = "InvisibleFragment" fun request(activity: FragmentActivity, vararg permissions: String, callback: PermissionCallback) { val fragmentManager = activity.supportFragmentManager val existedFragment = fragmentManager.findFragmentByTag(TAG) val fragment = if (existedFragment != null) { existedFragment as InvisibleFragment } else { val invisibleFragment = InvisibleFragment() fragmentManager.beginTransaction().add(invisibleFragment, TAG).commitNow() invisibleFragment } fragment.requestNow(callback, *permissions) } }
|
三,测试
app模块中引入library模块
xml写个按钮,然后AndroidManifest.xml里面要什么权限,就写什么权限。
1 2 3
| <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_CONTACTS" />
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| package com.lmc.permissionx
import android.Manifest import android.content.Intent import android.net.Uri import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.Button import android.widget.Toast import com.lmc.mylibrary.PermissionX
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) findViewById<Button>(R.id.makeCallBtn).setOnClickListener { PermissionX.request(this, Manifest.permission.CALL_PHONE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_CONTACTS) { { allGranted,deniedList -> if (allGranted) { call() } else { Toast.makeText(this,"你取消授权:$deniedList",Toast.LENGTH_SHORT).show() } } } } private fun call(){ try { val intent = Intent(Intent.ACTION_CALL) intent.data = Uri.parse("tel:10086") startActivity(intent) } catch (e:SecurityException){ e.printStackTrace() } } }
|
四,发布开源库
两个棘手问题:
-
第一行代码中的那个JCenter用不了,现在我们试一下MavenCentral
-
还有Gradle也变了,那个AndroidStudio中Project下的build.gradle根本就没有没有buildscript和allprojects了(移到了另外一个地方)
2022年冬天的:
build.gradle
在这里
准备域名
我的:lmc.pub
创建工单
-
注册一下这个sonatype
账号邮箱,密码要有大写。
-
-
这里就1按这个来,23看下面这张
-
然后马上就会发一条邮件到你邮箱,点进去
等下又来一个:
教你去给域名加一条TXT解析,内容给你了就是工单编号
登录域名管理的网站(我的是阿里云,那这个举例子)
控制台-》域名
解析
然后我们就可以向 s01.oss.sonatype.org 这个地址发布库
MavenCentral还要求,所有发布的库都必须使用GPG来进行签名才行
下载 GnuPG
我是win https://www.gpg4win.org/download.html
win记得只能下这个(你要是去了官网,这个下载地址在老下面,很容易下了前面的原始的。原始后果就是后面那个代码跑不起来)
然后找个文件夹安装好(我的在D盘)
密钥创建
gpg --full-generate-key
然后会跳出来下面这个,设一个密码
然后
第二行后8位记下来
E8B132DC
上传公钥到GPC服务器
gpg --keyserver keyserver.ubuntu.com --send-keys 你的后8位数
gpg --keyserver keyserver.ubuntu.com --recv-keys 你的后8位数
导出私钥
gpg --export-secret-keys -o 你想保存的地址+secring.gpg
gradle-maven-publish-plugin这样一个第三方开源插件
项目根目录下的gradle.properties文件
GROUP=com.guolindev.glance
POM_ARTIFACT_ID=glance
VERSION_NAME=1.0.0
POM_NAME=Glance
POM_DESCRIPTION=A simple and handy Android database debugging library.
POM_INCEPTION_YEAR=2020
POM_URL=https://github.com/guolindev/Glance/
POM_LICENSE_NAME=The Apache Software License, Version 2.0
POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENSE_DIST=repo
POM_SCM_URL=https://github.com/guolindev/Glance/
POM_SCM_CONNECTION=scm:git:git://github.com/guolindev/Glance.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://github.com/guolindev/Glance.git
POM_DEVELOPER_ID=guolindev
POM_DEVELOPER_NAME=Lin Guo
POM_DEVELOPER_URL=https://github.com/guolindev/
signing.keyId=密钥ID的后8位
signing.password=密钥密码
signing.secretKeyRingFile=私钥文件路径
mavenCentralUsername=Sonatype账号
mavenCentralPassword=Sonatype密码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| GROUP=pub.lmc.androidlib POM_ARTIFACT_ID=permissionx VERSION_NAME=1.0.0
POM_NAME=PermissionX POM_DESCRIPTION=Android开发中更方便的申请运行时权限. POM_INCEPTION_YEAR=2022 POM_URL=https://github.com/Mecenlee/PermissionX/
POM_LICENSE_NAME=The Apache Software License, Version 2.0 POM_LICENSE_URL=https://www.apache.org/licenses/LICENSE-2.0.txt POM_LICENSE_DIST=repo
POM_SCM_URL=https://github.com/Mecenlee/PermissionX/ POM_SCM_CONNECTION=scm:git:git://github.com/Mecenlee/PermissionX.git POM_SCM_DEV_CONNECTION=scm:git:ssh://github.com/Mecenlee/PermissionX.git
POM_DEVELOPER_ID=mecenlee POM_DEVELOPER_NAME=Mincan Li POM_DEVELOPER_URL=https://github.com/Mecenlee/
signing.keyId=密钥ID的后8位 signing.password=密钥密码 signing.secretKeyRingFile=私钥文件路径(记得带.gpg)
mavenCentralUsername=Sonatype用户名 mavenCentralPassword=Sonatype密码
|
前三行决定开源库地址
pub.lmc.androidlib:permissionx:1.0.0
其他的照着写写
在Android Studio右侧工具栏的Gradle页签当中找到publish这个任务(找不到正常上网搜,我遇到且解决了。写了解决方案在CSDN)
然后我们的sonatype主页就给你发消息说在同步了
第一个网址几十分钟就好了 https://repo1.maven.org/maven2/
第二个要等一会
https://search.maven.org/
然后在这里才能搜到你的那个开源库
以后用这个库就
dependencies {
implementation ‘pub.lmc.androidlib:permissionxr:1.0.0’
}