Android運行時權限的總結,以及EasyPermissions框架的使用

一、android6.0之後的危險權限介紹

(注意:Android O 8.0對於權限更加嚴格,下面會說一下8.0)
android6.0之後有些危險權限須要手動去受權,就有了運行時權限的處理。下面的表格就是危險權限組:android

權限組名 權限名
CALENDAR 日曆 READ_CALENDAR
WRITE_CALENDER
CAMERA 相機 CAMERA
CONTACTS 聯繫人 READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
LOCATION 定位 ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
MICROPHONE 麥克風 RECORD_AUDIO
PHONE 電話 READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
SENSORS 傳感器 BODY_SENSORS
SMS 短信 Short Message Service
SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
STORAGE 數據存儲 READ_EXTRAL_STRORAGE
WRITE_EXTERNAL_STORAGE

申請權限時:
一、在清單文件中聲明權限(若是不在這張表中,聲明完就能夠了)
二、若是在這張表中的權限須要手動來申請git

這些權限6.0之後須要手動申請,,每個權限組中的權限只要有一個權限贊成受權了,整個權限組中的權限就不用重複申請了。
若是若是查看全部的權限,請參考:https://segmentfault.com/a/11...github

二、運行時權限申請過程:

傳統的申請過程是:
一、在AndroidManifest文件中添加須要的權限。
二、檢查權限是否受權
三、申請權限
四、處理受權的結果segmentfault

一步步來:
一、首先在請單文件中聲明,這個不用說
二、檢查權限是否受權api

if (ContextCompat.checkSelfPermission(thisActivity,
            Manifest.permission.READ_CONTACTS)
    != PackageManager.PERMISSION_GRANTED) {
    //沒有受權,編寫申請權限代碼
}else{
//已經受權,執行操做代碼
}

基本上調用checkSelfPermission()函數傳入權限參數,返回的結果又兩個:
若是是已受權的權限,該方法返回結果是 PackageManager.PERMISSION_GRANTED 常量爲 0,
若是是未受權的權限,該方法返回結果是 PackageManager.PERMISSION_DENIED 常量爲 -1。
這樣就能夠判斷是否已經受權,來進行下一步的操做。數組

三、若是沒有受權,須要申請權限app

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

這是一個異步的方法,第一個參數是Context;第二個參數是須要申請的權限的字符串數組(這個是支持同時申請多個權限,系統會逐個詢問是否受權);第三個參數爲請求碼requestCode,主要用於回調的時候檢測。框架

四、處理權限申請的回調結果
重寫Activity或者fragment的 onRequestPermissionsResul()方法異步

//權限回調方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    switch (requestCode){

        case 0:
            //grantResults數組存儲的申請的返回結果,
            //PERMISSION_GRANTED 表示申請成功
            if (grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
                //受權成功,
                //這裏寫相應的 操做代碼
            }else{
                //受權失敗,能夠簡單提示用戶
                Toast.makeText(this, "沒有受權繼續操做", Toast.LENGTH_SHORT).show();

            }
            break;
        case 1:
            //同上
            break;
        default:
            break;
    }
}
這裏稍微說一下,申請的時候是一個一個的申請的話,每次申請都有一個請求碼,
這裏的grantResults數組就只有一個值,因此都是grantResults[0]來和
PERMISSION_GRANTED來進行比較
若是是一次申請多個權限,grantResults數組返回的值就不止一個,可是,直接遍歷
它就行,只要所有知足條件纔算申請成功,才能進行相應的操做
通常的寫法是:經過
if判斷權限是否申請,沒有申請,把它加到一個集合裏面,把全部的權限都判斷一遍
之後,去遍歷這個集合,只要有一個沒有申請的,就需、要去申請權限,   
 把這個集合轉爲數組,傳到requestPermissions的第二個參數,而後就處理相應
 結果就能夠了,遍歷grantResults數組,判斷是否是所有知足條件

三、EasyPermissions的使用

GitHub地址:https://github.com/googlesamp...
EasyPermissions是谷歌封裝的一個運行時權限申請的庫,簡化了操做的過程。
使用過程: 沒有什麼前後順序,下面沒有按這個順序。這麼作是能夠的,固然還有其餘的使用方法ide

一、builde gradle中依賴
二、清單文件中聲明權限
三、重寫onRequestPermissionsResult()方法,把執行操做給easyPermissions來
四、經過hasPermissions檢查權限,或者原生的也行,而後去申請權限
五、實現EasyPermissions.PermissionCallbacks接口,重寫兩個方法,成功或失敗
六、在成功或者失敗方法中編寫要具體作的事。

GitHub地址:
(1)依賴庫

dependencies {
    compile 'pub.devrel:easypermissions:1.0.1'
}

(2)再在清單文件中聲明要申請的危險權限
若是不聲明的話,直接在代碼中寫也能申請成功,可是好想不會彈出詢問框,直接就申請了

(3)申請權限
能夠直接申請

EasyPermissions.requestPermissions(
                    MainActivity.this,
                    "申請權限",
                    0,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE,
                    Manifest.permission.RECORD_AUDIO);

最好仍是檢查一下權限是否申請:
EasyPermissions.hasPermissions(Context context, @NonNull String… perms)方法來檢測一個或者多個權限是否被容許,第二個參數是個可變數組,能夠申請多個

String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION};
if (EasyPermissions.hasPermissions(this, perms)) {
    
    // 已經申請過權限,作想作的事
} else {
    // 沒有申請過權限,如今去申請
    EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale),
            RC_CAMERA_AND_LOCATION, perms);
}

下面來講一個申請權限這個方法:
EasyPermissions.requestPermissions():圖片描述

requestPermissions() 通常用這個四個參數的就能夠
第一個參數:Context對象
第二個參數:權限彈窗上的文字提示語。告訴用戶,這個權限用途。
第三個參數:此次請求權限的惟一標識請求碼,code。
第四個參數 : 一些系列的權限。
這裏說一下第二個參數,不是第一次申請系統默認彈出的提示語,而是,咱們拒絕後,再次點擊申請彈出的對話框,,顯示咱們設置的提示語,下面有兩個按鈕,確認和取消,我就不貼圖了。

還有六個參數的,多了兩個參數就是,修改咱們上面那個確認和取消的字樣,你能夠幹成yes 和no.

四、重寫onRequestPermissionsResult()方法,把執行操做給easyPermissions
一行代碼就搞定了

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}

五、實現EasyPermissions.PermissionCallbacks接口,重寫兩個方法

public class MainActivity extends AppCompatActivity implements EasyPermissions.PermissionCallbacks {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
}

@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);

    // 把執行結果的操做給EasyPermissions
    EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this);
}

@Override //申請成功時調用
public void onPermissionsGranted(int requestCode, List<String> list) {
    //請求成功執行相應的操做
    
    好比,舉個例子
    switch (requestCode){
        case 0:
            Toast.makeText(this, "已獲取WRITE_EXTERNAL_STORAGE權限", Toast.LENGTH_SHORT).show();
            break;
        case 1:
            Toast.makeText(this, "已獲取WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權限", Toast.LENGTH_SHORT).show();
            break;
    }
}

@Override //申請失敗時調用
public void onPermissionsDenied(int requestCode, List<String> list) {
    // 請求失敗,執行相應操做
    
}
}

接下來就要說一下成功或者失敗後的操做了: 申請成功就直接作該作的事就好了,沒啥。
申請若是失敗了,這時候有個方法出現了EasyPermissions.somePermissionPermanentlyDenied(this, perms)
這個方法是谷歌建議的。就是在咱們點了不在詢問並拒絕,會彈出對話框,告訴用戶這個權限時幹嗎的,很重要,建議不要拒絕哈哈
好比這樣:

@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {

if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
    new AppSettingsDialog.Builder(this).build().show();
    //彈出個對話框
}

}

固然咱們能夠定製一下這個對話框:

@Override
public void onPermissionsDenied(int requestCode, List<String> perms) {
    //處理權限名字字符串
    StringBuffer sb = new StringBuffer();
    for (String str : perms){
        sb.append(str);
        sb.append("\n");
    }
    sb.replace(sb.length() - 2,sb.length(),"");

    switch (requestCode){
        case 0:
            Toast.makeText(this, "已拒絕權限" + perms.get(0), Toast.LENGTH_SHORT).show();
            break;
        case 1:
            Toast.makeText(this, "已拒絕WRITE_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE權限"+ perms.get(0), Toast.LENGTH_SHORT).show();
            break;
    }
    if (EasyPermissions.somePermissionPermanentlyDenied(this, perms)) {
        Toast.makeText(this, "已拒絕權限" + sb + "並再也不詢問" , Toast.LENGTH_SHORT).show();
        new AppSettingsDialog
                .Builder(this)
                .setRationale("此功能須要" + sb + "權限,不然沒法正常使用,是否打開設置")
                .setPositiveButton("是")
                .setNegativeButton("否")
                .build()
                .show();
    }
}

六、(可選)@AfterPermissionGranted()註解

使用 AfterPermissioonGranted 註解。這是可選的,可是提供出來是爲了方便。若是全部的請求的權限都被授予了,被註解的方法將會被執行,這樣作是爲了簡化一般的請求權限成功以後再調用方法的流程。同時也能夠在onPermissionsGranted 的回調中添加邏輯操做:
好比官網上的這個實例代碼:
這裏的方法名能夠本身取,主要是權限都申請完,就調用這個方法,執行裏面的操做。
其實就至關於在onPermissionsGranted()調用這個方法而已:

@AfterPermissionGranted(RC_CAMERA_AND_LOCATION)
private void methodRequiresTwoPermission() {
String[] perms = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION};
if (EasyPermissions.hasPermissions(this, perms)) {
    // Already have permission, do the thing
    // ...
} else {
    // Do not have permissions, request them now
    EasyPermissions.requestPermissions(this, getString(R.string.camera_and_location_rationale),
            RC_CAMERA_AND_LOCATION, perms);
}
}

基本上介紹完了

四、android 8.0運行時權限

對於針對Android O的應用,此行爲已被糾正。系統只會授予應用明確請求的權限。然而一旦用戶爲應用授予某個權限,則全部後續對該權限組中權限的請求都將被自動批准。

例如,假設某個應用在其清單中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。應用請求READ_EXTERNAL_STORAGE,而且用戶授予了該權限,若是該應用針對的是API級別24或更低級別,系統還會同時授予WRITE_EXTERNAL_STORAGE,由於該權限也屬於STORAGE權限組而且也在清單中註冊過。若是該應用針對的是Android O,則系統此時僅會授予READ_EXTERNAL_STORAGE,不過在該應用之後申請WRITE_EXTERNAL_STORAGE權限時,系統會當即授予該權限,而不會提示用戶。
注意:若是使用了沒有受權的權限,會崩潰的

因此對於8.0權限,咱們要作的處理,是儘可能把所用到的危險權限所有申請。可是有的權限在不一樣版本出現,因此要兼容不一樣的版本,因此要加一個版本的判斷。

歸根結底:android M (6.0)之後,申請權限組一個,即表示整個權限組能夠用,因此咱們乾脆,只要api 版本大於23(6.0),咱們申請的權限就是申請整個權限組。這樣就兼容了android8.0-------------------爲了省事的話能夠用AndPermission這個第三方框架,或者本身封裝一個。
相關文章
相關標籤/搜索