Android6.0動(dòng)態(tài)權(quán)限筆記

參考:

提示用戶授予或拒絕權(quán)限的系統(tǒng)對(duì)話框怀骤。

一. 權(quán)限說明:

1. 權(quán)限種類:

Android中權(quán)限分為正常權(quán)限(即拣度,不會(huì)對(duì)用戶隱私或設(shè)備操作造成很大風(fēng)險(xiǎn)的權(quán)限)和危險(xiǎn)權(quán)限(即趣席,可能影響用戶隱私或設(shè)備正常操作的權(quán)限):

  • 正常權(quán)限涵蓋應(yīng)用需要訪問其沙盒外部數(shù)據(jù)或資源,但對(duì)用戶隱私或其他應(yīng)用操作風(fēng)險(xiǎn)很小的區(qū)域孩哑。例如癌蓖,設(shè)置時(shí)區(qū)的權(quán)限就是正常權(quán)限怯晕。如果應(yīng)用聲明其需要正常權(quán)限哟旗,系統(tǒng)會(huì)自動(dòng)向應(yīng)用授予該權(quán)限。如需當(dāng)前正常權(quán)限的完整列表荣病,請(qǐng)參閱正常權(quán)限

  • 危險(xiǎn)權(quán)限涵蓋應(yīng)用需要涉及用戶隱私信息的數(shù)據(jù)或資源个盆,或者可能對(duì)用戶存儲(chǔ)的數(shù)據(jù)或其他應(yīng)用的操作產(chǎn)生影響的區(qū)域脖岛。例如颊亮,能夠讀取用戶的聯(lián)系人屬于危險(xiǎn)權(quán)限。如果應(yīng)用聲明其需要危險(xiǎn)權(quán)限,則用戶必須明確向應(yīng)用授予該權(quán)限件舵。

危險(xiǎn)權(quán)限和權(quán)限組:

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

2. 權(quán)限的授予:

如果您的應(yīng)用在其清單中列出正常權(quán)限,系統(tǒng)會(huì)自動(dòng)授予這些權(quán)限。如果您的應(yīng)用在其清單中列出危險(xiǎn)權(quán)限合武,系統(tǒng)會(huì)要求用戶明確授予這些權(quán)限临梗。Android 發(fā)出請(qǐng)求的方式取決于系統(tǒng)版本:

  • 如果設(shè)備運(yùn)行的是 Android 6.0(API 級(jí)別 23)或更高版本,并且應(yīng)用的 targetSdkVersion
    是 23 或更高版本稼跳,則應(yīng)用在運(yùn)行時(shí)向用戶請(qǐng)求權(quán)限盟庞。用戶可隨時(shí)調(diào)用權(quán)限,因此應(yīng)用在每次運(yùn)行時(shí)均需檢查自身是否具備所需的權(quán)限汤善。

  • 如果設(shè)備運(yùn)行的是 Android 5.1(API 級(jí)別 22)或更低版本什猖,并且應(yīng)用的 targetSdkVersion
    是 22 或更低版本票彪,則系統(tǒng)會(huì)在用戶安裝應(yīng)用時(shí)要求用戶授予權(quán)限。如果將新權(quán)限添加到更新的應(yīng)用版本不狮,系統(tǒng)會(huì)在用戶更新應(yīng)用時(shí)要求授予該權(quán)限降铸。用戶一旦安裝應(yīng)用,他們撤銷權(quán)限的唯一方式是卸載應(yīng)用摇零。

二. 動(dòng)態(tài)權(quán)限授予的幾個(gè)重要的方法:

注意:在Activity里調(diào)用時(shí)Context和Activity參數(shù)可以忽略

  1. int ContextCompat.checkSelfPermission (Context context, String permission)參數(shù):(上下文, 需要判斷的權(quán)限[如:Manifest.permission.READ_CONTACTS])
    該方法用來檢測(cè)應(yīng)用是否具有某權(quán)限推掸,返回值是PackageManager.PERMISSION_GRANTED(已授權(quán))或PackageManager.PERMISSION_GRANTED(未授權(quán))

  2. void requestPermissions (Activity, permissions, int requestCode)參數(shù):(上下文,需要申請(qǐng)的權(quán)限的列表(String數(shù)組)[如:new String[]{Manifest.permission.READ_CONTACTS}]驻仅,自己定義的requestCode[如:REQUEST_READ_CONTACTS(自定義int值)](主要是回調(diào)的時(shí)候用來判斷授權(quán)種類))
    該方法用來請(qǐng)求權(quán)限终佛,請(qǐng)求過程會(huì)顯示一個(gè)Dialog(不可自定義),無論用戶是否確認(rèn)授權(quán)都會(huì)調(diào)用回調(diào)方法onRequestPermissionsResult()

  3. void onRequestPermissionsResult (int requestCode, String[] permissions, int[] grantResults)參數(shù):(requestPermissions方法傳過來的參數(shù)雾家,要請(qǐng)求的權(quán)限列表铃彰,各權(quán)限的授權(quán)情況(與需要權(quán)限的數(shù)組對(duì)應(yīng)))
    該方法是用戶請(qǐng)求權(quán)限之后的回調(diào)方法,用戶可以在這里做判斷進(jìn)行需要的操作芯咧。

  4. boolean shouldShowRequestPermissionRationale (Activity activity, String permission)參數(shù):(上下文牙捉,需要判斷的權(quán)限)
    該方法判斷一個(gè)權(quán)限是否被拒絕過,Android官方對(duì)此方法的解釋是用該方法判斷是否需要給用戶進(jìn)行為什么需要權(quán)限的提示敬飒。

三. 動(dòng)態(tài)權(quán)限的申請(qǐng)

  1. manifest中注冊(cè)權(quán)限:(如需要訪問通訊錄權(quán)限)
<uses-permission android:name="android.permission.READ_CONTACTS" />
  1. 詢問是否有該權(quán)限:
    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
    switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)){
            case PackageManager.PERMISSION_GRANTED:
                Log.i(TAG, "onCreate: Granted...");
                break;
            case PackageManager.PERMISSION_DENIED:
                Log.i(TAG, "onCreate: Denied...");
                Log.i(TAG, "onCreate: 是否被拒絕過:"+shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS));
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);//請(qǐng)求權(quán)限
                break;
        }
    }
  1. 當(dāng)沒有該權(quán)限時(shí)請(qǐng)求授予權(quán)限:
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);
  1. 重載回調(diào)方法:
@Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        /*判斷授權(quán)種類*/
        if(requestCode == REQUEST_READ_CONTACTS){
            /*授權(quán)成功*/
            if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求通過");
            }
            /*授權(quán)失敗*/
            else {
                Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求未通過");
            }
        }
    }

四. 源碼:

package cn.foxnickel.androidpermission;

import android.Manifest;
import android.annotation.TargetApi;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    public static int REQUEST_READ_CONTACTS=100;
    private final String TAG = getClass().getSimpleName();
    @TargetApi(Build.VERSION_CODES.M)
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)){
            case PackageManager.PERMISSION_GRANTED:
                Log.i(TAG, "onCreate: Granted...");
                break;
            case PackageManager.PERMISSION_DENIED:
                Log.i(TAG, "onCreate: Denied...");
                Log.i(TAG, "onCreate: 是否被拒絕過:"+shouldShowRequestPermissionRationale(Manifest.permission.READ_CONTACTS));
                requestPermissions(new String[]{Manifest.permission.READ_CONTACTS},REQUEST_READ_CONTACTS);
                break;
        }

    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        /*判斷授權(quán)種類*/
        if(requestCode == REQUEST_READ_CONTACTS){
            /*授權(quán)成功*/
            if(grantResults.length>0 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求通過");
            }
            /*授權(quán)失敗*/
            else {
                Log.i(TAG, "onRequestPermissionsResult: 權(quán)限請(qǐng)求未通過");
            }
        }
    }
}

五. 封裝(轉(zhuǎn)自吳小龍博客)

BaseActivity:

public class BaseActivity extends AppCompatActivity {
    public static int REQUEST_PERMISSION = 100;
    public onPermissionCallbackListener onPermissionCallbackListener;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
     
    @TargetApi(M)
    public void requestRuntimePermission(String permission, onPermissionCallbackListener onPermissionCallbackListener) {
        this.onPermissionCallbackListener = onPermissionCallbackListener;
        switch (checkSelfPermission(permission)) {
            case PackageManager.PERMISSION_GRANTED:
                // 已有授權(quán)
                Log.i("wxl", "已有授權(quán)");
                if (this.onPermissionCallbackListener != null)
                    onPermissionCallbackListener.onGranted();
                break;
            case PackageManager.PERMISSION_DENIED:
                // 1邪铲、沒有權(quán)限:尚未請(qǐng)求過權(quán)限;
                // 2无拗、或者請(qǐng)求授權(quán)被拒絕带到,用shouldShowRequestPermissionRationale判斷用戶是否拒絕過,如果返回true英染,表示用戶拒絕過揽惹,
                // 再次請(qǐng)求權(quán)限,將會(huì)出現(xiàn)“不再詢問”四康,勾上“不再詢問”搪搏,只能選擇拒絕,再次進(jìn)入闪金,shouldShowRequestPermissionRationale始終false
                // 3疯溺、或者曾經(jīng)授權(quán)過,但用戶在設(shè)置中禁用權(quán)限
                Log.i("wxl", "是否拒絕過=" + shouldShowRequestPermissionRationale(permission));
                requestPermissions(new String[]{permission}, REQUEST_PERMISSION);
                break;
            default:
                break;
        }
    }
  
    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {        
        if (requestCode == REQUEST_PERMISSION) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                // 授權(quán)請(qǐng)求被通過哎垦,讀取通訊錄
                Log.i("wxl", "onRequestPermissionsResult=授權(quán)請(qǐng)求被通過");
                if (onPermissionCallbackListener != null)
                    onPermissionCallbackListener.onGranted();
            } else {
                Log.i("wxl", "onRequestPermissionsResult=授權(quán)請(qǐng)求不被通過");
                if (onPermissionCallbackListener != null)
                    onPermissionCallbackListener.onDenied();
            }
        }
    }
}

/*這里新建了接口onPermissionCallbackListener囱嫩,為了回調(diào)方便:*/
public interface onPermissionCallbackListener {
    void onGranted();
    void onDenied();
}

在需要使用到權(quán)限之前調(diào)用requestRuntimePermission方法,如通訊錄權(quán)限:

requestRuntimePermission(READ_CONTACTS, new onPermissionCallbackListener() {
    @Override
    public void onGranted() {
        Log.i("wxl", "授權(quán)請(qǐng)求通過");
    }
    @Override
    public void onDenied() {
        Log.i("wxl", "授權(quán)請(qǐng)求拒絕");
    }
});

六. 總結(jié)

  • 先詢問是否已經(jīng)得到授權(quán)漏设,若已經(jīng)授權(quán)墨闲,則直接進(jìn)行操作,若未授權(quán)愿题,則請(qǐng)求權(quán)限损俭,然后在授權(quán)回調(diào)中進(jìn)行操作蛙奖。
  • 可以在MainActivity中進(jìn)行授權(quán)管理,也可以封裝授權(quán)管理到BaseActivity
  • 多個(gè)權(quán)限可以直接在String數(shù)組中加入(壞處:公用一個(gè)requestCode杆兵,不方便回調(diào)的判斷)雁仲,也可以重新詢問是否授權(quán)。

七.補(bǔ)充

  1. 申請(qǐng)多個(gè)權(quán)限時(shí)可以先判斷有沒有該權(quán)限琐脏,如果沒有就加到List中去攒砖,然后將List轉(zhuǎn)換為數(shù)組,然后調(diào)用
ActivityCompat.requestPermissions(Context,String []permissions,PERMISSIONS_REQ);

申請(qǐng)全部權(quán)限日裙。
代碼:

List<String> permissionList = new ArrayList<>();//申請(qǐng)權(quán)限的List
        /*判斷*/
        if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.M){
            if(checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onCreate: finelocation denied");
                permissionList.add(Manifest.permission.ACCESS_FINE_LOCATION);
            }
            if(checkSelfPermission(Manifest.permission.READ_PHONE_STATE)!=PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onCreate: phonestate denied");
                permissionList.add(Manifest.permission.READ_PHONE_STATE);
            }
            if(checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onCreate: write storage denied");
                permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
            }
            if(checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION)!=PackageManager.PERMISSION_GRANTED){
                Log.i(TAG, "onCreate: coarse location denied");
                permissionList.add(Manifest.permission.ACCESS_COARSE_LOCATION);
            }
        /*申請(qǐng)*/
            if(!permissionList.isEmpty()){
                String permissions[] = permissionList.toArray(new String[permissionList.size()]);
                ActivityCompat.requestPermissions(this,permissions,PERMISSIONS_REQ);
            }else {
                requestLocation();
            }
        }else {
            requestLocation();
        }
  1. 另一種申請(qǐng)多個(gè)權(quán)限的寫法(自己定義申請(qǐng)權(quán)限的函數(shù))
    • 調(diào)用requestPermission方法申請(qǐng)權(quán)限
/*判斷SDK版本吹艇,6.0以上就申請(qǐng)權(quán)限,將要申請(qǐng)的權(quán)限傳給requestPermission方法*/
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        requestPermission(Manifest.permission.SEND_SMS, Manifest.permission.READ_PHONE_STATE, Manifest.permission.CALL_PHONE, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.ACCESS_COARSE_LOCATION);
}
  • requestPermission方法
@TargetApi(Build.VERSION_CODES.M)
    private void requestPermission(String... permissions) {
        List<String> permissionList = new ArrayList<>();//要申請(qǐng)的權(quán)限列表
        /**
         * 判斷權(quán)限是否已經(jīng)擁有昂拂,若未擁有則添加到List中
         */
        for (String permission : permissions) {
            switch (checkSelfPermission(permission)) {
                case PackageManager.PERMISSION_GRANTED:
                    Log.i(TAG, "onCreate: Granted...");
                    break;
                case PackageManager.PERMISSION_DENIED:
                    Log.i(TAG, "onCreate: Denied...");
                    permissionList.add(permission);
                    break;
            }
        }
        //申請(qǐng)未擁有的權(quán)限
        if (!permissionList.isEmpty()) {
            requestPermissions(permissionList.toArray(new String[permissionList.size()]),REQUEST_PERMISSIONS);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末受神,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子格侯,更是在濱河造成了極大的恐慌鼻听,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件联四,死亡現(xiàn)場離奇詭異撑碴,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)朝墩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門醉拓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人收苏,你說我怎么就攤上這事亿卤。” “怎么了倒戏?”我有些...
    開封第一講書人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵怠噪,是天一觀的道長。 經(jīng)常有香客問我杜跷,道長,這世上最難降的妖魔是什么矫夷? 我笑而不...
    開封第一講書人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任葛闷,我火速辦了婚禮,結(jié)果婚禮上双藕,老公的妹妹穿的比我還像新娘淑趾。我一直安慰自己,他們只是感情好忧陪,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開白布扣泊。 她就那樣靜靜地躺著近范,像睡著了一般。 火紅的嫁衣襯著肌膚如雪延蟹。 梳的紋絲不亂的頭發(fā)上评矩,一...
    開封第一講書人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音阱飘,去河邊找鬼斥杜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沥匈,可吹牛的內(nèi)容都是我干的蔗喂。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼高帖,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼缰儿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起散址,我...
    開封第一講書人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤乖阵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后爪飘,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體义起,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年师崎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了默终。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡犁罩,死狀恐怖齐蔽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情床估,我是刑警寧澤含滴,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站丐巫,受9級(jí)特大地震影響谈况,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜递胧,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一碑韵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缎脾,春花似錦祝闻、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽华蜒。三九已至,卻和暖如春豁遭,著一層夾襖步出監(jiān)牢的瞬間叭喜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來泰國打工堤框, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留域滥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓蜈抓,卻偏偏與公主長得像启绰,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沟使,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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