使用RxPermissions(基於RxJava2)
使用RxPermissions(基於RxJava2)
0. 背景
Android 6.0 (API level 23)中。將權限分成了兩類。一類是Install權限(稱之為安裝時權限)。還有一類是Runtime權限(稱之為執行時權限)。
Install權限是什麽?
Install權限:安裝時權限,顧名思義,是在安裝app時。就賦予該app的權限,即安裝後馬上獲取到的權限。normal和signature級別的權限都是安裝時權限。賦予app normal和signature權限時,不會給用戶提示界面,系統自己主動決定權限的賦予。對於signature權限,假設使用權限的app與聲明權限的app的簽名不一致,則系統拒絕賦予該signature權限。Runtime權限是什麽?
Runtime權限:執行時權限。是指在app執行過程中。賦予app的權限。這個過程中,會顯示明顯的權限授予界面,讓用戶決定是否授予權限。假設app的targetSdkVersion
是22(Lollipop MR1)及下面,dangerous權限是安裝時權限,否則dangerous權限是執行時權限。
假設一個app的targetSdkVersion
是23(或者23以上)。那麽該app所申請的全部dangerous權限都是執行時權限。假設執行在Android 6.0的環境中,該app在執行時必須主動申請這些dangerous權限(調用requestPermissions()
很多其它關於權限的說明,請參考:『Android 權限的一些細節』
1. RxPermissions的優點
RxPermissions是幫助開發人員簡化requestPermissions()
相關的處理。
- (1) 開發人員不用操心Android執行環境的版本號。假設系統是Android 6.0之前的版本號,RxPermissions返回的結果是,app請求的每一個權限都被同意(granted)。
RxPermissions內部已經對Android版本號進行了推斷:
boolean isMarshmallow() {
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M;
}
public boolean isGranted(String permission) {
// 假設是Android 6.0 (Api 23)之前,則權限被同意使用。
return !isMarshmallow() || mRxPermissionsFragment.isGranted(permission);
}
(2) 將權限申請的代碼(
requestPermissions()
)和請求結果的代碼(onRequestPermissionsResult()
)放在一起管理,避免了代碼的分散。(3) RxPermissions具備Rx(RxJava)的特性,比如能夠使用鏈式操作,能夠執行filter操作,transform操作。等等。
2. RxPermissions的版本號
RxPermissions是基於RxJava的,RxJava如今有2個大版本號。一個RxJava 1.x(通常說RxJava),還有一個是RxJava2。
所以RxPermissions有2個版本號,分別支持RxJava和RxJava2。
RxPermissions的源代碼在https://github.com/tbruyelle/RxPermissions。
當中master
分支是支持RxJava 1.x的版本號,包名為com.tbruyelle.rxpermissions
。2.x
分支是支持RxJava2的版本號。包名為com.tbruyelle.rxpermissions2
。
默認看到的是master分支,所以看到的代碼是支持RxJava 1.x的RxPermissions。
分支的選擇(例如以下圖):
點擊『Branch: master』之後,能夠看到眼下有3個分支:2.x
,fix46
,和master
。
查看支持RxJava2的RxPermissions,將分支切換到2.x,例如以下:
3. RxPermissions代碼下載
下載包名為com.tbruyelle.rxpermissions
的代碼(支持RxJava1.x):
git clone https://github.com/tbruyelle/RxPermissions
下載包名為com.tbruyelle.rxpermissions2
的代碼(支持RxJava2):
git clone https://github.com/tbruyelle/RxPermissions RxPermissions2 -b 2.x
4. RxPermissions使用的註意事項
參考 https://github.com/tbruyelle/RxPermissions 中的README。
(1)
minSdkVersion
必須 >= 11。(2) 使用RxPermissions申請權限,必須在
Activity.onCreate()
或者View.onFinishInflate()
中處理。不能在
onResume()
中處理。由於onResume()在App的生命周期中可能執行的非常頻繁。假設在請求權限的時候。App又一次啟動了(比如屏幕旋轉導致的App關閉再又一次創建)。那麽用戶的選擇(同意 或者 拒絕)將無法發給App。 很多其它討論,請參考:https://github.com/tbruyelle/RxPermissions/issues/69
5. RxPermissions使用
基於RxJava2,使用包名為com.tbruyelle.rxpermissions2
的RxPermissions。
5.1 App module的build.gradle
dependencies {
...
compile ‘io.reactivex.rxjava2:rxandroid:2.0.1‘
compile ‘io.reactivex.rxjava2:rxjava:2.0.5‘
compile ‘com.tbruyelle.rxpermissions2:rxpermissions:0.9.3@aar‘
...
}
5.2 AndroidManifest.xml中使用權限
<!-- protection level is dangerous, need request runtime permission -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.CALL_PHONE"/>
5.3 在Activity的onCreate()中申請權限
package com.galian.rxjavatest;
import android.Manifest;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import com.tbruyelle.rxpermissions2.Permission;
import com.tbruyelle.rxpermissions2.RxPermissions;
import io.reactivex.functions.Consumer;
public class RxPermissionTestActivity extends AppCompatActivity {
private static final String TAG = "RxPermissionTest";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_rx_permission_test);
requestPermissions();
}
private void requestPermissions() {
RxPermissions rxPermission = new RxPermissions(RxPermissionTestActivity.this);
rxPermission
.requestEach(Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.READ_CALENDAR,
Manifest.permission.READ_CALL_LOG,
Manifest.permission.READ_CONTACTS,
Manifest.permission.READ_PHONE_STATE,
Manifest.permission.READ_SMS,
Manifest.permission.RECORD_AUDIO,
Manifest.permission.CAMERA,
Manifest.permission.CALL_PHONE,
Manifest.permission.SEND_SMS)
.subscribe(new Consumer<Permission>() {
@Override
public void accept(Permission permission) throws Exception {
if (permission.granted) {
// 用戶已經同意該權限
Log.d(TAG, permission.name + " is granted.");
} else if (permission.shouldShowRequestPermissionRationale) {
// 用戶拒絕了該權限,沒有選中『不再詢問』(Never ask again),那麽下次再次啟動時。還會提示請求權限的對話框
Log.d(TAG, permission.name + " is denied. More info should be provided.");
} else {
// 用戶拒絕了該權限,而且選中『不再詢問』
Log.d(TAG, permission.name + " is denied.");
}
}
});
}
}
5.4 界面顯示及log
假設點擊『拒絕』。不選中『不再詢問』,log為:
D/RxPermissionTest: android.permission.ACCESS_FINE_LOCATION is denied. More info should be provided.
假設點擊『拒絕』,選中了『不再詢問』。則log為:
D/RxPermissionTest: android.permission.ACCESS_FINE_LOCATION is denied.
假設點擊『同意』,log為:
D/RxPermissionTest: android.permission.ACCESS_FINE_LOCATION is granted.
6. 參考
- (1) https://github.com/tbruyelle/RxPermissions
- (2)https://developer.android.com/guide/topics/permissions/requesting.html
- (3) https://developer.android.com/training/permissions/requesting.html
使用RxPermissions(基於RxJava2)