EasyPermission:一句代碼解決動態(tài)權(quán)限的申請和回執(zhí)(帶權(quán)限提示信息)

效果展示

216x384.gif

以上是演示請求一個相機權(quán)限的過程:

首次申請(頂部提醒)-拒絕-再次申請(頂部提醒)-再次拒絕(并勾選禁止再次詢問)-再次申請(中部彈窗引導(dǎo))-在設(shè)置頁不授權(quán)-返回-再次申請(中部彈窗引導(dǎo))-在設(shè)置頁將相機權(quán)限設(shè)為允許-返回app

在此過程中,任意一次拒絕和允許争剿,都可以及時的拿到允許/拒絕的結(jié)果功氨,進(jìn)而在頁面展示授權(quán)狀態(tài)或者執(zhí)行自己授權(quán)后的邏輯。以上的這些所有邏輯振惰,只需要一句代碼就能搞定,你相信嗎垄懂?

是的骑晶,EasyPermission她來了,在項目中集成之后草慧,安卓權(quán)限的檢查桶蛔、申請、提示漫谷、結(jié)果回執(zhí)仔雷,一句代碼就可以搞定。

EasyPermission.build()
    .mRequestCode(RC_CODE_PERMISSION)//請求code舔示,自己定義
    .mPerms(Manifest.permission.CAMERA)//權(quán)限碟婆,可支持多個
    .setAutoOpenAppDetails(true)//默認(rèn)true
    .mAlertInfo( new PermissionAlertInfo("**需要申請攝像頭權(quán)限",
                                         "**需要申請攝像頭拍攝權(quán)限,以便您能夠通過掃一掃實現(xiàn)掃描二維碼惕稻;通過拍照更換您帳號的頭像竖共;拍照上傳一些注冊帳號需要的證件信息。拒絕或取消授權(quán)將影響以上功能俺祠,不影響使用其他服務(wù)"))
    .mResult(new EasyPermissionResult() {
        @Override
        public void onPermissionsAccess(int requestCode) {
            super.onPermissionsAccess(requestCode);
            //權(quán)限已通過
        }

        @Override
        public void onPermissionsDismiss(int requestCode, @NonNull List<String> permissions) {
            super.onPermissionsDismiss(requestCode, permissions);
            //權(quán)限被拒絕
        }
).requestPermission();

接下來我們就看下它是怎么實現(xiàn)的肘迎。

需求來源

最近國家工信部對手機隱私安全越來越重視甥温,權(quán)限不能濫用,不能隨意申請(有些應(yīng)用在啟動時就申請一堆權(quán)限)妓布,更不能強制申請(有些權(quán)限不通過就不讓進(jìn)入應(yīng)用的姻蚓,已經(jīng)被下架了)。最近公司又接到上頭通知:公司某款app中有申請定位權(quán)限時沒有對用戶解釋說明匣沼,需要及時整改狰挡。

和產(chǎn)品溝通后借鑒小紅書、京東释涛,類似這種在請求權(quán)限的時候加叁,在底下彈出系統(tǒng)彈窗時,同時在頂部浮出說明信息唇撬;如果權(quán)限被禁止了它匕,就在中部彈出說明彈窗,引導(dǎo)去設(shè)置頁面中完成授權(quán)窖认。

image.png
image.png

方案分析

咨詢了隔壁IOS的現(xiàn)狀豫柬、權(quán)限在項目中,權(quán)限的申請可以也必須配置說明文案扑浸,那么在使用申請權(quán)限時系統(tǒng)就會彈出信息說明烧给。

可是安卓的動態(tài)權(quán)限管理比較松散(無情的吐槽),請求權(quán)限真的是干巴巴的請求喝噪,就像上面圖1底部的系統(tǒng)彈窗础嫡。要像京東、小紅書那樣實現(xiàn)申請彈窗時提示信息酝惧,收到權(quán)限或者拒絕時隱藏榴鼎,權(quán)限有可能被禁止(拒絕并勾選不再提示),禁止時需要彈窗提醒晚唇,引導(dǎo)去設(shè)置頁返回時又得不到有效的回調(diào)(是的檬贰,京東從設(shè)置頁回來的時候,授權(quán)后不會繼續(xù)執(zhí)行申請權(quán)限的邏輯缺亮,我們的EasyPermission卻完全可以做到)。

根據(jù)大致的分析桥言,其實流程也是挺清晰的萌踱,實現(xiàn)以上效果的流程圖如下(最終的EasyPermission庫的最終實現(xiàn)思路也是基于此做的):

image.png

方案中需要考慮的問題

看到以上流程圖,其實實現(xiàn)起來感覺還好号阿,但是有一些問題:

  • 安卓的權(quán)限申請并鸵、回調(diào)函數(shù)、彈窗都是依賴于界面的扔涧,也就是跟activity相關(guān)园担。那么在后臺服務(wù)中届谈、或者某個View中,如果用到權(quán)限怎么辦弯汰?
  • 一個頁面中用到多個權(quán)限艰山,這些回調(diào)、彈窗是不是就串在一起了很亂咏闪?
  • 假如在好多頁面都用到某個權(quán)限曙搬,全要實現(xiàn)一遍這樣的邏輯?
  • 公司有幾個app鸽嫂,每個app都要去大量的處理權(quán)限邏輯和彈窗纵装?

尋找成熟的方案

發(fā)現(xiàn)幾個用的比較多的,RxPermissions据某,easypermissions(googlesamples)橡娄,兩個庫都有幾千的star,說明還是挺多人用的癣籽。但是有個問題沒有解決(activity的關(guān)聯(lián))挽唉。

想起之前封裝的EasyPermission,雖然只是簡單的實現(xiàn)了權(quán)限的請求和回調(diào)才避,最終還是決定拿她孵化一下橱夭,進(jìn)化進(jìn)化,實現(xiàn)新的設(shè)想桑逝。

最終確實想到了解決方案棘劣,通過在初始化時,注冊一個ActivityLifecycleCallback楞遏,監(jiān)聽activity的變動茬暇,這樣在請求權(quán)限和彈窗時就可以隨時取用最頂層的activity。

當(dāng)然封裝包括后面試用時寡喝,還是發(fā)現(xiàn)了不少問題糙俗,比如單例的頁面ActivityLifecycleCallback回調(diào)的比較遲,可能導(dǎo)致拿到的activity是無效的预鬓;安卓沒有直接查詢權(quán)限是否被禁止的方法等巧骚,終是一一克服了。最終是上傳到了jetpack上格二,可以直接引用劈彪。接下來就看下怎么使用一句話來實現(xiàn)權(quán)限的請求、彈窗顶猜、回調(diào)沧奴。

集成引導(dǎo)

第一步. 添加依賴

1. 根build.gradle中添加maven倉庫的依賴.

        repositories {
            ...
            maven { url 'https://jitpack.io' }
        }
    }

2. 項目主Module的bulid.gradle添加工具庫最新版本依賴

            implementation 'com.gitee.zhang-yanqiang:easypermission:v2.0.12'
    }

最新版本查看鏈接:https://jitpack.io/#com.gitee.zhang-yanqiang/easypermission

第三步. 初始化配置

1.在Application的onCreate中完成初始化

public void onCreate() {
    super.onCreate();
    //首次使用權(quán)限申請之前完成初始化,建議放在Application onCreate()中完成
    EasyPermissionHelper.getInstance().init(this);
    }

2.將要使用EasyPermission的Activity中的onRequestPermissionsResultonActivityResult,

  • 在對應(yīng)的Activity調(diào)用EasyPermissionHelper.getInstance().onRequestPermissionsResult和onActivityResult即可长窄;
  • 如果你有BaseActivity滔吠,那么只需要在BaseActivity中設(shè)置一次即可纲菌。
  • 這兩個方方法為了實現(xiàn)授權(quán)結(jié)果的自動回調(diào),如果不需要回調(diào)可以不配置
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        //使用EasyPermissionHelper注入回調(diào)(授權(quán)彈窗回調(diào))
        EasyPermissionHelper.getInstance().onRequestPermissionsResult(requestCode, permissions, grantResults, this);
    }

@Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        //使用EasyPermissionHelper注入回調(diào)(系統(tǒng)設(shè)置返回使用)
        EasyPermissionHelper.getInstance().onActivityResult(requestCode, resultCode, data);
    }

功能使用

接下來看下怎么使用疮绷。

1.檢測權(quán)限

只需要調(diào)用EasyPermission的hasPermission方法,支持多個權(quán)限同時傳入翰舌。

EasyPermission.build().hasPermission(Manifest.permission.CAMERA);

2.申請權(quán)限

如果你在應(yīng)用啟動時需要申請權(quán)限,而且并不關(guān)注權(quán)限的結(jié)果矗愧, 只需要調(diào)用EasyPermission的requestPermission方法灶芝,支持多個權(quán)限傳入。

EasyPermission.build().requestPermission(Manifest.permission.CAMERA);

3.需要權(quán)限的結(jié)果

  • 如果你需要知道申請權(quán)限后用戶的選擇結(jié)果唉韭,同時去執(zhí)行自己的方法myVoid(),
  • 那么在onPermissionsAccess中去做就可以了夜涕,
  • onPermissionsDismiss是用戶拒絕了權(quán)限的反饋。
EasyPermission.build()
                .mRequestCode(RC_CODE_PERMISSION)//請求code属愤,自己定義
                .mPerms(Manifest.permission.CAMERA)//權(quán)限女器,可支持多個
                .mResult(new EasyPermissionResult() {//回調(diào)
                    @Override
                    public void onPermissionsAccess(int requestCode) {
                        super.onPermissionsAccess(requestCode);
                        //權(quán)限已通過
                    }

                    @Override
                    public void onPermissionsDismiss(int requestCode, @NonNull List<String> permissions) {
                        super.onPermissionsDismiss(requestCode, permissions);
                        //權(quán)限被拒絕
                    }
                }).requestPermission();

4.有時用戶拒絕了權(quán)限,而且禁止了彈出詢問住诸,我該怎么辦驾胆?想要在申請權(quán)限時彈窗告知用戶權(quán)限的必要性怎么辦?

  • 事實上贱呐,在新版本只需要通過mAlertInfo設(shè)置了提示文本丧诺,現(xiàn)在已經(jīng)默認(rèn)處理了彈窗的展示,也就是說不需要去重寫onDismissAskopenAppDetails方法了
  • 如果想要自己處理彈窗邏輯奄薇,可以通過setAutoOpenAppDetails=false關(guān)閉自動處理的邏輯
  • 只要在onDismissAsk中驳阎,就可以得到被禁止的結(jié)果,同時你要注意onDismissAsk默認(rèn)返回false
  • 如果你自己修改return true馁蒂,將視為已經(jīng)處理了禁止結(jié)果呵晚,將不再回調(diào)onPermissionsDismiss這個方法
  • 調(diào)用openAppDetails方法,可以彈窗引導(dǎo)用戶去設(shè)置界面設(shè)置權(quán)限沫屡,成功后會自動回調(diào)
EasyPermission.build()
        .mRequestCode(RC_CODE_PERMISSION)//請求code饵隙,自己定義
        .mPerms(Manifest.permission.CAMERA)//權(quán)限,可支持多個
        .setAutoOpenAppDetails(true)//默認(rèn)true
        .mAlertInfo( new PermissionAlertInfo("**需要申請攝像頭權(quán)限",
        "**需要申請攝像頭拍攝權(quán)限沮脖,以便您能夠通過掃一掃實現(xiàn)掃描二維碼金矛;通過拍照更換您帳號的頭像;拍照上傳一些注冊帳號需要的證件信息勺届。拒絕或取消授權(quán)將影響以上功能驶俊,不影響使用其他服務(wù)"))
        .mResult(new EasyPermissionResult() {
            @Override
            public void onPermissionsAccess(int requestCode) {
                super.onPermissionsAccess(requestCode);
                //權(quán)限已通過
            }

            @Override
            public void onPermissionsDismiss(int requestCode, @NonNull List<String> permissions) {
                super.onPermissionsDismiss(requestCode, permissions);
                //權(quán)限被拒絕
            }

            @Override
            public boolean onDismissAsk(int requestCode, @NonNull List<String> permissions) {
                //權(quán)限被拒絕并禁止再次詢問
                return super.onDismissAsk(requestCode,permissions);//這里true表示攔截處理,不再回調(diào)onPermissionsDismiss涮因;
            }
            @Override
            public void openAppDetails() {
                //彈出默認(rèn)的權(quán)限詳情設(shè)置提示彈出框,在設(shè)置頁完成允許操作后伺绽,會自動回調(diào)到onPermissionsAccess()
                super.openAppDetails();
                //如果樣式不滿意养泡,可以彈出自定義明彈窗嗜湃,在用戶確認(rèn)時調(diào)用 goToAppSettings();完成跳轉(zhuǎn)設(shè)置頁
            }).requestPermission();

5.彈窗樣式自定義

權(quán)限庫用起來蠻方便的,但是彈窗的文字顏色需要改一下澜掩,又不像大動干戈地每次自己去寫彈窗购披,能不能設(shè)置一下文字大小、顏色肩榕?沒問題刚陡,咱們支持彈窗自定義樣式。

setDialogStyle在初始化方法init()之后任意時刻調(diào)用株汉,設(shè)置樣式后全局生效筐乳。

·使用默認(rèn)經(jīng)典樣式(類似京東、小紅書)

EasyPermissionHelper.getInstance().setDialogStyle(new EasyAppSettingDialogStyle(EasyAppSettingDialogStyle.DialogStyle.STYLE_DEFAULT));

image.png

·使用系統(tǒng)自帶彈窗樣式

使用系統(tǒng)自帶的AlertDialog樣式乔妈,具體的展示效果每個機型不太一樣

EasyPermissionHelper.getInstance().setDialogStyle(new EasyAppSettingDialogStyle(EasyAppSettingDialogStyle.DialogStyle.STYLE_SYSTEM));
image.png

·使用自定義彈窗樣式

EasyPermissionHelper.getInstance().setDialogStyle(
        new EasyAppSettingDialogStyle(EasyAppSettingDialogStyle.DialogStyle.STYLE_CUSTOM)
        .setTitleGravity(Gravity.CENTER)//設(shè)置居中
        .setTitleSize(17)//設(shè)置標(biāo)題
        .setTitleColor("#333333")
        .setMessageSize(14)//設(shè)置內(nèi)容
        .setMessageColor("#666666")
        .setButtonTextSize(14)//設(shè)置按鈕
        .setButtonThemeColor("#FF0000")
        .setCancelText("取消")//設(shè)置文本
        .setConfirmText("去打開"));
image.png

完全自定義彈窗

以上方式只需要在初始話后設(shè)置一次蝙云,全局生效。如果以上方式依然滿足不了你胃口路召,那只能自己去控制彈窗啦勃刨。 在EasyPermissionResult中重寫openAppDetails(),只會影響當(dāng)前權(quán)限的請求彈窗。

 @Override
public void openAppDetails() {
      //在前往應(yīng)用設(shè)置詳情頁展示自己的彈窗告知用戶我們需要哪些權(quán)限打開
      //在用戶點擊確認(rèn)時調(diào)用easyPermission.goToAppSettings();完成跳轉(zhuǎn)設(shè)置頁
      }

6.其它注意事項

  1. mAlertInfo不設(shè)置將不會自動彈出權(quán)限說明彈窗,為了滿足當(dāng)前的日益嚴(yán)格的隱私政策股淡,請對認(rèn)真對待每一個權(quán)限說明
  2. 權(quán)限的申請不建議在onNewIntent中獲取
  3. 相關(guān)日志tag為"EasyPermissionLog",默認(rèn)不輸出太多信息身隐,如果需要調(diào)試請打開EasyPermissionConfigs.setDebug(true)
  4. 增加setAutoOpenAppDetails,如果PermissionAlertInfo有值,則在被禁止時自動觸發(fā) openAppDetails()
  5. 如果openAppDetails()樣式不滿足唯灵,可以重寫openAppDetails()自定義彈出內(nèi)容贾铝,也可以直接在onDismissAsk()攔截
  6. 由于EasyPermission在init初始化時使用ActivityLifecycleCallbacks開始監(jiān)聽activity變化,所以在launchMode="singleTask" onNewIntent中如果需要請求權(quán)限早敬,需要重新設(shè)置activity忌傻。 可以使用兩種方式完成。
  • 方式一:
EasyPermissionHelper.getInstance().updateTopActivity(mContext); 
easyPermission.requestPermission();
  • 方式二:
easyPermission.mContext(mContext).requestPermission();

7.其它工具

· 定位服務(wù)管理 EasyLocationTool

Android 9.0以后即使已經(jīng)獲得了用戶授權(quán)定位權(quán)限搞监,由于GPS定位服務(wù)未打開水孩,依然獲取不到定位,所以還需要對定位服務(wù)進(jìn)行處理琐驴,LocationTool支持以下方法:

  1. isLocationEnabled() 獲取當(dāng)前定位服務(wù)是否開啟
  2. gotoAppSettings() 直接跳轉(zhuǎn)到手機-設(shè)置-安全和隱私-定位服務(wù)開啟/關(guān)閉的頁面

· 通知服務(wù)管理 EasyNotificationTool

通知服務(wù)的權(quán)限在Android中也比較特殊俘种,它不像其它權(quán)限那樣去直接申請,像定位服務(wù)一樣需要去系統(tǒng)設(shè)置中開啟绝淡,所以也要去設(shè)置頁:

  1. isNotificationEnabled() 獲取當(dāng)前APP的通知權(quán)限是否開啟
  2. gotoAppSettings() 直接跳轉(zhuǎn)到手機-設(shè)置-通知和狀態(tài)欄-通知管理-APP通知設(shè)置頁

· 懸浮窗權(quán)限管理 EasyFloatWindowTool

懸浮窗權(quán)限在Android中也比較特殊宙刘,它不像其它權(quán)限那樣去直接申請,像定位服務(wù)一樣需要去系統(tǒng)設(shè)置中開啟牢酵,所以也要去設(shè)置頁:

  1. isFloatWindowEnabled() 獲取當(dāng)前APP的是否有懸浮窗權(quán)限
  2. gotoAppSettings() 直接跳轉(zhuǎn)到手機-設(shè)置-應(yīng)用管理-特殊應(yīng)用權(quán)限-顯示在其他應(yīng)用的上層-APP設(shè)置頁

結(jié)束語

  • 如果又更好的方案和思路悬包,歡迎留言或者私信,可以git上提交解決方案或者issue
  • 祝所有人平安幸福、家庭和睦馍乙、身體健康布近。
  • 愿祖國早日完成統(tǒng)一大業(yè)垫释,世界和平共處,繁榮發(fā)展撑瞧。
  • 有任何疑問棵譬,可以及時反饋給我;
  • 如果你覺得還不錯预伺,請點贊o( ̄▽ ̄)d订咸。

源代碼

Gitee地址:https://gitee.com/zhang-yanqiang/easypermission

Github地址:https://github.com/githubZYQ/easypermission

由于Github訪問不是很通暢,通常gitee更新效率會高一些

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末酬诀,一起剝皮案震驚了整個濱河市脏嚷,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌料滥,老刑警劉巖然眼,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異葵腹,居然都是意外死亡高每,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門践宴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來鲸匿,“玉大人,你說我怎么就攤上這事阻肩〈叮” “怎么了?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵烤惊,是天一觀的道長乔煞。 經(jīng)常有香客問我,道長柒室,這世上最難降的妖魔是什么渡贾? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮雄右,結(jié)果婚禮上空骚,老公的妹妹穿的比我還像新娘。我一直安慰自己擂仍,他們只是感情好囤屹,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著逢渔,像睡著了一般肋坚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天智厌,我揣著相機與錄音粟判,去河邊找鬼。 笑死峦剔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的角钩。 我是一名探鬼主播吝沫,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼递礼!你這毒婦竟也來了惨险?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤脊髓,失蹤者是張志新(化名)和其女友劉穎辫愉,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體将硝,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡恭朗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了依疼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片痰腮。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖律罢,靈堂內(nèi)的尸體忽然破棺而出膀值,到底是詐尸還是另有隱情,我是刑警寧澤误辑,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布沧踏,位于F島的核電站,受9級特大地震影響巾钉,放射性物質(zhì)發(fā)生泄漏翘狱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一睛琳、第九天 我趴在偏房一處隱蔽的房頂上張望盒蟆。 院中可真熱鬧,春花似錦师骗、人聲如沸历等。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寒屯。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間寡夹,已是汗流浹背处面。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留菩掏,地道東北人魂角。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像智绸,于是被迫代替她去往敵國和親野揪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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