寫在前面
對于android 6.0來說,增加了權限的管理,能夠更好的保護用戶的隱私,當用戶需要某權限時,才動態(tài)的去申請。用戶也可以在應用權限管理里面關閉和打開。為了方便以后使用,這里對權限使用相關做一個簡單的總結。
android權限分類
Android6.0系統(tǒng)把權限分為兩個級別:
- Normal Permissions,即普通權限,這類權限不會潛藏有侵害用戶隱私和安全的問題,比如,訪問網(wǎng)絡的權限,訪問WIFI的權限等;
- Dangerous Permissions,即危險權限,這類權限會直接的威脅到用戶的安全和隱私問題,比如說訪問短信,相冊等權限。
普通權限是不會威脅到用戶安全的,所以這類權限是可以直接在manifest里面直接的使用,而且在安裝后也會直接的生效了。不需要特殊處理。危險權限在使用時不僅需要在manifest里面注冊,還需要動態(tài)申請,否則程序會崩潰,提示沒有權限。
危險權限分為9組,總共24個權限,如下:
| 權限組名 | 權限名 |
|---|---|
| CALENDAR 日歷 | READ_CALENDAR WRITE_CALENDER |
| CAMERA 相機 | CAMERA |
| CONTACTS 聯(lián)系人 | 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 數(shù)據(jù)存儲 | READ_EXTRAL_STRORAGE WRITE_EXTERNAL_STORAGE |
申請權限時:
1、在清單文件中聲明權限(如果不在這張表中,聲明完就可以了)
2、如果在這張表中的權限需要手動來申請
這些權限6.0以后需要手動申請,,每一個權限組中的權限只要有一個權限同意授權了,整個權限組中的權限就不用重復申請了。
如果如果查看所有的權限,請參考:
https://developer.android.com/about/versions/marshmallow
android 權限使用場景
由于android 系統(tǒng)版本太多,并且用戶使用的手機版本也無法確定,因此在權限處理時,需要多方面考慮。 而對于開發(fā)者而言,最主要考慮的是 targetversion和buildVersion(即真機系統(tǒng)版本)。下面從以下方面考慮:
| targetVersion | BuildVersion | 是否需要處理 |
|---|---|---|
| >=23 | >=23 | 需要動態(tài)處理 |
| >=23 | <23 | 不需要 |
| < 23 | >=23 | 需要處理 |
| < 23 | <23 | 不需要 |
權限基本使用
- 在manifest.xml文件中聲明需要的權限
- 檢查是否擁有權限,通過checkSelfPermission函數(shù),如下:
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
//沒有授權,編寫申請權限代碼
}else{
//已經(jīng)授權,執(zhí)行操作代碼
}
checkSelfPermission函數(shù)有兩個參數(shù):context和需要的權限
- 若沒有權限則申請權限,如下:
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
1);
這是一個異步的方法,第一個參數(shù)是Context;第二個參數(shù)是需要申請的權限的字符串數(shù)組(這個是支持同時申請多個權限,系統(tǒng)會逐個詢問是否授權);第三個參數(shù)為請求碼requestCode,主要用于回調(diào)的時候檢測。
- 處理權限的回調(diào)結果
//權限回調(diào)方法
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case 0:
//grantResults數(shù)組存儲的申請的返回結果,
//PERMISSION_GRANTED 表示申請成功
if (grantResults.length>0&&grantResults[0]== PackageManager.PERMISSION_GRANTED){
//授權成功,
//這里寫相應的 操作代碼
}else{
//授權失敗,可以簡單提示用戶
Toast.makeText(this, "沒有授權繼續(xù)操作", Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}
注意:申請的時候是一個一個的申請的話,每次申請都有一個請求碼,這里的grantResults數(shù)組就只有一個值,所以都是grantResults[0]來和PERMISSION_GRANTED來進行比較
如果是一次申請多個權限,grantResults數(shù)組返回的值就不止一個,但是,直接遍歷它就行,只要全部滿足條件才算申請成功,才能進行相應的操作
一般的寫法是:
通過if判斷權限是否申請,沒有申請,把它加到一個集合里面,把所有的權限都判斷一遍以后,去遍歷這個集合,只要有一個沒有申請的,就需、要去申請權限, 把這個集合轉為數(shù)組,傳到requestPermissions的第二個參數(shù),然后就處理相應結果就可以了,遍歷grantResults數(shù)組,判斷是不是全部滿足條件
特殊處理
但 targetVersion小于23,但是BuildVersion大于23這個場景時,若用戶在應用權限設置里面手動關閉了要使用的權限,在應用操作時,檢查權限會一直返回true,并且系統(tǒng)崩潰。
導致這個的原因,是 ContextCompat.checkSelfPermission函數(shù)再TargetVersion<23時,會一直返回true。因此為了兼容此情形,V4包里面提供了PermissionChecker.checkSelfPermission函數(shù),用來處理這種情形。因此,考慮兩種情形,完成的權限檢查代碼如下:
/**
* android 6.0 以上檢查是否有權限
* @param context context
* @param primission 權限名稱
* @return false 沒有權限 true 有權限
*/
private boolean checkPrimission(Context context ,String primission)
{
int targetSdkVersion ;
boolean result = false;
PackageInfo info = null;
try {
info = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
targetSdkVersion = info.applicationInfo.targetSdkVersion;
if (targetSdkVersion >= Build.VERSION_CODES.M) { //targetSdkVersion >= 23
if (ContextCompat.checkSelfPermission(cdActivity, primission) != PackageManager.PERMISSION_GRANTED) {
result = false;
}else{
result = true;
}
} else { //targetSdkVersion < 23
if (PermissionChecker.checkSelfPermission(cdActivity, Manifest.permission.CAMERA)
!= PermissionChecker.PERMISSION_GRANTED) {
result = false;
}else{
result = true;
}
}
} catch (PackageManager.NameNotFoundException e) {
Log.e(TAG,e.getMessage());
}
return result;
}
多次請求處理
shouldShowRequestPermissionRationale應用場景
//參數(shù)是一個權限,返回true或false
shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
?當用戶第一次拒絕申請的權限,第二次再申請權限之前彈出一個對話框,給用戶做出一個解釋,為啥需要申請權限,根據(jù)用戶的選擇,再考慮是否申請權限。
該函數(shù)返回值根據(jù)不同情形有以下情況:
?1. 第一次請求某權限時,返回值為false
?2. 第一次請求某權限拒絕后,返回值為true
?3. 第二次請求某權限拒絕后,返回值為true
?4. 第三次請求某權限,點了不再提醒,并拒絕,返回值為false
?5. 任何時候,只要允許了權限,返回值就為false
因此根據(jù)這些情況可以做一下特殊處理
- 在請求權限前,調(diào)用此函數(shù),判斷是否需要和用戶解釋(true,表示拒絕過一次);
- 在onRequestPermissionsResult里面調(diào)用,判斷用戶是否點了“不在詢問”,并拒絕??梢詮棾鰧υ捒蛞龑в脩羧ピO置頁面設置。
??不再提醒權限方法:(用戶勾選拒絕后不再詢問)
//參數(shù)是一個權限,返回true或false
shouldShowRequestPermissionRationale(Manifest.permission.WRITE_EXTERNAL_STORAGE)
返回true表示用戶沒有勾選 拒絕后不再詢問,你可以再去調(diào)用requestPermissions申請權限
返回false分幾種情況:
1.用戶勾選了 拒絕后不再詢問,你只能引導用戶去設置中開啟權限了
2.用戶自己在設置中把權限給關了...
3.系統(tǒng)禁止應用具有該權限!
注意:部分手機會對權限有自己的默認處理,比如小米,該函數(shù)一直返回false,因此,針對于不同的手機需要自己適配處理該方法。
android 8.0 處理
??在android 6.0 之上,最開始的處理是: 只要一組權限中的一個權限通過,該組其他權限也默認通過。
??對于針對Android O的應用,此行為已被糾正。系統(tǒng)只會授予應用明確請求的權限。然而一旦用戶為應用授予某個權限,則所有后續(xù)對該權限組中權限的請求都將被自動批準。
例如,假設某個應用在其清單中列出READ_EXTERNAL_STORAGE和WRITE_EXTERNAL_STORAGE。應用請求READ_EXTERNAL_STORAGE,并且用戶授予了該權限,如果該應用針對的是API級別24或更低級別,系統(tǒng)還會同時授予WRITE_EXTERNAL_STORAGE,因為該權限也屬于STORAGE權限組并且也在清單中注冊過。如果該應用針對的是Android O,則系統(tǒng)此時僅會授予READ_EXTERNAL_STORAGE,不過在該應用以后申請WRITE_EXTERNAL_STORAGE權限時,系統(tǒng)會立即授予該權限,而不會提示用戶。
權限請求框架
- RxPermission
- PermissionsDispatcher
- EasyPermissions
具體使用方式后續(xù)補充??梢詆ithub上自行搜索使用方式。
自己也封裝過一個框架
github地址:https://github.com/YuanQiCan/PermissionGrant
包含以下功能:
- 權限檢查,targetSdkVersion 大于23和小于23兩種情形
- 單個權限和多個權限申請?zhí)幚?/li>
- shouldShowRequestPermissionRationale包含的情形處理
- 基本對畫框顯示和頁面跳轉
有興趣的可以看看,使用方便。