Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android6.0權限管理到RxPermissions源碼分析

Android6.0權限管理到RxPermissions源碼分析

編輯:關於Android編程

在給應用適配6.0版本的時候,我們就需要運行時權限管理。在6.0開始有一套新的運行機制管理用於更友好的保護用戶的隱私安全,一般涉及用戶隱私的需要實時來提示用戶通過允許和拒絕來授權。

如何申請一個權限呢?
1.在AndroidManifest中把我們需要的權限添加,像我那天忘記加了一點就閃退,呼!奔潰了好久。
2.檢查權限

if (ContextCompat.checkSelfPermission(thisActivity,
                Manifest.permission.READ_CONTACTS)
        != PackageManager.PERMISSION_GRANTED) {
        // 已經申請同意了就直接處理邏輯代碼
}else{
    // 走申請流程
}

3.申請這個權限

ActivityCompat.requestPermissions(thisActivity,
                new String[]{Manifest.permission.READ_CONTACTS},
                MY_PERMISSIONS_REQUEST_READ_CONTACTS);

4.在Activity中處理這個申請回調

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // 如果權限被取消了,這個數組會是空的
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // 權限被允許了  接著處理下一步邏輯

            } else {

                // 權限被拒絕   可以做些友好的引導處理
            }
            return;
        }
    }
}

OK、一整段的流程下來之後我瞬間感覺這麼寫反正我不喜歡,跟onActivityResult的回調似的,太不喜歡了。然後就在github上搜索一下,發現了RxPermissions這麼一個開源庫而且是基於RxJava瞬間就被吸引了,接下來我們就聊聊這個庫。

RxPermissions簡單用法介紹

// 必須在類似onCreate的方法中進行初始化
RxPermissions.getInstance(this)
    .request(Manifest.permission.CAMERA)
    .subscribe(granted -> {
        if (granted) { // M版本之前都是返回true
           // 權限允許
        } else {
           // 權限被拒絕
        }
    });

這是一段簡單用法並且基於RxJava以及在Retrolambda條件下看起來的模樣,當然這裡是你需要的權限每一個都同意之後才回調到回來,當然你也可以一個一個處理回調。

RxPermissions.getInstance(this)
    .requestEach(Manifest.permission.CAMERA,
             Manifest.permission.READ_PHONE_STATE)
    .subscribe(permission -> { // 將會發射多個權限請求
        if (permission.granted) {
           // 權限允許
        }
    });

更多用法可以查看https://github.com/tbruyelle/RxPermissions
接下來點進去查看源碼,看他是如何封裝權限管理的。

    static RxPermissions sSingleton;

    public static RxPermissions getInstance(Context ctx) {
        if (sSingleton == null) {
            sSingleton = new RxPermissions(ctx.getApplicationContext());
        }
        return sSingleton;
    }

    private Context mCtx;

沒錯RxPermissions是采用單例模式,傳入ctx.getApplicationContext()是因為權限允許與否是回調回來,存在可能得Context洩露所以傳入的是ApplicationContext對象,接下我們就連著調用request方法。

/**
     * 立即請求權限,調用必須在應用程序的初始化階段
     */
    public Observable request(final String... permissions) {
        return Observable.just(null).compose(ensure(permissions));
    }

我們可以看到是走入ensure這個方法,permissions這個參數就是我們傳入的權限數組,compose操作法需要一個Observable.Transformer來將我們前面的Observable轉成我們想要的Observable類似於flatmap操作符,我們可以看到返回的結果是Observable.Transformer< Object, Boolean >也就是把Observable.just(null)轉成我們想要的Observable< Boolean >,所以我們進入到ensure這個方法看是如何轉換的。

public Observable.Transformer

根據傳入的參數一開始是進入request這個方法中去,二話不說直接跟著進去看看情況。

    private Observable request(final Observable trigger,
                                           final String... permissions) {
        if (permissions == null || permissions.length == 0) {
            throw new IllegalArgumentException("RxPermissions.request/requestEach requires at least one input permission");
        }
        return oneOf(trigger, pending(permissions))
                .flatMap(new Func1

繼續二話不說跳入oneOf這個方法中去,可是我們發現參數中pending(permissions)有這個一個方法,所以我們先進去看這個方法。

    private Observable pending(final String... permissions) {
        for (String p : permissions) {
            if (!mSubjects.containsKey(p)) {
                return Observable.empty();
            }
        }
        return Observable.just(null);
    }

這時候又迷糊了mSubjects這裡面是什麼東西呢?

    // Contains all the current permission requests.
    // Once granted or denied, they are removed from it.
    private Map> mSubjects = new HashMap<>();

從聲明的注釋裡面來看,存放的就是當前的權限請求數組,允許或者拒絕都將從裡面移除。這裡需要解釋一下Observable.empty()表示的是:不發射任何數據並正常結束的Observable。所以pending裡面要麼返回empty要麼返回null的Observable,根據後面的代碼可以看到只有我們請求一個不存在的權限的時候會拋出錯誤從而沒有在mSubjects中remove,然後我們再進入oneOf:

    private Observable oneOf(Observable trigger, Observable pending) {
        if (trigger == null) {
            return Observable.just(null);
        }
        return Observable.merge(trigger, pending);
    }

所以這邊會返回一個Observable.just(null)、或者返回Observable.merge(trigger, pending)的一個合並的Observable然後一個一個的發射出去。然後進入最重要的request_方法中去:

    private Observable request_(final String... permissions) {

        List> list = new ArrayList<>(permissions.length);
        List unrequestedPermissions = new ArrayList<>();

        // In case of multiple permissions, we create a observable for each of them.
        // At the end, the observables are combined to have a unique response.
        for (String permission : permissions) {
            log("Requesting permission " + permission);
            if (isGranted(permission)) {
                // Already granted, or not Android M
                // Return a granted Permission object.
                list.add(Observable.just(new Permission(permission, true)));
                continue;
            }

            if (isRevoked(permission)) {
                // Revoked by a policy, return a denied Permission object.
                list.add(Observable.just(new Permission(permission, false)));
                continue;
            }

            PublishSubject subject = mSubjects.get(permission);
            // Create a new subject if not exists
            if (subject == null) {
                unrequestedPermissions.add(permission);
                subject = PublishSubject.create();
                mSubjects.put(permission, subject);
            }

            list.add(subject);
        }

        if (!unrequestedPermissions.isEmpty()) {
            startShadowActivity(unrequestedPermissions
                    .toArray(new String[unrequestedPermissions.size()]));
        }
        return Observable.concat(Observable.from(list));
    }

for循環我們要請求的權限數組,通過isGranted_先判斷是否已經權限被允許了。

    private boolean isGranted_(String permission) {
        return mCtx.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
    }

通過isRevoked_方法來確認是否權限被取消了

    private boolean isRevoked_(String permission) {
        return mCtx.getPackageManager().isPermissionRevokedByPolicy(permission, mCtx.getPackageName());
    }

然後會判斷是否已經在mSubjects權限列表中了,如果沒有加入unrequestedPermissions這個還沒被請求的列表中然後去啟動ShadowActivity來進行權限授權。

        if (!unrequestedPermissions.isEmpty()) {
            startShadowActivity(unrequestedPermissions
                    .toArray(new String[unrequestedPermissions.size()]));
        }

在Activity中處理Intent請求拿出需要請求的權限

    private void handleIntent(Intent intent) {
        String[] permissions = intent.getStringArrayExtra("permissions");
        requestPermissions(permissions, 42);
    }

然後回調權限請求結果到onRequestPermissionsResult中

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        RxPermissions.getInstance(this).onRequestPermissionsResult(requestCode, permissions, grantResults);
        finish();
    }

然後執行到onRequestPermissionsResult(引用RxPermissions是一個單列所以對象是同一個的)把授權的結果返回出去。

    void onRequestPermissionsResult(int requestCode,
                                    String permissions[], int[] grantResults) {
        for (int i = 0, size = permissions.length; i < size; i++) {
            log("onRequestPermissionsResult  " + permissions[i]);
            // Find the corresponding subject
            PublishSubject subject = mSubjects.get(permissions[i]);
            if (subject == null) {
                // No subject found
                throw new IllegalStateException("RxPermissions.onRequestPermissionsResult invoked but didn't find the corresponding permission request.");
            }
            mSubjects.remove(permissions[i]);
            boolean granted = grantResults[i] == PackageManager.PERMISSION_GRANTED;
            subject.onNext(new Permission(permissions[i], granted));
            subject.onCompleted();
        }
    }

是不是覺得很奇怪這邊發射了數據出去然後我們在ensure這個方法通過subscribe也發射數據,按我的理解呢onRequestPermissionsResult這裡面的發射數據我們並沒有去做接收,更多的是確認當前這次的權限請求是否被允許了。然後無亂結果與否我們都返回到request_這個方法中去,並且通過concat把結果返回給ensure。

return Observable.concat(Observable.from(list));

concat主要作用是將多個Observable連續發射出去。

buffer(permissions.length)

我們看到ensure中用到這麼一個操作符,這個操作符類似一個緩存區也就是說一下子把緩沖區中的數據一下子全部發射出去而不是一個一個發射,而request跟requestEach的區別就是這與這個buffer操作。

flatMap(new Func1, Observable>() {
                            @Override
                            public Observable call(List permissions) {
                                if (permissions.isEmpty()) {
                                    // Occurs during orientation change, when the subject receives onComplete.
                                    // In that case we don't want to propagate that empty list to the
                                    // subscriber, only the onComplete.
                                    return Observable.empty();
                                }
                                // Return true if all permissions are granted.
                                for (Permission p : permissions) {
                                    if (!p.granted) {
                                        return Observable.just(false);
                                    }
                                }
                                return Observable.just(true);
                            }
                        });

然後通過flatMap來判斷任何一個權限被拒絕了就會返回false全部通過才返回true。
上面的是對權限請求必須每一個都同意後才能通過,如果我們使用requestEach來權限請求的話就不同了只要有允許就發射出去。

    public Observable.Transformer

因為requestEach返回的用concat連接起來的Observable所以會依次發射權限數據出去。
大概的RxPermissons的源碼就是這麼個流程,當然裡面涉及了一些RxJava的操作符而且該庫也支持RxJava2.0了,這樣封裝在項目中使用就更加方便了。

RxPermissions項目地址:https://github.com/tbruyelle/RxPermissions
參考文章:http://blog.csdn.net/lmj623565791/article/details/50709663

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved