PermissionX

一,预备知识

SDK——开源库

  1. 没有界面
  2. 是逻辑功能
  3. 做好的工具库SDK是被其他项目引用
  4. 面向其他开发者做的
  5. 稳定工作,提供简单的接口给其他开发者

PermissionX

简化获取运行时权限的资源库

二,怎么写自己的SDK?

1. 新建一个 Android 项目,名字是你想给这个开源库的名字

2. 加一个模块

之前我们都在app下面写,写出来的都是app

现在我们自己开一个library,写开源库

image-20221125183151093

image-20221125183309358

3. 库模块和app模块的区别

image-20221125183558828

4. 实现设想

运行时权限API封装一般要特定上下文依赖,且还要回调处理

市面的解决办法:

  • BaseActivity
  • 透明的Activity
  • Fragment中申请运行时权限

why?

优势:不像Activity那样要界面,可以搞个隐藏的Fragment然后在他里面去对运行时权限的API进行封装。且对本来的Activity性能没有影响。

5. 代码实现

InvisibleFragment-隐形Fragment

image-20221125190531640

第一版:

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 : 给任意类型指定一个别名(更加简介了)
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"
//注解:FragmentActivity 是 AppCompatActivity 的父类(不信 Ctrl+H)
fun request(activity: FragmentActivity, vararg permissions: String, callback:
PermissionCallback) {
val fragmentManager = activity.supportFragmentManager//获取FragmentManager的实例
val existedFragment = fragmentManager.findFragmentByTag(TAG)
val fragment = if (existedFragment != null) {
existedFragment as InvisibleFragment
} else {
val invisibleFragment = InvisibleFragment()
//把invisibleFragment加进Activity
fragmentManager.beginTransaction().add(invisibleFragment, TAG).commitNow()//这里不能换成commit(否则下面这个作为返回值返回的时候是没有那个i——Fragment的 // )
invisibleFragment
}
fragment.requestNow(callback, *permissions)//*:表示将一个数组转换成可变长度参数传递过去
}
}

三,测试

app模块中引入library模块

image-20221126162625003

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()
}
}
}

四,发布开源库

两个棘手问题:

  1. 第一行代码中的那个JCenter用不了,现在我们试一下MavenCentral

  2. 还有Gradle也变了,那个AndroidStudio中Project下的build.gradle根本就没有没有buildscript和allprojects了(移到了另外一个地方)

    2022年冬天的:

    build.gradleimage-20221126191331879

    在这里image-20221126191402261

准备域名

我的:lmc.pub

创建工单

  1. 注册一下这个sonatype

    账号邮箱,密码要有大写。

  2. image-20221126193038946

  3. image-20221126194627496

    这里就1按这个来,23看下面这张

  4. image-20221126195545268

然后马上就会发一条邮件到你邮箱,点进去

image-20221126195939437

image-20221126195952499

等下又来一个:image-20221126200605520

教你去给域名加一条TXT解析,内容给你了就是工单编号

登录域名管理的网站(我的是阿里云,那这个举例子)

image-20221126201618462

控制台-》域名

image-20221126201652919

解析image-20221126201731296

image-20221126202306113

image-20221126205419905

然后我们就可以向 s01.oss.sonatype.org 这个地址发布库

MavenCentral还要求,所有发布的库都必须使用GPG来进行签名才行

下载 GnuPG

我是win https://www.gpg4win.org/download.html

win记得只能下这个(你要是去了官网,这个下载地址在老下面,很容易下了前面的原始的。原始后果就是后面那个代码跑不起来)

然后找个文件夹安装好(我的在D盘)

image-20221126211042610

密钥创建

gpg --full-generate-key

image-20221126211600799

然后会跳出来下面这个,设一个密码

image-20221126211244258

然后

image-20221126211701568

第二行后8位记下来

E8B132DC

上传公钥到GPC服务器

gpg --keyserver keyserver.ubuntu.com --send-keys 你的后8位数

gpg --keyserver keyserver.ubuntu.com --recv-keys 你的后8位数

image-20221126212253389

导出私钥

gpg --export-secret-keys -o 你想保存的地址+secring.gpg

image-20221126212759209

gradle-maven-publish-plugin这样一个第三方开源插件

image-20221126213151138

项目根目录下的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

其他的照着写写

image-20221126215453897

image-20221126215949736

在Android Studio右侧工具栏的Gradle页签当中找到publish这个任务(找不到正常上网搜,我遇到且解决了。写了解决方案在CSDN)

image-20221126222014109

image-20221126225024193

然后我们的sonatype主页就给你发消息说在同步了

第一个网址几十分钟就好了 https://repo1.maven.org/maven2/

image-20221126225154656

第二个要等一会

https://search.maven.org/

然后在这里才能搜到你的那个开源库

image-20221126225222374

以后用这个库就

dependencies {
implementation ‘pub.lmc.androidlib:permissionxr:1.0.0’
}