安卓組件化應用的6.0權限適配優(yōu)化方案

組件化應用

組件化應用的概念最近挺火的肩狂。隨著app版本的迭代存捺,業(yè)務也會變的越來越復雜抖甘。組件化應用能將每個業(yè)務都單獨分成一個模塊,作為一個組件(Module)闷尿,業(yè)務模塊彼此互不依賴塑径,然后讓這些業(yè)務模塊都依賴公共模塊(也是Module)等,用路由的方式替代startactivity進行模塊間的跳轉(zhuǎn)和數(shù)據(jù)傳遞填具。這就是組件化應用的簡單概念统舀。

u=3895375886,3606044301&fm=11&gp=0.jpg

因為module與module之間是代碼隔離的,互不依賴劳景,所以添加或移除module是很方便的誉简,也方便了應用的多人并行開發(fā)。

Android6.0權限

Android6.0已經(jīng)出來快兩年了盟广,除了繼續(xù)推進Material Design闷串,相信最直觀的改變就是權限申請方式了:權限模式從一開始的全部列出授予,變成了現(xiàn)在的運行時動態(tài)申請筋量。下圖列出了截止7月份最新的系統(tǒng)占有率烹吵。雖然碎片化問題依舊嚴重,但6.0以上系統(tǒng)占有率也已經(jīng)接近一半了桨武。所以說各位安卓開發(fā)者們肋拔,如果你的應用還沒適配6.0的話,可要抓緊了呀酸。

QQ截圖20170810160140.png

如何適配

簡單介紹了上面的兩個概念后凉蜂,咱們切回正題。因為最近在做一個APP的組件化改造性誉,原來的權限適配方案是跳到一個空白activity做申請然后回調(diào)申請結(jié)果的窿吩,但是現(xiàn)在module與module之間是互不依賴的,所以activity之間接口回調(diào)的方式是行不通的艾栋。一時間不知道有什么好的方法爆存,也參考了github上幾個主流的權限適配庫,但遺憾都沒有對組件化應用提供一個專門的解決方案蝗砾。
因為這個項目采用的路由是阿里的ARouter先较。查閱文檔后發(fā)現(xiàn)里面有攔截器的功能携冤,下面是簡單的示例代碼。

// 比較經(jīng)典的應用就是在跳轉(zhuǎn)過程中處理登陸事件闲勺,這樣就不需要在目標頁重復做登陸檢查
// 攔截器會在跳轉(zhuǎn)之間執(zhí)行曾棕,多個攔截器會按優(yōu)先級順序依次執(zhí)行
  @Interceptor(priority = 8, name = "測試用攔截器")
public class TestInterceptor implements IInterceptor {
    @Override
    public void process(Postcard postcard, InterceptorCallback callback) {
    
    callback.onContinue(postcard);  // 處理完成,交還控制權
    // callback.onInterrupt(new RuntimeException("我覺得有點異常"));      // 覺得有問題菜循,中斷路由流程

    // 以上兩種至少需要調(diào)用其中一種翘地,否則不會繼續(xù)路由
    }

    @Override
    public void init(Context context) {
    // 攔截器的初始化,會在sdk初始化的時候調(diào)用該方法癌幕,僅會調(diào)用一次
    }
}

那么我們何不利用這個攔截器衙耕,在跳到一個需要頁面(比如相機頁面)之前 進行統(tǒng)一攔截,然后判斷權限是否擁有勺远,如果后則callback.onContinue(postcard),繼續(xù)跳轉(zhuǎn)橙喘,否則callback.onInterrupt(null),攔截跳轉(zhuǎn)并執(zhí)行權限申請。
同時通常一個應用通常有必要權限,沒有必要權限應用無法正常運行胶逢,如Manifest.permission.READ_PHONE_STATE,還有非必要權限厅瞎,如Manifest.permission.ACCESS_FINE_LOCATION
那么我們可以用priority字段創(chuàng)建優(yōu)先級最高的攔截器初坠,檢測所有跳轉(zhuǎn)時是否有必要權限和簸,否則先申請必要權限,然后繼續(xù)觸發(fā)下一個優(yōu)先級低的攔截器攔截檢測普通權限碟刺。

實際實現(xiàn)

定義一個permissionActivity,讓所有需要跳轉(zhuǎn)權限的頁面的activity繼承這個锁保,因為如上文講的,我們實際權限的申請和處理不是在真正需要權限的頁面完成南誊,而是在上一個頁面申請完成再跳到需要權限的頁面的身诺。如果頁面太多建議所有頁面都繼承這個activity。

public class PermissionActivity extends FragmentActivity {
  private PermissionListener permissionListener;

    public void setPermissionListener(PermissionListener permissionListener) {
        this.permissionListener = permissionListener;
    }
    /**
     * 權限請求結(jié)果
     */
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (permissionListener != null ) {
            permissionListener.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }
    }

創(chuàng)建攔權限截器:

@Interceptor(priority = 1)
public class PermissionInterceptor implements IInterceptor {

    @Override
    public void process(final Postcard postcard, final InterceptorCallback callback) {
        final Activity activity = ActivityHelper.last();
        final  String[] PERMISSIONS = new String[]{
            Manifest.permission.READ_EXTERNAL_STORAGE,
    };
        if (activity != null && !PermissionHelper.hasPermission(activity)) {
            permissionRequest(postcard, callback, (PermissionActivity) activity, permissions);
        } else {
            callback.onContinue(postcard);  // 已有權限抄囚,無需申請霉赡,繼續(xù)跳轉(zhuǎn)
        }
    }

    private void permissionRequest(final Postcard postcard, final InterceptorCallback interceptorCallback, final PermissionActivity activity, final String[] permissions) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                PermissionHelper.requestPermissions(activity, permissions, new PermissionListener() {
                    @Override
                    public void onsuccessed() {
                        callback.onContinue(postcard);// 權限申請成功,繼續(xù)跳轉(zhuǎn)
                    }

                    @Override
                    public boolean onfail() {
                        callback.onInterrupt(null);// 權限申請失敗幔托,攔截跳轉(zhuǎn)
                    }
                });
            }
        };
        MainLooper.runOnUiThread(runnable );
    }

    @Override
    public void init(Context context) {
    
    }
}

實際實現(xiàn)中有幾個注意點:
1.攔截器init(Context context)方法中的context不是當前頁的activity穴亏,而是application,也就是說你在攔截器里是無法直接拿到當前頁的上下文的重挑。所以你需要額外維護一個activity棧嗓化,在每個acitivity的oncreate()方法中入棧,在ondestory()中出棧谬哀,然后在攔截器里面取出棧頂?shù)腶citivity刺覆,也就是當前頁的acitivity。
2.void process(Postcard postcard, InterceptorCallback callback)方法在子線程中執(zhí)行史煎,如果要執(zhí)行權限申請需要先切換回主線程谦屑。

public class MainLooper extends Handler {
    private static MainLooper instance = new MainLooper(Looper.getMainLooper());

    protected MainLooper(Looper looper) {
        super(looper);
    }

    public static MainLooper getInstance() {
        return instance;
    }

    public static void runOnUiThread(Runnable runnable) {
        if(Looper.getMainLooper().equals(Looper.myLooper())) {
            runnable.run();
        } else {
            instance.post(runnable);
        }

    }
}

總結(jié)

這樣實現(xiàn)的好處也是顯而易見的:所有的權限申請操作都在攔截器里完成驳糯,對原代碼無入侵:所有的權限申請彈框都出現(xiàn)在需要權限的頁面上一個activity。我們只要讓這個activity繼承permissionActivity并處理onRequestPermissionsResult的回調(diào)即可氢橙,其他譬如處理權限申請酝枢,處理權限申請成功,失敗操作都統(tǒng)一在攔截器里完成即可悍手。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帘睦,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子坦康,更是在濱河造成了極大的恐慌竣付,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滞欠,死亡現(xiàn)場離奇詭異卑笨,居然都是意外死亡,警方通過查閱死者的電腦和手機仑撞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妖滔,“玉大人隧哮,你說我怎么就攤上這事∽幔” “怎么了沮翔?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長曲秉。 經(jīng)常有香客問我采蚀,道長,這世上最難降的妖魔是什么承二? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任榆鼠,我火速辦了婚禮,結(jié)果婚禮上亥鸠,老公的妹妹穿的比我還像新娘妆够。我一直安慰自己,他們只是感情好负蚊,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布神妹。 她就那樣靜靜地躺著,像睡著了一般家妆。 火紅的嫁衣襯著肌膚如雪鸵荠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天伤极,我揣著相機與錄音蛹找,去河邊找鬼姨伤。 笑死,一個胖子當著我的面吹牛熄赡,可吹牛的內(nèi)容都是我干的姜挺。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼彼硫,長吁一口氣:“原來是場噩夢啊……” “哼炊豪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起拧篮,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤词渤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后串绩,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缺虐,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年礁凡,在試婚紗的時候發(fā)現(xiàn)自己被綠了高氮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡顷牌,死狀恐怖剪芍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情窟蓝,我是刑警寧澤罪裹,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站运挫,受9級特大地震影響状共,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜谁帕,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一峡继、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧匈挖,春花似錦鬓椭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至贮折,卻和暖如春裤翩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工踊赠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呵扛,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓筐带,卻偏偏與公主長得像今穿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子伦籍,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容