帶你封裝自己的『許可權管理』框架
前言
本文已經收錄到我的 Github 個人部落格,歡迎大佬們光臨寒舍:
我的 Github 部落格
本篇文章需要已經具備的知識:
Git
與Github
的基本使用Kotlin
語法基礎Android
開發基礎
學習清單:
如何封裝自己的許可權框架 將開源庫釋出到 JitPack
倉庫的一整套流程
一.為什麼要封裝這套框架
我們在日常開發中,經常需要用到申請執行時許可權的知識,於是,經常就寫了下面的一大串程式碼
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
...
//申請 CALL_PHONE 許可權
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.CALL_PHONE
) != PackageManager.PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), 1)
} else {
call()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
1 -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
call()
} else {
Toast.makeText(this, "You denied the permission", Toast.LENGTH_SHORT).show()
}
}
}
}
麻鴨,頭疼,這麼多程式碼,不僅寫著難受,看著更是頭疼
這時候,如果這個世界簡單點,純粹點,就好了
XPermission.request(
this,
Manifest.permission.CALL_PHONE
) { allGranted, deniedList ->
if (allGranted) {
call()
} else {
Toast.makeText(this, "You denied $deniedList", Toast.LENGTH_SHORT).show()
}
}
是不是感覺世界又友好了很多呢?這段程式碼比之前的程式碼量少了很多不說,邏輯更是清晰了很多鴨!
很顯然,上面用到了自己封裝的框架,有可能你會一臉不屑:『這算啥?Github
上一堆許可權申請框架,他們寫的這個簡潔又漂亮,功能又多又全,超帥的』
我想說:『是的,你說的對,雖然 Github
上有這麼多,跑得又快又棒的輪子,但是,別人做的菜總歸沒有自己的香鴨!我們可以通過自己封裝一個簡單的許可權申請框架開始,學習釋出開源庫到 Jitpack
/ Jcenter
的一整套流程,從而激發自己的學習興趣,以後自己也多多造輪子(xia zhe teng)!成為 Android
界的輪子哥』
先為大佬送上筆者已經封裝好的輪子:https://github.com/LoveLifeEveryday/XPermissions
二.入坑之路
2.1 建立 Android
專案
新建一個空的 Android
專案
2.2 建立 Github
專案
然後,把該專案
clone
到一個上面已經建立的Android
專案的位置將克隆下來的所有檔案全部複製到上一層目錄(注意:複製的時候不要忘記複製
.git
檔案)將克隆的
XPermission
目錄刪除執行一系列的
git add .
git commit -m "First commit"
git push origin master
操作
2.3 實現 XPermission
對著最頂層的 XPermission
,新建一個module
,選擇Android Library
看到 library
就行,如下
然後,我們思考下,執行時許可權的實現思路,有以下三種:
將執行時許可權的操作封裝到 BaseActivity
中提供一個透明的 Activity
來處理提供一個隱藏的 Fragment
來處理
本文,將根據最後一個思路進行實現
2.3.1 建立 InvisibleFragment
//給 (Boolean, List<String>) -> Unit 指定一個別名
typealias PermissionCallback = (Boolean, List<String>) -> Unit
class InvisibleFragment : Fragment() {
//定義一個 callback 作為執行時許可權申請結果的回撥通知方式
private var callback: PermissionCallback? = null
//定義申請許可權的方法,vararg 表示可變長度的 permissions 引數列表
fun requestNow(cb: PermissionCallback, vararg permission: String) {
callback = cb
requestPermissions(permission, 1)
}
/**
* 請求返回結果
* @param requestCode Int 請求碼
* @param permissions Array<String> 許可權
* @param grantResults IntArray 請求結果
*/
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
if (requestCode == 1) {
// deniedList 用來記錄被使用者拒絕的許可權
val deniedList = ArrayList<String>()
for ((index, result) in grantResults.withIndex()) {
if (result != PackageManager.PERMISSION_GRANTED) {
deniedList.add(permissions[index])
}
}
// allGranted 用來標識是否所有申請的許可權都已經授權
val allGranted = deniedList.isEmpty()
//對申請許可權的結果進行回撥
callback?.let { it(allGranted, deniedList) }
}
}
}
首先,我們定義一個 callback
作為執行時許可權申請結果的回撥通知方式然後,定義一個 requestNow
方法最後重寫 onRequestPermissionsResult
方法
2.3.2 建立 XPermission
object XPermission {
private const val TAG = "InvisibleFragment"
fun request(
activity: FragmentActivity,
vararg permission: 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
}
//這裡在 permission 前面加個星號的意思是:將陣列轉化為可變長度引數傳遞過去
fragment.requestNow(callback, *permission)
}
}
相信程式碼大家都看得懂,所以筆者就不寫很多註釋了(其實是因為懶..)
2.4 測試
在
app\build.gradle
中引入library
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
//新增這行就行
implementation project(':library')
}
然後進行你喜歡的許可權申請
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
makeCallBtn.setOnClickListener {
XPermission.request(this, Manifest.permission.CALL_PHONE) { allGranted, deniedList ->
if (allGranted) {
call()
} else {
Toast.makeText(this, "You Denied $deniedList", Toast.LENGTH_SHORT).show()
}
}
}
}
private fun call() {
val intent = Intent(Intent.ACTION_CALL)
intent.data = Uri.parse("tel:10086")
startActivity(intent)
}
}
如果可以的話,恭喜你,你已經成功一大步了
2.5 釋出到 JitPack
2.5.1 JitPack
簡介
JitPack 是一個網站,它允許你把 git
託管的 java
或 android
專案(貌似目前僅支援github
和碼雲),輕鬆釋出到 jitpack
的 maven
倉庫上,它所有內容都通過內容分發網路(CDN
)使用加密 https
連接獲取
2.5.2 為什麼用 JitPack
優點:打包比較簡單,省時間,背靠 Github
這座大山
缺點:每次匯入庫的時候,都要先在根的 build.gradle
檔案中新增 maven
2.5.3 步驟
在根的 build.gradle
中新增maven
外掛
點選檢視最新版本
buildscript {
ext.kotlin_version = '1.3.71'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
//新增 maven 外掛
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
在 library
目錄的build.gradle
下apply
外掛和新增group
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
//新增下面兩行
apply plugin: 'com.github.dcendents.android-maven'
//這裡 LoveLifeEveryday 改為你的 github 賬號名,我的是:LoveLifeEveryday
group='com.github.LoveLifeEveryday'
android {
...
}
同步一下
在命令列中輸入 gradlew install
,從而構建你的library
到你的本地maven
倉庫
等待
BUILD SUCCESSFUL,
若BUILD FAIL
,說明構建失敗,這時候你就要按照失敗提示去排錯,排錯完後在執行一遍gradlew install
命令,直到出現BUILD SUCCESS
把程式碼提交到本地 git
倉庫
git add .
和git commit -m “XX”
在本地 git
倉庫打tag
git tag -a 1.0.0 -m "第一版"
git push origin 1.0.0
開啟你的 libary
的github
介面,點選release
,如下:
點選 Draft a new release
,新建一個release
,如下:
然後填資訊,如下:
填好資訊後,點選 publich release
,如下:
用 GitHub
賬號登陸、註冊jitpack
登陸後,在位址列中輸入你的 library
的github
專案地址,然後點選Look Up
,如下:
然後點選 Get it
,它會滾到下面去,你要滾回上面去,先等一會,等jitpack
那裡構建完,會出現一個綠色的log
,則構建成功,如下:
然後你就可以愉快的在專案中按照它的提示引用你的開源庫
點選那個 jitpack
,把它的連結複製到你的Readme
中去,如下:
2.6 嘗試使用你的框架
當然是在 app\build.gradle
中
//引用自己的開源庫
implementation 'com.github.LoveLifeEveryday:XPermissions:1.0.0'
然後嘗試使用吧
2.7 美化你的專案
一個優秀的開源專案,readme
一定不會差