日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

Android運(yùn)行時權(quán)限終極方案(PermissionX)

瀏覽:247日期:2022-09-24 10:48:56

各位小伙伴們大家早上好,不知道你的《第三行代碼》已經(jīng)讀到哪里了?

有些朋友的閱讀速度真是令人印象深刻,我記得在《第三行代碼》剛剛發(fā)售一周不到的時間里,竟然就有人已經(jīng)讀到第9章了(因?yàn)楣娞柡笈_有人回復(fù)第9章里隱藏的關(guān)鍵字)。現(xiàn)在,《第三行代碼》已經(jīng)出版一個月有余了,相信已經(jīng)有不少朋友將全本書都看完了。

全書都看完的朋友一定知道,《第三行代碼》的最后一章是帶著大家一起開發(fā)了一個開源庫:PermissionX。這一章的主旨是為了讓你了解一個開源庫整體的開發(fā)與發(fā)布過程,為了更好地演示這個過程,我想到了去寫PermissionX這樣一個庫。

不過,書中PermissionX庫的整體功能還是比較簡單的,因?yàn)檫@一章的重點(diǎn)不在于如何將開源庫做得完善與強(qiáng)大,而是強(qiáng)調(diào)的一個開發(fā)與發(fā)布的過程。

但是后來,我覺得PermissionX確實(shí)可以做成一個真正用于簡化Android運(yùn)行時權(quán)限處理的庫,它所存在的意義應(yīng)該不僅限于書中的教學(xué)目的,而是可以真的應(yīng)用到實(shí)際的項(xiàng)目當(dāng)中,幫助大家解決處理運(yùn)行時權(quán)限的痛點(diǎn)。

所以,后期我又對PermissionX進(jìn)行了諸多功能拓展,現(xiàn)在已經(jīng)達(dá)到對外發(fā)布的標(biāo)準(zhǔn)了,那么今天正式向大家宣布:PermissionX已經(jīng)上線!

源碼庫地址是:https://github.com/guolindev/PermissionX

痛點(diǎn)在哪里?

沒有人愿意編寫處理Android運(yùn)行時權(quán)限的代碼,因?yàn)樗娴奶爆嵙恕?/p>

這是一項(xiàng)沒有什么技術(shù)含量,但是你又不得不去處理的工作,因?yàn)椴惶幚硭绦蚓蜁罎ⅰ5绻幚砥饋肀容^簡單也就算了,可事實(shí)上,Android提供給我們的運(yùn)行時權(quán)限API并不友好。

以一個撥打電話的功能為例,因?yàn)镃ALL_PHONE權(quán)限是危險權(quán)限,所以在我們除了要在AndroidManifest.xml中聲明權(quán)限之外,還要在執(zhí)行撥打電話操作之前進(jìn)行運(yùn)行時權(quán)限處理才行。

權(quán)限聲明如下:

<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.permissionx.app'> <uses-permission android:name='android.permission.CALL_PHONE' />...</manifest>

然后,編寫如下代碼來進(jìn)行運(yùn)行時權(quán)限處理:

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) makeCallBtn.setOnClickListener { if (ContextCompat.checkSelfPermission(this, Manifest.permission.CALL_PHONE) == PackageManager.PERMISSION_GRANTED) {call() } else {ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.CALL_PHONE), 1) } } } override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<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 CALL_PHONE permission', 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() } }}

這段代碼中真有正意義的功能邏輯就是call()方法中的內(nèi)容,可是如果直接調(diào)用call()方法是無法實(shí)現(xiàn)撥打電話功能的,因?yàn)槲覀冞€沒有申請CALL_PHONE權(quán)限。

那么整段代碼其他的部分就都是在處理CALL_PHONE權(quán)限申請。可以看到,這里需要先判斷用戶是否已授權(quán)我們撥打電話的權(quán)限,如果沒有的話則要進(jìn)行權(quán)限申請,然后還要在onRequestPermissionsResult()回調(diào)中處理權(quán)限申請的結(jié)果,最后才能去執(zhí)行撥打電話的操作。

你可能覺得,這也不算是很繁瑣呀,代碼量并不是很多。那是因?yàn)椋壳拔覀冞€只是處理了運(yùn)行時權(quán)限最簡單的場景,而實(shí)際的項(xiàng)目環(huán)境中有著更加復(fù)雜的場景在等著我們。

比如說,你的App可能并不只是單單申請一個權(quán)限,而是需要同時申請多個權(quán)限。雖然ActivityCompat.requestPermissions()方法允許一次性傳入多個權(quán)限名,但是你在onRequestPermissionsResult()回調(diào)中就需要判斷哪些權(quán)限被允許了,哪些權(quán)限被拒絕了,被拒絕的權(quán)限是否影響到應(yīng)用程序的核心功能,以及是否要再次申請權(quán)限。

而一旦牽扯到再次申請權(quán)限,就引出了一個更加復(fù)雜的問題。你申請的權(quán)限被用戶拒絕過了一次,那么再次申請將很有可能再次被拒絕。為此,Android提供了一個shouldShowRequestPermissionRationale()方法,用于判斷是否需要向用戶解釋申請這個權(quán)限的原因,一旦shouldShowRequestPermissionRationale()方法返回true,那么我們最好彈出一個對話框來向用戶闡明為什么我們是需要這個權(quán)限的,這樣可以增加用戶同意授權(quán)的幾率。

是不是已經(jīng)覺得很復(fù)雜了?不過還沒完,Android系統(tǒng)還提供了一個“拒絕,不要再詢問”的選項(xiàng),如下圖所示:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

只要用戶選擇了這個選項(xiàng),那么我們以后每次執(zhí)行權(quán)限申請的代碼都將會直接被拒絕。

可是如果我的某項(xiàng)功能就是必須要依賴這個權(quán)限才行呢?沒有辦法,你只能提示用戶去應(yīng)用程序設(shè)置當(dāng)中手動打開權(quán)限,程序方面已無法進(jìn)行操作。

可以看出,如果想要在項(xiàng)目中對運(yùn)行時權(quán)限做出非常全面的處理,是一件相當(dāng)復(fù)雜的事情。事實(shí)上,大部分的項(xiàng)目都沒有將權(quán)限申請這塊處理得十分恰當(dāng),這也是我編寫PermissionX的理由。

PermissionX的實(shí)現(xiàn)原理

在開始介紹PermissionX的具體用法之前,我們先來討論一下它的實(shí)現(xiàn)原理。

其實(shí)之前并不是沒有人嘗試過對運(yùn)行時權(quán)限處理進(jìn)行封裝,我之前在做直播公開課的時候也向大家演示過一種運(yùn)行時權(quán)限API的封裝過程。

但是,想要對運(yùn)行時權(quán)限的API進(jìn)行封裝并不是一件容易的事,因?yàn)檫@個操作是有特定的上下文依賴的,一般需要在Activity中接收onRequestPermissionsResult()方法的回調(diào)才行,所以不能簡單地將整個操作封裝到一個獨(dú)立的類中。

為此,也衍生出了一系列特殊的封裝方案,比如將運(yùn)行時權(quán)限的操作封裝到BaseActivity中,或者提供一個透明的Activity來處理運(yùn)行時權(quán)限等。

不過上述兩種方案都不夠輕量,因?yàn)楦淖傾ctivity的繼承結(jié)構(gòu)這可是大事情,而提供一個透明的Activty則需要在AndroidManifest.xml中進(jìn)行額外的聲明。

現(xiàn)在,業(yè)內(nèi)普遍比較認(rèn)可使用另外一種小技巧來進(jìn)行實(shí)現(xiàn)。是什么小技巧呢?回想一下,之前所有申請運(yùn)行時權(quán)限的操作都是在Activity中進(jìn)行的,事實(shí)上,Android在Fragment中也提供了一份相同的API,使得我們在Fragment中也能申請運(yùn)行時權(quán)限。

但不同的是,F(xiàn)ragment并不像Activity那樣必須有界面,我們完全可以向Activity中添加一個隱藏的Fragment,然后在這個隱藏的Fragment中對運(yùn)行時權(quán)限的API進(jìn)行封裝。這是一種非常輕量級的做法,不用擔(dān)心隱藏Fragment會對Activity的性能造成什么影響。

這就是PermissionX的實(shí)現(xiàn)原理了,書中其實(shí)也已經(jīng)介紹過了這部分內(nèi)容。但是,在其實(shí)現(xiàn)原理的基礎(chǔ)之上,后期我又增加了很多新功能,讓PermissionX變得更加強(qiáng)大和好用,下面我們就來學(xué)習(xí)一下PermissionX的具體用法。

基本用法

要使用PermissionX之前,首先需要將其引入到項(xiàng)目當(dāng)中,如下所示:

dependencies {...implementation ’com.permissionx.guolindev:permissionx:1.1.1’}

我在寫本篇文章時PermissionX的最新版本是1.1.1,想要查看它的當(dāng)前最新版本,請?jiān)L問PermissionX的主頁:https://github.com/guolindev/PermissionX

PermissionX的目的是為了讓運(yùn)行時權(quán)限處理盡可能的容易,因此怎么讓API變得簡單好用就是我優(yōu)先要考慮的問題。

比如同樣實(shí)現(xiàn)撥打電話的功能,使用PermissionX只需要這樣寫:

class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) makeCallBtn.setOnClickListener { PermissionX.init(this).permissions(Manifest.permission.CALL_PHONE).request { allGranted, grantedList, deniedList -> if (allGranted) { call() } else { Toast.makeText(this, '您拒絕了撥打電話權(quán)限', Toast.LENGTH_SHORT).show() }} } } ...}

是的,PermissionX的基本用法就這么簡單。首先調(diào)用init()方法來進(jìn)行初始化,并在初始化的時候傳入一個FragmentActivity參數(shù)。由于AppCompatActivity是FragmentActivity的子類,所以只要你的Activity是繼承自AppCompatActivity的,那么直接傳入this就可以了。

接下來調(diào)用permissions()方法傳入你要申請的權(quán)限名,這里傳入CALL_PHONE權(quán)限。你也可以在permissions()方法中傳入任意多個權(quán)限名,中間用逗號隔開即可。

最后調(diào)用request()方法來執(zhí)行權(quán)限申請,并在Lambda表達(dá)式中處理申請結(jié)果。可以看到,Lambda表達(dá)式中有3個參數(shù):allGranted表示是否所有申請的權(quán)限都已被授權(quán),grantedList用于記錄所有已被授權(quán)的權(quán)限,deniedList用于記錄所有被拒絕的權(quán)限。

因?yàn)槲覀冎簧暾埩艘粋€CALL_PHONE權(quán)限,因此這里直接判斷:如果allGranted為true,那么就調(diào)用call()方法,否則彈出一個Toast提示。

運(yùn)行結(jié)果如下:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

怎么樣?對比之前的寫法,是不是覺得運(yùn)行時權(quán)限處理沒那么繁瑣了?

核心用法

然而我們目前還只是處理了最普通的場景,剛才提到的,假如用戶拒絕了某個權(quán)限,在下次申請之前,我們最好彈出一個對話框來向用戶解釋申請這個權(quán)限的原因,這個又該怎么實(shí)現(xiàn)呢?

別擔(dān)心,PermissionX對這些情況進(jìn)行了充分的考慮。

onExplainRequestReason()方法可以用于監(jiān)聽那些被用戶拒絕,而又可以再次去申請的權(quán)限。從方法名上也可以看出來了,應(yīng)該在這個方法中解釋申請這些權(quán)限的原因。

而我們只需要將onExplainRequestReason()方法串接到request()方法之前即可,如下所示:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE) .onExplainRequestReason { deniedList -> } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, '所有申請的權(quán)限都已通過', Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, '您拒絕了如下權(quán)限:$deniedList', Toast.LENGTH_SHORT).show() } }

這種情況下,所有被用戶拒絕的權(quán)限會優(yōu)先進(jìn)入onExplainRequestReason()方法進(jìn)行處理,拒絕的權(quán)限都記錄在deniedList參數(shù)當(dāng)中。接下來,我們只需要在這個方法中調(diào)用showRequestReasonDialog()方法,即可彈出解釋權(quán)限申請?jiān)虻膶υ捒颍缦滤荆?/p>

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE) .onExplainRequestReason { deniedList -> showRequestReasonDialog(deniedList, '即將重新申請的權(quán)限是程序必須依賴的權(quán)限', '我已明白', '取消') } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, '所有申請的權(quán)限都已通過', Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, '您拒絕了如下權(quán)限:$deniedList', Toast.LENGTH_SHORT).show() } }

showRequestReasonDialog()方法接受4個參數(shù):第一個參數(shù)是要重新申請的權(quán)限列表,這里直接將deniedList參數(shù)傳入。第二個參數(shù)則是要向用戶解釋的原因,我只是隨便寫了一句話,這個參數(shù)描述的越詳細(xì)越好。第三個參數(shù)是對話框上確定按鈕的文字,點(diǎn)擊該按鈕后將會重新執(zhí)行權(quán)限申請操作。第四個參數(shù)是一個可選參數(shù),如果不傳的話相當(dāng)于用戶必須同意申請的這些權(quán)限,否則對話框無法關(guān)閉,而如果傳入的話,對話框上會有一個取消按鈕,點(diǎn)擊取消后不會重新進(jìn)行權(quán)限申請,而是會把當(dāng)前的申請結(jié)果回調(diào)到request()方法當(dāng)中。

另外始終要記得將所有申請的權(quán)限都在AndroidManifest.xml中進(jìn)行聲明:

<manifest xmlns:android='http://schemas.android.com/apk/res/android' package='com.permissionx.app'> <uses-permission android:name='android.permission.READ_CONTACTS' /> <uses-permission android:name='android.permission.CAMERA' /> <uses-permission android:name='android.permission.CALL_PHONE' />...</manifest>

重新運(yùn)行一下程序,效果如下圖所示:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

目前解釋權(quán)限申請?jiān)驅(qū)υ捒虻臉邮綍簳r還無法自定義,下個版本當(dāng)中,我會加入自定義對話框樣式的功能。

當(dāng)然,我們也可以指定要對哪些權(quán)限重新申請,比如上述申請的3個權(quán)限中,我認(rèn)為CAMERA權(quán)限是必不可少的,而其他兩個權(quán)限則可有可無,那么在重新申請的時候也可以只申請CAMERA權(quán)限:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.ACCESS_FINE_LOCATION) .onExplainRequestReason { deniedList -> val filteredList = deniedList.filter { it == Manifest.permission.CAMERA } showRequestReasonDialog(filteredList, '攝像機(jī)權(quán)限是程序必須依賴的權(quán)限', '我已明白', '取消') } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, '所有申請的權(quán)限都已通過', Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, '您拒絕了如下權(quán)限:$deniedList', Toast.LENGTH_SHORT).show() } }

這樣當(dāng)再次申請權(quán)限的時候就只會申請CAMERA權(quán)限,剩下的兩個權(quán)限最終會被傳入到request()方法的deniedList參數(shù)當(dāng)中。

解決了向用戶解釋權(quán)限申請?jiān)虻膯栴},接下來還有一個頭疼的問題要解決:如果用戶不理會我們的解釋,仍然執(zhí)意拒絕權(quán)限申請,并且還選擇了拒絕且不再詢問的選項(xiàng),這該怎么辦?通常這種情況下,程序?qū)用嬉呀?jīng)無法再次做出權(quán)限申請,唯一能做的就是提示用戶到應(yīng)用程序設(shè)置當(dāng)中手動打開權(quán)限。

那么PermissionX是如何處理這種情況的呢?我相信絕對會給你帶來驚喜。PermissionX中還提供了一個onForwardToSettings()方法,專門用于監(jiān)聽那些被用戶永久拒絕的權(quán)限。另外從方法名上就可以看出,我們可以在這里提醒用戶手動去應(yīng)用程序設(shè)置當(dāng)中打開權(quán)限。代碼如下所示:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE) .onExplainRequestReason { deniedList -> showRequestReasonDialog(deniedList, '即將重新申請的權(quán)限是程序必須依賴的權(quán)限', '我已明白', '取消') } .onForwardToSettings { deniedList -> showForwardToSettingsDialog(deniedList, '您需要去應(yīng)用程序設(shè)置當(dāng)中手動開啟權(quán)限', '我已明白', '取消') } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, '所有申請的權(quán)限都已通過', Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, '您拒絕了如下權(quán)限:$deniedList', Toast.LENGTH_SHORT).show() } }

可以看到,這里又串接了一個onForwardToSettings()方法,所有被用戶選擇了拒絕且不再詢問的權(quán)限都會進(jìn)行到這個方法中處理,拒絕的權(quán)限都記錄在deniedList參數(shù)當(dāng)中。

接下來,你并不需要自己彈出一個Toast或是對話框來提醒用戶手動去應(yīng)用程序設(shè)置當(dāng)中打開權(quán)限,而是直接調(diào)用showForwardToSettingsDialog()方法即可。類似地,showForwardToSettingsDialog()方法也接收4個參數(shù),每個參數(shù)的作用和剛才的showRequestReasonDialog()方法完全一致,我這里就不再重復(fù)解釋了。

showForwardToSettingsDialog()方法將會彈出一個對話框,當(dāng)用戶點(diǎn)擊對話框上的我已明白按鈕時,將會自動跳轉(zhuǎn)到當(dāng)前應(yīng)用程序的設(shè)置界面,從而不需要用戶自己慢慢進(jìn)入設(shè)置當(dāng)中尋找當(dāng)前應(yīng)用了。另外,當(dāng)用戶從設(shè)置中返回時,PermissionX將會自動重新請求相應(yīng)的權(quán)限,并將最終的授權(quán)結(jié)果回調(diào)到request()方法當(dāng)中。效果如下圖所示:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

同樣,下個版本當(dāng)中,我也會加入自定義這個對話框樣式的功能。

更多用法

PermissionX最主要的功能大概就是這些,不過我在使用一些App的時候發(fā)現(xiàn),有些App喜歡在第一次請求權(quán)限之前就先彈出一個對話框向用戶解釋自己需要哪些權(quán)限,然后才會進(jìn)行權(quán)限申請。這種做法是比較提倡的,因?yàn)橛脩敉馐跈?quán)的概率會更高。

那么PermissionX中要如何實(shí)現(xiàn)這樣的功能呢?

其實(shí)非常簡單,PermissionX還提供了一個explainReasonBeforeRequest()方法,只需要將它也串接到request()方法之前就可以了,代碼如下所示:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE).explainReasonBeforeRequest() .onExplainRequestReason { deniedList -> showRequestReasonDialog(deniedList, '即將申請的權(quán)限是程序必須依賴的權(quán)限', '我已明白') } .onForwardToSettings { deniedList -> showForwardToSettingsDialog(deniedList, '您需要去應(yīng)用程序設(shè)置當(dāng)中手動開啟權(quán)限', '我已明白') } .request { allGranted, grantedList, deniedList -> if (allGranted) { Toast.makeText(this, '所有申請的權(quán)限都已通過', Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, '您拒絕了如下權(quán)限:$deniedList', Toast.LENGTH_SHORT).show() } }

這樣,當(dāng)每次請求權(quán)限時,會優(yōu)先進(jìn)入onExplainRequestReason()方法,彈出解釋權(quán)限申請?jiān)虻膶υ捒颍脩酎c(diǎn)擊我已明白按鈕之后才會執(zhí)行權(quán)限申請。效果如下圖所示:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

不過,你在使用explainReasonBeforeRequest()方法時,其實(shí)還有一些關(guān)鍵的點(diǎn)需要注意。

第一,單獨(dú)使用explainReasonBeforeRequest()方法是無效的,必須配合onExplainRequestReason()方法一起使用才能起作用。這個很好理解,因?yàn)闆]有配置onExplainRequestReason()方法,我們怎么向用戶解釋權(quán)限申請?jiān)蚰兀?/p>

第二,在使用explainReasonBeforeRequest()方法時,如果onExplainRequestReason()方法中編寫了權(quán)限過濾的邏輯,最終的運(yùn)行結(jié)果可能和你期望的會不一致。這一點(diǎn)可能會稍微有點(diǎn)難理解,我用一個具體的示例來解釋一下。

觀察如下代碼:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE).explainReasonBeforeRequest() .onExplainRequestReason { deniedList -> val filteredList = deniedList.filter { it == Manifest.permission.CAMERA } showRequestReasonDialog(filteredList, '攝像機(jī)權(quán)限是程序必須依賴的權(quán)限', '我已明白') } ...

這里在onExplainRequestReason()方法中編寫了剛才用到的權(quán)限過濾邏輯,當(dāng)有多個權(quán)限被拒絕時,我們只重新申請CAMERA權(quán)限。

在沒有加入explainReasonBeforeRequest()方法時,一切都可以按照我們所預(yù)期的那樣正常運(yùn)行。但如果加上了explainReasonBeforeRequest()方法,在執(zhí)行權(quán)限請求之前會先進(jìn)入onExplainRequestReason()方法,而這里將除了CAMERA之外的其他權(quán)限都過濾掉了,因此實(shí)際上PermissionX只會請求CAMERA這一個權(quán)限,剩下的權(quán)限將完全不會嘗試去請求,而是直接作為被拒絕的權(quán)限回調(diào)到最終的request()方法當(dāng)中。

效果如下圖所示:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

針對于這種情況,PermissionX在onExplainRequestReason()方法中提供了一個額外的beforeRequest參數(shù),用于標(biāo)識當(dāng)前上下文是在權(quán)限請求之前還是之后,借助這個參數(shù)在onExplainRequestReason()方法中執(zhí)行不同的邏輯,即可很好地解決這個問題,示例代碼如下:

PermissionX.init(this) .permissions(Manifest.permission.CAMERA, Manifest.permission.READ_CONTACTS, Manifest.permission.CALL_PHONE).explainReasonBeforeRequest() .onExplainRequestReason { deniedList, beforeRequest -> if (beforeRequest) { showRequestReasonDialog(deniedList, '為了保證程序正常工作,請您同意以下權(quán)限申請', '我已明白') } else { val filteredList = deniedList.filter {it == Manifest.permission.CAMERA } showRequestReasonDialog(filteredList, '攝像機(jī)權(quán)限是程序必須依賴的權(quán)限', '我已明白') } } ...

可以看到,當(dāng)beforeRequest為true時,說明此時還未執(zhí)行權(quán)限申請,那么我們將完整的deniedList傳入showRequestReasonDialog()方法當(dāng)中。

而當(dāng)beforeRequest為false時,說明某些權(quán)限被用戶拒絕了,此時我們只重新申請CAMERA權(quán)限,因?yàn)樗潜夭豢缮俚模渌麢?quán)限則可有可無。

最終運(yùn)行效果如下:

Android運(yùn)行時權(quán)限終極方案(PermissionX)

Permission-Support

這個庫的名字叫PermissionX,因此不用多說,它肯定是與AndroidX兼容的。以防還有部分朋友不清楚AndroidX是什么的,這里有一篇我之前寫的科普文章 總是聽到有人說AndroidX,到底什么是AndroidX?

但是,我相信現(xiàn)在仍然存在很多項(xiàng)目沒有使用AndroidX,而是在繼續(xù)使用著之前的Android Support Library。為此,我又專門提供了一份面向Android Support Library的版本:Permission-Support。

在用法層面,兩個版本沒有任何區(qū)別,本文以上討論的所有內(nèi)容在Permission-Support上都適用。只是在引用庫的時候,如果你準(zhǔn)備使用Permission-Support,請使用以下依賴庫地址:

dependencies {...implementation ’com.permissionx.guolindev:permission-support:1.1.1’}

不過,Android Support Library注定將會在不久的將來被Google完全淘汰,因此Permission-Support我也不會維護(hù)太久的時間,只是暫時過渡一下。而PermissionX我是準(zhǔn)備長期維護(hù)下去的,并會持續(xù)增加更多好用的新功能。

后記

最后,一定也會有朋友想要詢問,Java語言的項(xiàng)目能不能使用PermissionX呢?

其實(shí)早在最開始的時候,我是打算將PermissionX設(shè)計(jì)成Kotlin和Java都可以通用的一個庫。但是寫著寫著發(fā)現(xiàn),如果想要兼容Java語言,需要放棄很多Kotlin的語法特性,這樣PermissionX用起來就不再是那么簡潔了,最終只好選擇了放棄Java語言的支持。

不過等PermissionX整體功能穩(wěn)定下來之后,我可能會專門再編寫一個Java版的PermissionX。語法層面肯定要比Kotlin版的復(fù)雜不少,但是一定比你自己去處理運(yùn)行時權(quán)限簡單得多。

新庫剛剛發(fā)布,可能還存在很多我自己沒能測出來的bug,也請大家?guī)兔Χ喽鄿y試,共同將這個庫變得更加完善。

再次貼上PermissionX的開源庫地址,歡迎大家star和fork。

https://github.com/guolindev/PermissionX

到此這篇關(guān)于Android運(yùn)行時權(quán)限終極方案(PermissionX)的文章就介紹到這了,更多相關(guān)Android 運(yùn)行時權(quán)限內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
久久精品天堂| 日韩和欧美一区二区| 麻豆成人综合网| 麻豆精品久久久| 欧美激情福利| 美女久久久精品| 欧美成人精品午夜一区二区| 日本成人在线不卡视频| 日韩不卡在线观看日韩不卡视频 | 亚洲欧洲一区二区天堂久久| 亚洲一级网站| 亚洲免费影院| 亚洲精品第一| 国产午夜久久av| 国产精品多人| 国产中文字幕一区二区三区| 久久不见久久见国语| 麻豆国产精品| 精品中文在线| 97在线精品| 久久九九精品| 亚洲中字黄色| 亚洲精品婷婷| 国产精品欧美日韩一区| 国产91在线播放精品| 99久久99视频只有精品| 伊人成人网在线看| 亚洲+小说+欧美+激情+另类| 国产精品久久乐| а√天堂中文在线资源8| 亚洲一级特黄| 日韩av电影一区| 国产一区三区在线播放| 久久在线免费| 蜜臀久久99精品久久久久久9| 日韩福利在线观看| 国产精品麻豆久久| 激情丁香综合| 久久精品xxxxx| 成人三级高清视频在线看| 久久国产小视频| 视频一区二区不卡| 国产福利一区二区精品秒拍 | 久热精品在线| 国产免费av国片精品草莓男男| 国产成人精品一区二区三区视频 | 久久免费精品| 欧美日韩国产综合网| 日韩二区三区四区| 免费一二一二在线视频| 三级欧美韩日大片在线看| 久久99精品久久久久久园产越南| 日韩不卡视频在线观看| 中文一区一区三区免费在线观 | 欧美午夜不卡影院在线观看完整版免费| 亚洲一区二区三区无吗| 国产精品一国产精品k频道56| 国产日韩电影| 亚洲1区在线观看| av免费不卡国产观看| 日韩制服丝袜先锋影音| 国产精品对白| 在线观看免费一区二区| 国产欧美久久一区二区三区| 久久五月天小说| 欧美一级二区| 偷拍欧美精品| 精品国产一级| 日韩一区欧美二区| 国产成人久久精品一区二区三区| 久久亚洲色图| 欧美国产偷国产精品三区| 亚洲人妖在线| 99成人超碰| 欧美激情一区| 亚洲毛片网站| 欧美精品一区二区三区精品| 国产精品调教视频| 亚洲欧美日韩视频二区| 成人在线黄色| 欧美永久精品| 玖玖精品视频| 蜜桃成人av| 成人污污视频| 国产精品主播在线观看| 亚洲一区导航| 久久精品国内一区二区三区水蜜桃| 国产欧美激情| 亚洲va久久| 国产精品毛片在线| 久久精品国产99久久| 久久中文精品| 国产亚洲欧美日韩在线观看一区二区| 国产亚洲毛片| 久久久夜精品| 国产成人精品999在线观看| 国产女人18毛片水真多18精品| 美女精品一区| 精品一区在线| sm捆绑调教国产免费网站在线观看| 欧美日韩 国产精品| 蜜臀久久99精品久久一区二区| 国产成人调教视频在线观看| 天堂av一区| 久久男人天堂| 亚洲黑丝一区二区| 国产白浆在线免费观看| 欧美片网站免费| 日韩福利视频导航| 亚洲精品麻豆| 蜜臀久久99精品久久久久宅男 | 99国产精品自拍| 久久中文字幕二区| 欧美天堂视频| 成年男女免费视频网站不卡| 九九99久久精品在免费线bt| 国产精品亚洲综合色区韩国| 国产图片一区| 国产精品久久久久久久久久妞妞| 日韩av不卡一区二区| 日韩国产成人精品| 欧美日韩一区二区三区四区在线观看| 日本国产一区| 久久激情五月婷婷| 国产精品一国产精品| 欧美国产三级| 欧美激情日韩| 久久精品网址| 成人精品高清在线视频| 国产日韩电影| 日韩精品午夜| 国产韩日影视精品| 亚洲激情另类| 在线精品福利| 青草国产精品久久久久久| 日韩成人一级| 美腿丝袜在线亚洲一区| 国精品产品一区| 亚洲电影有码| 一本色道精品久久一区二区三区| 快she精品国产999| 日韩**一区毛片| 国产欧美成人| 水蜜桃久久夜色精品一区| 久久久精品网| 视频一区二区不卡| 国产无遮挡裸体免费久久| 精品美女视频 | 免费一级欧美在线观看视频| 国产精品成人**免费视频| 国精品产品一区| 欧美日韩精品一区二区视频| 免费日韩一区二区| 欧美午夜网站| 在线看片福利| 在线成人直播| 日韩成人午夜精品| 国产精品99在线观看| 欧洲亚洲一区二区三区| 美女尤物久久精品| 国产精品一页| 久久九九精品| 亚洲影视一区二区三区| 欧美国产另类| 日韩在线看片| 日韩专区欧美专区| 你懂的国产精品| 欧美日韩中文字幕一区二区三区 | 国产日韩综合| 国产日韩高清一区二区三区在线| 国产精品久久久久久久免费观看 | 在线人成日本视频| 亚洲欧美日韩综合国产aⅴ| 国产精品中文字幕亚洲欧美| 免费高潮视频95在线观看网站| 香蕉久久久久久久av网站| 国产日韩一区二区三免费高清| 日韩欧美综合| 亚洲精品麻豆| 国产理论在线| 亚洲涩涩av| 高清一区二区| 中文字幕日韩亚洲| 黑森林国产精品av| 中文字幕一区二区av| 成人片免费看| 日本中文字幕视频一区| 欧美精品资源| 69堂精品视频在线播放| 91精品精品| 国产欧美日韩在线观看视频| 亚洲一级特黄| 久草精品视频| 亚欧洲精品视频在线观看| 日韩欧美三级| 欧美精品国产白浆久久久久| 午夜欧美在线| 久久99精品久久久野外观看| 亚洲欧美日韩视频二区| 亚洲美女久久精品|