Android - 6.0動(dòng)態(tài)權(quán)限申請(qǐng)封裝

運(yùn)行時(shí)權(quán)限

此版本引入了一種新的權(quán)限模式埋泵,如今砂竖,用戶可直接在運(yùn)行時(shí)管理應(yīng)用權(quán)限。這種模式讓用戶能夠更好地了解和控制權(quán)限谭跨,同時(shí)為應(yīng)用開發(fā)者精簡(jiǎn)了安裝和自動(dòng)更新過程。用戶可為所安裝的各個(gè)應(yīng)用分別授予或撤銷權(quán)限。

對(duì)于以 Android 6.0(API 級(jí)別 23)或更高版本為目標(biāo)平臺(tái)的應(yīng)用螃宙,請(qǐng)務(wù)必在運(yùn)行時(shí)檢查和請(qǐng)求權(quán)限蛮瞄。要確定您的應(yīng)用是否已被授予權(quán)限,請(qǐng)調(diào)用新增的 checkSelfPermission() 方法谆扎。要請(qǐng)求權(quán)限挂捅,請(qǐng)調(diào)用新增的 requestPermissions() 方法。即使您的應(yīng)用并不以 Android 6.0(API 級(jí)別 23)為目標(biāo)平臺(tái)堂湖,您也應(yīng)該在新權(quán)限模式下測(cè)試您的應(yīng)用闲先。

如需了解有關(guān)在您的應(yīng)用中支持新權(quán)限模式的詳情,請(qǐng)參閱使用系統(tǒng)權(quán)限无蜂。如需了解有關(guān)如何評(píng)估新模式對(duì)應(yīng)用的影響的提示伺糠,請(qǐng)參閱權(quán)限最佳做法

新增檢查方法 checkSelfPermission()

| 參數(shù) |
permission String:正在檢查的權(quán)限的名稱斥季。
這個(gè)值絕對(duì)不能null训桶。
| 返回 |
| int | PackageManager.PERMISSION_GRANTED如果您有權(quán)限,或者如果沒有酣倾。PackageManager.PERMISSION_DENIED
價(jià)值是PERMISSION_GRANTED或PERMISSION_DENIED舵揭。

新增請(qǐng)求權(quán)限方法 requestPermissions()

| 參數(shù) |
permissions String:請(qǐng)求的權(quán)限。我必須非空并且不是空的躁锡。
requestCode int:特定于應(yīng)用程序的請(qǐng)求代碼以與報(bào)告的結(jié)果匹配午绳。應(yīng)該>=0onRequestPermissionsResult(int, String[], int[])
| 拋出 |
IllegalArgumentException 如果requestCode為負(fù)數(shù)。

官方有個(gè)地方說可以使用ContextWrapper.checkSelfPermission(String) 映之。其實(shí)這個(gè)方法很多地方都能使用到拦焚。
好,Android M 為什么會(huì)新增這兩方法呢.因?yàn)樵贏ndroid 6.0 (API 23) 開始用戶開始在應(yīng)用運(yùn)行時(shí)向其授予權(quán)限,而不是在應(yīng)用安裝時(shí)授予惕医。這種權(quán)限機(jī)制可以讓用戶更好的管理應(yīng)用的權(quán)限耕漱,保障用戶隱私。從此之后...

系統(tǒng)權(quán)限分為兩種

正常權(quán)限

不會(huì)直接給用戶隱私權(quán)帶來風(fēng)險(xiǎn)抬伺。如果您的應(yīng)用在其清單中列出了正常權(quán)限螟够,系統(tǒng)將自動(dòng)授予該權(quán)限。
android.permission.ACCESS LOCATIONEXTRA_COMMANDS
android.permission.ACCESS NETWORKSTATE
android.permission.ACCESS NOTIFICATIONPOLICY
android.permission.ACCESS WIFISTATE
android.permission.ACCESS WIMAXSTATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE NETWORKSTATE
android.permission.CHANGE WIFIMULTICAST_STATE
android.permission.CHANGE WIFISTATE
android.permission.CHANGE WIMAXSTATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND STATUSBAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET PACKAGESIZE
android.permission.INTERNET
android.permission.KILL BACKGROUNDPROCESSES
android.permission.MODIFY AUDIOSETTINGS
android.permission.NFC
android.permission.READ SYNCSETTINGS
android.permission.READ SYNCSTATS
android.permission.RECEIVE BOOTCOMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST INSTALLPACKAGES
android.permission.SET TIMEZONE
android.permission.SET_WALLPAPER
android.permission.SET WALLPAPERHINTS
android.permission.SUBSCRIBED FEEDSREAD
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE SYNCSETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT

危險(xiǎn)權(quán)限

會(huì)授予應(yīng)用訪問用戶機(jī)密數(shù)據(jù)的權(quán)限峡钓。如果您列出了危險(xiǎn)權(quán)限妓笙,則用戶必須明確批準(zhǔn)您的應(yīng)用使用這些權(quán)限。
group:android.permission-group.CONTACTS
permission:android.permission.WRITE_CONTACTS
permission:android.permission.GET_ACCOUNTS
permission:android.permission.READ_CONTACTS

group:android.permission-group.PHONE
permission:android.permission.READ_CALL_LOG
permission:android.permission.READ_PHONE_STATE
permission:android.permission.CALL_PHONE
permission:android.permission.WRITE_CALL_LOG
permission:android.permission.USE_SIP
permission:android.permission.PROCESS_OUTGOING_CALLS
permission:com.android.voicemail.permission.ADD_VOICEMAIL

group:android.permission-group.CALENDAR
permission:android.permission.READ_CALENDAR
permission:android.permission.WRITE_CALENDAR

group:android.permission-group.CAMERA
permission:android.permission.CAMERA

group:android.permission-group.SENSORS
permission:android.permission.BODY_SENSORS

group:android.permission-group.LOCATION
permission:android.permission.ACCESS_FINE_LOCATION
permission:android.permission.ACCESS_COARSE_LOCATION

group:android.permission-group.STORAGE
permission:android.permission.READ_EXTERNAL_STORAGE
permission:android.permission.WRITE_EXTERNAL_STORAGE

group:android.permission-group.MICROPHONE
permission:android.permission.RECORD_AUDIO

group:android.permission-group.SMS
permission:android.permission.READ_SMS
permission:android.permission.RECEIVE_WAP_PUSH
permission:android.permission.RECEIVE_MMS
permission:android.permission.RECEIVE_SMS
permission:android.permission.SEND_SMS
permission:android.permission.READ_CELL_BROADCASTS

閱讀到這里,小伙伴會(huì)有疑問.為什么危險(xiǎn)權(quán)限一組一組能岩。這里解釋一下,比如 permission-group.SMS 中的其中一條READ_SMS被授權(quán)了寞宫。那么在使用其他同組權(quán)限的時(shí)候就不會(huì)去向用戶發(fā)起請(qǐng)求,我們使用checkSelfPermission得到的結(jié)果也是授權(quán)的拉鹃。

兼容性的問題

在Android 6.0 以前只要在AndroidManifest.xml上申明了權(quán)限,應(yīng)用就默認(rèn)帶有權(quán)限.(在原生系統(tǒng)中)辈赋。有些廠商的手機(jī)一樣可以讓用戶關(guān)閉掉權(quán)限鲫忍。那么...在API<23的情況下關(guān)掉權(quán)限.再使用權(quán)限.那么只有死路條.所以。采取良好的方案就是Try 钥屈。

封裝思路

其實(shí)每寫一篇簡(jiǎn)書前我都會(huì)看其他人寫的文章,這樣就可以把每個(gè)人的優(yōu)勢(shì)結(jié)合在一起悟民。我之前做適配的時(shí)候也在Github上找過動(dòng)態(tài)權(quán)限申請(qǐng)的庫(kù),也可以說成是工具類把。我去看了源碼篷就。又一個(gè)聲稱可以在任何地方都可以使用到權(quán)限,后來我就用上了這個(gè)射亏。其實(shí)當(dāng)時(shí)我并不是很理解,因?yàn)闄?quán)限當(dāng)時(shí)我去找資料了是Activity才能發(fā)起了.回調(diào)固然回到Activity,后來我翻看他的源碼...是new 了一個(gè)Activity出來.還有一些工具類是讓你一行代碼調(diào)用.然后在onRequestPermissionsResult也要寫一行工具類的代碼.我覺得這種比較麻煩。后來我就想到了竭业。將使用到的方法功能封裝在一個(gè)Activity里面智润。讓BaseActivity去繼承這個(gè)PermissionRequestActivity。一個(gè)方法使用,給一個(gè)回調(diào)出來,授權(quán)權(quán)限是否成功未辆。

PermissionRequestActivity


import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.provider.Settings;
import android.support.annotation.NonNull;
import android.support.v4.app.ActivityCompat;
import android.support.v4.app.FragmentActivity;
import android.support.v7.app.AlertDialog;

/**
 * Created by 賣火柴的小女孩 - Jc on 2018/8/21.
 */

public class PermissionRequestActivity extends FragmentActivity {

    private static final int PERMISSION_REQUEST_CODE = 1088;

    private String mPermissionDes;
    private CallBack mCallBack;


    /**
     * 權(quán)限申請(qǐng)使用方法
     *
     * @param permissionDes 權(quán)限說明
     * @param callBack      申請(qǐng)回調(diào)
     * @param permissions   申請(qǐng)權(quán)限
     */
    protected void requestPermission(String permissionDes, CallBack callBack, @NonNull String... permissions) {
        mCallBack = callBack;
        mPermissionDes = permissionDes;
        if (checkPermission(permissions))
            mCallBack.hasPermission();
        else {
            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);
        }
    }

    /**
     * 判斷系統(tǒng)版本大于6.0的時(shí)候
     *
     * @param permissions 申請(qǐng)權(quán)限
     * @return
     */
    protected boolean checkPermission(@NonNull String... permissions) {
        //大于6.0的時(shí)候需要?jiǎng)討B(tài)申請(qǐng)權(quán)限.小于6.0的時(shí)候如果用戶手動(dòng)關(guān)閉權(quán)限,程序即崩 需要做Try處理
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            return checkSelfPermissions(permissions);
        }
        return true;
    }

    /**
     * 檢查權(quán)限是否已經(jīng)授權(quán)
     *
     * @param permissions 申請(qǐng)權(quán)限
     * @return
     */
    private boolean checkSelfPermissions(@NonNull String... permissions) {
        boolean flag = true;
        for (String p : permissions) {
            if (ActivityCompat.checkSelfPermission(this, p) != PackageManager.PERMISSION_GRANTED) {
                flag = false;
                break;
            }
        }
        return flag;
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        boolean hasAllGranted = true;
        for (int i = 0; i < grantResults.length; ++i) {
            if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                hasAllGranted = false;
                if (!ActivityCompat.shouldShowRequestPermissionRationale(this, permissions[i])) {
                    showDialogPrompt();
                } else {
                    //權(quán)限申請(qǐng)被拒絕 窟绷,但用戶未選擇'不再提示'選項(xiàng)
                    mCallBack.lossPermission();
                }
                break;
            }
        }
        if (hasAllGranted) {
            mCallBack.hasPermission();
        }
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    /**
     * 由于用戶手動(dòng)關(guān)閉權(quán)限提示。APP需要做人性化提示
     */
    private void showDialogPrompt() {
        new AlertDialog.Builder(this)
                .setTitle("權(quán)限申請(qǐng)")
                .setMessage(mPermissionDes)
                .setCancelable(false)
                .setPositiveButton("去設(shè)置", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //引導(dǎo)用戶至設(shè)置頁(yè)手動(dòng)授權(quán)
                        getAppSetting();
                    }
                })
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //引導(dǎo)用戶手動(dòng)授權(quán)鼎姐,權(quán)限請(qǐng)求失敗
                        mCallBack.lossPermission();
                    }
                }).show();
    }

    /**
     * 跳轉(zhuǎn)設(shè)置 應(yīng)用設(shè)置界面
     *
     * @return
     */
    private Intent getAppSetting() {
        Intent localIntent = null;
        if (Build.VERSION.SDK_INT >= 9) {
            localIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            localIntent.setData(Uri.fromParts("package", getPackageName(), null));
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        } else if (Build.VERSION.SDK_INT <= 8) {
            localIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            localIntent.setAction(Intent.ACTION_VIEW);
            localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails");
            localIntent.putExtra("com.android.settings.ApplicationPkgName", getPackageName());
            localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        startActivity(localIntent);
        return localIntent;
    }


    /**
     * 權(quán)限申請(qǐng)回調(diào)
     */
    interface CallBack {
        void hasPermission();

        void lossPermission();
    }

}

使用

requestPermission("獲取手機(jī)信息-獲取手機(jī)號(hào)碼钾麸、IMEI、IMSI權(quán)限\n讀寫手機(jī)存儲(chǔ)-讀寫手機(jī)存儲(chǔ)", new CallBack() {
                @Override
                public void hasPermission() {
                    String IMEI = getIMEI(MainActivity.this);
                    ((TextView) findViewById(R.id.tv)).setText(IMEI);
                }

                @Override
                public void lossPermission() {
                    Toast.makeText(MainActivity.this, "權(quán)限申請(qǐng)被拒絕", Toast.LENGTH_SHORT).show();
                }
            }, Manifest.permission.READ_PHONE_STATE, Manifest.permission.READ_EXTERNAL_STORAGE);

代碼講解

其實(shí)代碼不多,只有100多行炕桨。
方法: requestPermission
參數(shù):String permissionDes -- 用于用戶選擇'不再提示'按鈕提示語(yǔ)
CallBack callBack -- 應(yīng)用是否帶有權(quán)限或是否授權(quán)權(quán)限成功
@NonNull String... permissions -- 需要授權(quán)或檢查的權(quán)限

這個(gè)方法一進(jìn)去 我做了一個(gè)判斷 checkPermission(permissions) , 先去檢查是否有權(quán)限,如果有權(quán)限的話.那么就不去授權(quán)權(quán)限了.

方法 :checkPermission() 進(jìn)來判斷是否有權(quán)限的時(shí)候這個(gè)方法有一個(gè)API 就是剛才最上面開始講的checkSelfPermission 這個(gè)需要 Build.VERSION.SDK_INT >= Build.VERSION_CODES.M..所以不滿足這個(gè)條件的都以TRUE返回出去,表明應(yīng)用在6.0以下的設(shè)備默認(rèn)有這些權(quán)限饭尝。但是剛才在兼容性的時(shí)候講過了.會(huì)崩。

接下來檢測(cè)到?jīng)]有權(quán)限,使用了這一段代碼

ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST_CODE);

這一行就是向用戶發(fā)起權(quán)限授權(quán)的代碼了.接下來 我們看 onRequestPermissionsResult 献宫。 這個(gè)方法是向用戶請(qǐng)求權(quán)限的回調(diào)結(jié)果钥平。這個(gè)方法里面我做了處理,我檢測(cè)了用戶是否點(diǎn)擊了 ' 不再提示 ' 的按鈕。(有些手機(jī)沒有這個(gè)按鈕,有些手機(jī)有,當(dāng)選擇了此按鈕之后 再次發(fā)起授權(quán)請(qǐng)求,系統(tǒng)將不再向用戶發(fā)起權(quán)限授權(quán)請(qǐng)求.而是直接返回拒絕的信息回來.)那么這時(shí)我們就需要做一個(gè)友好的提示了姊途。如果用戶是由于手動(dòng)點(diǎn)擊了這個(gè)不再提示的按鈕而導(dǎo)致第二次或第n次沒有收到授權(quán)的消息.那我們應(yīng)用需要給用戶一個(gè)提示框showDialogPrompt(),我這里寫了一個(gè)最簡(jiǎn)單的彈窗涉瘾。很多APP都有自己主題的彈窗.主要就是提示用戶。告知用戶 他的權(quán)限被他自己手動(dòng)不再提示了.那么我們給他一個(gè)系統(tǒng)設(shè)置界面的跳轉(zhuǎn)getAppSetting(); 然后這個(gè)方法的Build.VERSION.SDK_INT <= 8 我就不解釋了.有興趣的就自己去百度捷兰。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末立叛,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贡茅,更是在濱河造成了極大的恐慌秘蛇,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顶考,死亡現(xiàn)場(chǎng)離奇詭異赁还,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)驹沿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門艘策,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人渊季,你說我怎么就攤上這事朋蔫》=ィ” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵斑举,是天一觀的道長(zhǎng)搅轿。 經(jīng)常有香客問我,道長(zhǎng)富玷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任既穆,我火速辦了婚禮赎懦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘幻工。我一直安慰自己励两,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開白布囊颅。 她就那樣靜靜地躺著当悔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪踢代。 梳的紋絲不亂的頭發(fā)上盲憎,一...
    開封第一講書人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音胳挎,去河邊找鬼饼疙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛慕爬,可吹牛的內(nèi)容都是我干的窑眯。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼医窿,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼磅甩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起姥卢,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卷要,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后隔显,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體却妨,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年括眠,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了彪标。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡掷豺,死狀恐怖捞烟,靈堂內(nèi)的尸體忽然破棺而出薄声,到底是詐尸還是另有隱情,我是刑警寧澤题画,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布默辨,位于F島的核電站,受9級(jí)特大地震影響苍息,放射性物質(zhì)發(fā)生泄漏缩幸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一竞思、第九天 我趴在偏房一處隱蔽的房頂上張望表谊。 院中可真熱鬧,春花似錦盖喷、人聲如沸爆办。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)距辆。三九已至,卻和暖如春暮刃,著一層夾襖步出監(jiān)牢的瞬間跨算,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來泰國(guó)打工沾歪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漂彤,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓灾搏,卻偏偏與公主長(zhǎng)得像挫望,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子狂窑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 那些要?jiǎng)討B(tài)權(quán)限(這么記比較危險(xiǎn)的權(quán)限媳板,獲取硬件和用戶信息權(quán)限) 不過現(xiàn)在as 中會(huì)主動(dòng)提示加動(dòng)態(tài)權(quán)限 calend...
    菩提大師閱讀 2,716評(píng)論 1 8
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,190評(píng)論 25 707
  • 故鄉(xiāng)對(duì)面有座山,相貌平平泉哈。我與它卻有著一段不解之緣蛉幸。 開門平眼望去便能看見對(duì)面那一座山,山不高一眼盡收眼底丛晦。故鄉(xiāng)對(duì)...
    南林瑤閱讀 329評(píng)論 2 5
  • 我寫日記大約有10年左右時(shí)間奕纫,主要是敘事的,感悟的烫沙,聽了葉老師的100講匹层,第一次聽到晨間日記。于是就開始寫了锌蓄,開始...
    趙遠(yuǎn)東閱讀 353評(píng)論 0 1