首先我們先科普一下它的技術(shù)背景:
從 Android 6.0(API 級別 23)開始,出于對用戶安全性能的考慮,將權(quán)限這部分分成 了兩類:一類是Install權(quán)限,稱之為安裝時權(quán)限,另一類是Runtime權(quán)限,稱之為運(yùn)行時權(quán)限。
安裝時權(quán)限,就是在安裝app時賦予該app的權(quán)限。比如:Normal和Signature級別的權(quán)限都是安裝時權(quán)限。賦予app Normal和Signature權(quán)限時,不會給用戶提示界面,系統(tǒng)自動決定權(quán)限的賦予。
這里需要注意一點(diǎn),對于Signature權(quán)限,如果使用權(quán)限的app與聲明權(quán)限的app的簽名不一致,則系統(tǒng)拒絕賦予該Signature權(quán)限。這句話怎么理解呢?
聲明權(quán)限是指在AndroidManifest.xml中使用<permission>標(biāo)簽的權(quán)限
使用權(quán)限是指在AndroidManifest.xml中使用<uses-permission>標(biāo)簽的權(quán)限。
舉個場景例子:
app A中聲明了權(quán)限PermissionA,app B中想要使用權(quán)限PermissionA。
那么app B在清單文件中配置了PermissionA。如果這個PermissionA的protectionLevel(風(fēng)險級別)屬性設(shè)置為Normal,那么app B完全可以獲得PermissionA使用,但如果PermissionA的protectionLevel屬性設(shè)置為Signature,因?yàn)閍pp A 與app B簽名文件不一樣,那么app B不會獲得PermissionA的使用
還不怎么理解的同學(xué)給你們兩個網(wǎng)頁,結(jié)合著看,受益挺多
Android聲明和使用權(quán)限 、Android 權(quán)限的一些細(xì)節(jié)
- 運(yùn)行時權(quán)限,是指在app運(yùn)行過程中,賦予app的權(quán)限。這個過程中,會顯示明顯的權(quán)限授予界面,讓用戶決定是否授予權(quán)限。比如:Dangerous級別的權(quán)限,如果運(yùn)行在Android 6.0及以上的手機(jī)系統(tǒng)中,app在運(yùn)行時必須主動申請這些Dangerous權(quán)限,否則app就不會獲取到dangerous權(quán)限。
注意一點(diǎn),這種權(quán)限有點(diǎn)特殊,和上面的分類不同,它的分類具體來說和app有關(guān)系:如果app的targetSdkVersion是22及以下,Dangerous權(quán)限歸到安裝時權(quán)限,如果app的targetSdkVersion是23及以上Dangerous權(quán)限歸到運(yùn)行時權(quán)限
說到這里了,總結(jié)一下共說了幾種權(quán)限:
- Normal: 低風(fēng)險的,不會對系統(tǒng)、用戶或其他應(yīng)用程序造成危害,這類權(quán)限不涉及個人隱私,不需要用戶進(jìn)行授權(quán),比如手機(jī)震動,訪問網(wǎng)絡(luò)。
- Dangerous 高風(fēng)險的,系統(tǒng)將可能要求用戶輸入相關(guān)信息,才會授予此權(quán)限,這類權(quán)限涉及個人隱私,需要用戶進(jìn)行授權(quán),比如讀取SD卡,訪問通訊錄等。
- Signature 只有當(dāng)應(yīng)用程序所用數(shù)字簽名與聲明此權(quán)限的應(yīng)用程序所用數(shù)字簽名相同時,才能將權(quán)限授給它。
- SignatureOrSystem 將權(quán)限授給具有相同數(shù)字簽名的應(yīng)用程序或Android包類,這一級別適用于非常特殊的情況,比如多個供應(yīng)商需要通過系統(tǒng)影像共享功能時(簡單了解即可,幾乎用不到)
RxPermissions的好處
- 開發(fā)者不用擔(dān)心Android運(yùn)行環(huán)境的版本,如果系統(tǒng)是Android 6.0之前的版本,RxPermissions返回的結(jié)果是true,即app請求的每個權(quán)限都被允許
RxPermissions內(nèi)部已經(jīng)對Android版本進(jìn)行了判斷:
boolean isMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public boolean isGranted(String permission) {
// 如果是Android 6.0 (Api 23)之前,則權(quán)限被允許使用。
return !isMarshmallow() || mRxPermissionsFragment.isGranted(permission);
}
- 將權(quán)限申請的代碼和請求結(jié)果的代碼放在一起管理,避免了代碼的分散。
權(quán)限的申請?jiān)瓉碓趓equestPermissions()方法中,請求的結(jié)果放在onRequestPermissionsResult()方法中。
而RxPermissions通過request(需要的權(quán)限)與subscribe(Action)統(tǒng)一進(jìn)行管理操作
- RxPermissions具備Rx(RxJava)的特性,例如可以使用鏈?zhǔn)讲僮?,可以?zhí)行filter操作、transform操作、lambda表達(dá)式等等。
RxPermissions獲取運(yùn)行時權(quán)限的步驟
- 準(zhǔn)備工作
⑴ 安卓手機(jī)必須是Android 6.0 (API level >= 23)以上,因?yàn)?.0以下安卓手機(jī)沒有運(yùn)行時權(quán)限這個概念
⑵ 使用這個庫的時候,項(xiàng)目文件build.gradle中的targetSdkVersion >= 23
⑶ 使用這個庫的時候,項(xiàng)目文件build.gradle中的minSdkVersion >= 11 - 添加依賴
因?yàn)橐玫絉xPermissions,所以先加入依賴,而RxPermissions又屬于RX系列,所以也要加入對rxjava的依賴
compile 'com.tbruyelle.rxpermissions:rxpermissions:0.7.0@aar'
compile 'io.reactivex:rxjava:1.1.3'
- 添加權(quán)限
在AndroidManifest.xml加入項(xiàng)目所需的運(yùn)行時權(quán)限,例如:
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECEIVE_MMS" />
<uses-permission android:name="android.permission.READ_CALL_LOG" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
- Activity代碼操作
細(xì)分的化可以分成三種操作:
①.請求單個權(quán)限
//場景模擬是點(diǎn)擊button,用RxPermissions申請讀取日程提醒權(quán)限
mButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
RxPermissions.getInstance(TestActivity.this)
.request(Manifest.permission.READ_CALENDAR)//這里填寫所需要的權(quán)限
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean) {//true表示獲取權(quán)限成功(如果手機(jī)為android6.0以下的話這里總是返回true,不會彈框權(quán)限提示)
Log.i("permissions", Manifest.permission.READ_CALENDAR + ":獲取成功");
} else {
Log.i("permissions", Manifest.permission.READ_CALENDAR + ":獲取失敗");
}
}
});
}
});
效果圖如下:


②.一次申請多個權(quán)限
RxPermissions.getInstance(TestActivity.this)
.request(Manifest.permission.RECEIVE_MMS, Manifest.permission.READ_CALL_LOG)//多個權(quán)限用","隔開
.subscribe(new Action1<Boolean>() {
@Override
public void call(Boolean aBoolean) {
if (aBoolean) {
//當(dāng)所有權(quán)限都允許之后,返回true
Log.i("permissions", "btn_more_sametime:" + aBoolean);
} else {
//只要有一個權(quán)限禁止,返回false,下一次申請只申請沒通過申請的權(quán)限
Log.i("permissions", "btn_more_sametime:" + aBoolean);
}
}
});
效果圖如下:



③.分別申請多個權(quán)限
//分別申請多個權(quán)限時,使用requestEach
RxPermissions.getInstance(TestActivity.this)
.requestEach(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
.subscribe(new Action1<Permission>() {
@Override
public void call(Permission permission) {
if (permission.name.equals(Manifest.permission.ACCESS_FINE_LOCATION)) {
//當(dāng)ACCESS_FINE_LOCATION權(quán)限獲取成功時,permission.granted=true
Log.i("permissions", Manifest.permission.ACCESS_FINE_LOCATION + ":" + permission.granted);
}
if (permission.name.equals(Manifest.permission.RECORD_AUDIO)) {
//當(dāng)RECORD_AUDIO 權(quán)限獲取成功時,permission.granted=true
Log.i("permissions", Manifest.permission.RECORD_AUDIO + ":" + permission.granted);
}
if (permission.name.equals(Manifest.permission.CAMERA)) {
//當(dāng)CAMERA權(quán)限獲取成功時,permission.granted=true
Log.i("permissions", Manifest.permission.CAMERA + ":" + permission.granted);
}
}
});
效果圖如下:




注意
⑴由于在請求權(quán)限的過程中app有可能會被重啟,所以權(quán)限請求必須放在初始化的階段,比如在Activity.onCreate/onResume, 或者
View.onFinishInflate方法中。如果不這樣處理,那么如果app在請求過程中重啟的話,權(quán)限請求結(jié)果將不會發(fā)送給訂閱者即subscriber。
⑵上圖可知多次權(quán)限申請的兩種方式效果圖完全一樣,都是一項(xiàng)項(xiàng)彈出,一項(xiàng)項(xiàng)讓用戶選擇。它倆的區(qū)別“同時”和“分別”是體現(xiàn)在代碼結(jié)果的獲取上的.“同時”是等用戶把每項(xiàng)權(quán)限彈框都選擇完后執(zhí)行結(jié)果回調(diào),所有的權(quán)限統(tǒng)一處理,只要有一項(xiàng)不允許,就走false,“分別”也是等用戶把每項(xiàng)權(quán)限彈框都選擇完后執(zhí)行結(jié)果回調(diào),但所有的權(quán)限不統(tǒng)一處理,每項(xiàng)權(quán)限都有一個結(jié)果回調(diào)處理方法。這塊不要弄混
⑶權(quán)限的彈框樣式不同的手機(jī)不同的效果圖,這些Dialog是各個手機(jī)廠商定制的,不能由開發(fā)者定制。
關(guān)鍵部分就這些了,挺簡單的。動態(tài)權(quán)限授權(quán)雖然給程序員帶來了一些麻煩, 但是對用戶的安全性來講還是很有必要的, 我們也應(yīng)該歡迎, 畢竟每個程序員都是半個產(chǎn)品經(jīng)理。
在開發(fā)過程中遇到一個問題,就是在vivo(垃圾! 胡改八改?。9 (6.0.1 API 23)手機(jī)上運(yùn)行程序,測試出的結(jié)果是6.0以下手機(jī)的邏輯,現(xiàn)在還在研究中,有知道的大神麻煩告知一下。