動的権限を申請する必要がある理由
6.0より前のAndroidアプリケーションの権限はマニフェストで構成されていましたが、バージョン6.0では、ユーザーのプライバシーを保護するために新しい権限モードが導入されました。この権限モードは2つのタイプに分けられます。
-
機密性の低いアクセス許可:このアクセス許可は動的に適用する必要はなく、マニフェストで構成する必要があるだけです。これは、6.0より前のアクセス許可の要求と同じです。
-
機密性の高いアクセス許可:ユーザーが機密性の高いアクセス許可を使用する必要がある場合、システムに動的に適用する必要があります。そのようなアクセス許可はグループ化されます。アクセス許可のグループがいずれかに適用される限り、同じグループの他のアクセス許可も適用されます。 。
特別許可グループ(Googleドキュメントから)
許可グループ 権限 CALENDAR
READ_CALENDAR``WRITE_CALENDAR
CALL_LOG
READ_CALL_LOG
WRITE_CALL_LOG``PROCESS_OUTGOING_CALLS
CAMERA
CAMERA
CONTACTS
READ_CONTACTS``WRITE_CONTACTS``GET_ACCOUNTS
LOCATION
ACCESS_FINE_LOCATION``ACCESS_COARSE_LOCATION
MICROPHONE
RECORD_AUDIO
PHONE
READ_PHONE_STATE``READ_PHONE_NUMBERS``CALL_PHONE``ANSWER_PHONE_CALLS``ADD_VOICEMAIL``USE_SIP
SENSORS
BODY_SENSORS
SMS
SEND_SMS``RECEIVE_SMS``READ_SMS``RECEIVE_WAP_PUSH``RECEIVE_MMS
STORAGE
READ_EXTERNAL_STORAGE``WRITE_EXTERNAL_STORAGE
ネイティブアプリケーションの許可方法
-
システムに権限があるかどうかを確認し、ない場合は
requestPermissions
メソッドを呼び出しますif (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, Manifest.permission.CAMERA,10) }
-
onRequestPermissionsResultをオーバーライドして、アプリケーションが成功したかどうかを判断します
if (requestCode == 10) { if (TextUtils.equals(permissions[0],Manifest.permission.WRITE_EXTERNAL_STORAGE) && grantResults[0] == PackageManager.PERMISSION_DENIED) { //用户不同意,向用户展示该权限作用 if (!ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) { alertDialog( "请注意", "本应用需要使用访问本地存储权限,否则无法正常使用!", false, "确定", "取消", DialogInterface.OnClickListener { _, _ -> finish() }, DialogInterface.OnClickListener { _, _ -> finish() }) return } } }
RxPermissionsアプリケーションのアクセス許可メソッド
-
単一許可申請
RxPermissions(this).request(Manifest.permission.ACCESS_COARSE_LOCATION) .subscribe { if (it) { //申请成功 } else { //申请被拒 } }
-
複数の権限のアプリケーション
RxPermissions(this).requestEach( Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS ) .subscribe { permission -> when { permission.granted -> { //申请成功 } permission.shouldShowRequestPermissionRationale -> { // 用户拒绝了该权限,没有选择 不再提示 ,下次请求时,还会提示请求权限的对话框 } else -> { // 用户拒绝了该权限,选择了 不再提示 ,再次请求不会询问,需要在setting中开启 } } }
RxPermissionsパーミッションリクエストがシステムパーミッションリクエストよりもはるかに簡潔なのはなぜですか?実際、フレームワークはこれらの複雑な操作を実現するのに役立ちます。次に、RxPermissionsが内部でどのように実装されているかを見てみましょう。
ソースコード分析
すなわち、3つの主な種類を備えRxPermissions Permission
、RxPermissions
、RxPermissionsFragment
。
まず、構築メソッドを見てみましょう。このメソッドには、フラグメントを取得するためのコードが1行しかありません。
public RxPermissions(@NonNull Activity activity) {
mRxPermissionsFragment = getRxPermissionsFragment(activity);
}
getRxPermissionsFragmentメソッドで、TAGに従って検索しますrxPermissionFragment
。タグが空の場合は、タグを作成rxPermissionFragment
してアクティビティに追加します。アクセス許可のリクエストとコールバックは、このフラグメントで完了します。詳細については、以下で説明します。
private RxPermissionsFragment getRxPermissionsFragment(Activity activity) {
RxPermissionsFragment rxPermissionsFragment = findRxPermissionsFragment(activity);
boolean isNewInstance = rxPermissionsFragment == null;
if (isNewInstance) {
rxPermissionsFragment = new RxPermissionsFragment();
FragmentManager fragmentManager = activity.getFragmentManager();
fragmentManager
.beginTransaction()
.add(rxPermissionsFragment, TAG)
.commitAllowingStateLoss();
fragmentManager.executePendingTransactions();
}
return rxPermissionsFragment;
}
private RxPermissionsFragment findRxPermissionsFragment(Activity activity) {
//根据TAG找到fragment
return (RxPermissionsFragment) activity.getFragmentManager().findFragmentByTag(TAG);
}
その後、メソッドを呼び出してrequest
、ensure
、requestImplementation
public Observable<Boolean> request(final String... permissions) {
return Observable.just(TRIGGER).compose(ensure(permissions));
}
public <T> ObservableTransformer<T, Boolean> ensure(final String... permissions) {
// 将Observable<Permission>转换为Observable<Boolean>
return new ObservableTransformer<T, Boolean>() {
@Override
public ObservableSource<Boolean> apply(Observable<T> o) {
return request(o, permissions)
.buffer(permissions.length)
.flatMap(new Function<List<Permission>, ObservableSource<Boolean>>() {
@Override
public ObservableSource<Boolean> apply(List<Permission> permissions) throws Exception {
//如果permissions为空,直接返回Observable.empty(),不执行下面的逻辑
if (permissions.isEmpty()) {
return Observable.empty();
}
//遍历permissions,如果有一个Permission被拒,则返回false并发送出去
for (Permission p : permissions) {
if (!p.granted) {
return Observable.just(false);
}
}
//如果权限都申请成功,则发送true
return Observable.just(true);
}
});
}
};
}
private Observable<Permission> requestImplementation(final String... permissions) {
List<Observable<Permission>> list = new ArrayList<>(permissions.length);
List<String> unrequestedPermissions = new ArrayList<>();
//遍历permissions,在mRxPermissionsFragment中判断该权限是否已经请求成功,如果成功构建成Permission通过Observable.just()发送出去并将Observable添加到list中
for (String permission : permissions) {
mRxPermissionsFragment.log("Requesting permission " + permission);
if (isGranted(permission)) {
list.add(Observable.just(new Permission(permission, true, false)));
continue;
}
// 如果权限被拒绝
if (isRevoked(permission)) {
list.add(Observable.just(new Permission(permission, false, false)));
continue;
}
//如果权限还没有申请过,则创建一个PublishSubject并添加到 unrequestedPermissions中
PublishSubject<Permission> subject = mRxPermissionsFragment.getSubjectByPermission(permission);
if (subject == null) {
unrequestedPermissions.add(permission);
subject = PublishSubject.create();
mRxPermissionsFragment.setSubjectForPermission(permission, subject);
}
list.add(subject);
}
if (!unrequestedPermissions.isEmpty()) {
String[] unrequestedPermissionsArray = unrequestedPermissions.toArray(new String[unrequestedPermissions.size()]);
//调用requestPermissionsFromFragment中的方法申请权限
requestPermissionsFromFragment(unrequestedPermissionsArray);
}
//将多个Observable结合成一个Observable发射出去
return Observable.concat(Observable.fromIterable(list));
}
ここで最も重要なメソッドは、RxPermissionsFragment
パーミッションリクエストとデータコールバックを含むこのクラスにあります
void requestPermissions(@NonNull String[] permissions) {
//调用系统的请求权限的方法
requestPermissions(permissions, PERMISSIONS_REQUEST_CODE);
}
void onRequestPermissionsResult(String permissions[], int[] grantResults, boolean[] shouldShowRequestPermissionRationale) {
for (int i = 0, size = permissions.length; i < size; i++) {
PublishSubject<Permission> subject = mSubjects.get(permissions[i]);
...
boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
//将结果封装成Permission发送出去
subject.onNext(new Permission(permissions[i], granted, shouldShowRequestPermissionRationale[i]));
}
}
これまでのところ、request
プロセス全体を分析しましたがrequestEach
、分析は残っていません。実際のrequestEach
プロセスは上記と同様であるため、ここでは分析しません。全体として、RxPermissionsのプロセスは非常に単純ですが、多くのRxJava
演算子が使用されており、要求結果はリスナーモードを介して取得されて送信されます。
総括する
- 空のフラグメントを作成し、アクティビティに追加します
- 許可リストをトラバースし、許可を要求せずにフラグメントを介して許可を要求するメソッドを呼び出します
- Fragment
onRequestPermissionsResult
でメソッドを書き直して、結果を送信します - 観測可能なデータストリームを組み合わせる