1. 目標(biāo)
此文章的最終目標(biāo):讓童鞋們了解6.0動態(tài)權(quán)限的邏輯,以及學(xué)會封裝動態(tài)權(quán)限申請,實(shí)現(xiàn)'一句話申請權(quán)限'。
2. 前言
在android6.0之前,開發(fā)者無需在java代碼里進(jìn)行危險權(quán)限的申請,只需在AndroidManifest.xml文件里進(jìn)行權(quán)限聲明即可,但從android6.0開始,google為了用戶的安全考慮,加入了動態(tài)權(quán)限機(jī)制,危險權(quán)限必須在代碼里申請,當(dāng)然,AndroidManifest.xml文件里一樣還是要進(jìn)行聲明,別忘了這一點(diǎn)哦。(ps:加入了動態(tài)權(quán)限,雖然對開發(fā)者而言是麻煩了一些,但是對整體的android環(huán)境有一定的改善,流氓軟件不能像以前那樣流氓了。)
3. 正常權(quán)限 和 危險權(quán)限
Android系統(tǒng)權(quán)限分為幾個保護(hù)級別。需要了解的兩個最重要保護(hù)級別是 正常權(quán)限 和 危險權(quán)限:
(1)正常權(quán)限:
涵蓋應(yīng)用需要訪問其沙盒外部數(shù)據(jù)或資源,但對用戶隱私或其他應(yīng)用操作風(fēng)險很小的區(qū)域。這些權(quán)限在應(yīng)用安裝時授予,運(yùn)行時不再詢問用戶。例如: 網(wǎng)絡(luò)訪問、WIFI狀態(tài)、音量設(shè)置等。完整的正常權(quán)限列表參考官網(wǎng) 正常權(quán)限。
(2)危險權(quán)限:
涵蓋應(yīng)用需要涉及用戶隱私信息的數(shù)據(jù)或資源,或者可能對用戶存儲的數(shù)據(jù)或其他應(yīng)用的操作產(chǎn)生影響的區(qū)域。例如: 讀取通訊錄、讀寫存儲器數(shù)據(jù)、獲取用戶位置等。如果應(yīng)用聲明需要這些危險權(quán)限,則必須在運(yùn)行時明確告訴用戶,讓用戶手動授予。
權(quán)限組
Android系統(tǒng)對所有的危險權(quán)限進(jìn)行了分組,稱為 權(quán)限組 。屬于同一組的危險權(quán)限將自動合并授予,用戶授予應(yīng)用某個權(quán)限組的權(quán)限,則應(yīng)用將獲得該權(quán)限組下的所有權(quán)限(前提是相關(guān)權(quán)限在 AndroidManifest.xml 中有聲明)。
危險權(quán)限 和 權(quán)限組 列表如下:
(英文版)

(中文版)

注意:在 AndroidManifest.xml 聲明過的危險權(quán)限對應(yīng)的權(quán)限組可以在系統(tǒng) “設(shè)置” -> “應(yīng)用” -> “應(yīng)用信息” -> “權(quán)限” 中查看,可以手動授權(quán)和取消授權(quán)。
4.申請步驟
(1) targetSdkVersion>=23的,需要動態(tài)申請;<23不需要動態(tài)申請(2018年8月Google要求所有應(yīng)用面向Android8.0及以上開發(fā),即targetSdkVersion 26+);
(2) 在AndroidManifest.xml中申請你需要的權(quán)限,包括普通權(quán)限和需要申請的特殊權(quán)限。
(3) 開始申請權(quán)限,此處分為3部。
a.檢查權(quán)限,有的話就doSomething,沒有就走第2步。
/**
* 檢查所有權(quán)限是否授權(quán)
* @return true,全部已授權(quán),false,全部或者部分未授權(quán)
*/
private boolean isAllPermissionGranted() {
boolean isAllGranted = true;
for (int i = 0; i < mPermissions.length; i++) {
if (ContextCompat.checkSelfPermission(this,mPermissions[i]) != PackageManager.PERMISSION_GRANTED) {
isAllGranted = false;
break;
}
}
return isAllGranted;
}
b.申請權(quán)限
if(ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.CALL_PHONE)){
//已經(jīng)拒絕過一次,會有一個不再提示的選項框
new AlertDialog.Builder(this)
.setTitle("權(quán)限申請")
.setMessage("提供了解釋需要該權(quán)限的機(jī)會")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
requestPermission();
}
})
.setNegativeButton("Cancel", null)
.create()
.show();
}else {
//從未拒絕過
requestPermission();
}
c.處理申請結(jié)果,在Activity/Fragment中有回調(diào)方法onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE){
//是否全部授權(quán)
boolean isAllGranted = true;
for (int grant:grantResults) {
Log.d("grant:",grant+"");
if (grant != PackageManager.PERMISSION_GRANTED){
//一個未通過授權(quán)即變?yōu)閒alse
isAllGranted = false;
break;
}
}
if (isAllGranted){
//授權(quán)成功
call();
}else {
//引導(dǎo)用戶去設(shè)置里面手動設(shè)置權(quán)限
openAppDetails();
}
}
}
private void openAppDetails() {
new AlertDialog.Builder(this)
.setMessage("需要撥打電話權(quán)限")
.setPositiveButton("手動設(shè)置", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent();
intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.setData(Uri.parse("package:"+getPackageName()));
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
startActivity(intent);
}
})
.setNegativeButton("取消",null)
.create()
.show();
}
https://blog.csdn.net/android2me/article/details/69525975
Android 6.0動態(tài)權(quán)限介紹與處理詳細(xì)介紹