一、Android權(quán)限介紹
應(yīng)用權(quán)限有助于保護(hù)對以下數(shù)據(jù)的訪問和對以下操作的執(zhí)行,從而為保護(hù)用戶隱私提供支持:
- 受限數(shù)據(jù),例如系統(tǒng)狀態(tài)和用戶的聯(lián)系信息。
- 受限操作,例如連接到已配對的設(shè)備并錄制音頻。
1.1 權(quán)限分類
- 安裝時權(quán)限
系統(tǒng)會在應(yīng)用安裝時自動授予應(yīng)用相應(yīng)權(quán)限,包括普通權(quán)限和簽名權(quán)限。 - 運(yùn)行時權(quán)限
運(yùn)行時權(quán)限也稱為危險權(quán)限,Android 6.0 開始需要在應(yīng)用中執(zhí)行權(quán)限申請相關(guān)代碼,系統(tǒng)會彈出授權(quán)框提示框,需要用戶點(diǎn)擊才可以授權(quán)。 - 特殊權(quán)限
Android 6.0 開始需要用戶在應(yīng)用設(shè)置界面中才能開啟權(quán)限。
基本上每個版本,權(quán)限都會有一定的修改,而且系統(tǒng)對這方面的限制是越來越嚴(yán)格,所以正確的做法是請求最少數(shù)量的權(quán)限。
二、權(quán)限申請
Android 6.0 版本開始,權(quán)限部分有了重大改變,所以下面以Android 6.0 為分界線,介紹如何申請權(quán)限。
2.1 Android 6.0 以下
不管是普通權(quán)限還是危險權(quán)限,只需在 AndroidManifest.xml 清單文件中進(jìn)行申明即可:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3.2 android 6.0 以上
安裝時只會給普通權(quán)限授權(quán),其他權(quán)限需要特殊操作進(jìn)行申請。
- 危險權(quán)限:
不僅要在清單文件中申明權(quán)限,還需要代碼中動態(tài)申請權(quán)限,系統(tǒng)會彈出對應(yīng)的權(quán)限提示框,用戶點(diǎn)擊同意才可以授權(quán)。 - 特殊權(quán)限
不僅要在清單文件中申明權(quán)限,還需要在用戶在應(yīng)用設(shè)置界面進(jìn)行授權(quán)。
權(quán)限等級可以通過 官網(wǎng) 進(jìn)行查詢。
動態(tài)申請權(quán)限
主要分為以下幾個步驟:
- 判斷當(dāng)前是否有權(quán)限
if (PackageManager.PERMISSION_GRANTED == ActivityCompat
.checkSelfPermission(context, permission)) {
//已授權(quán)
} else {
//未授權(quán)
}
- 進(jìn)行權(quán)限申請
ActivityCompat.requestPermissions(activity, String[] permissions, REQUEST_CODE));
- 用戶授權(quán)后操作
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE) {
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
//已授權(quán)
} else {
//未授權(quán)
}
}
}
}
完整參考代碼如下:
private void requestStoragePermission() {
List<String> needRequestList = checkPermission(this, PERMISSION_LIST);
if (needRequestList.isEmpty()) {
//已授權(quán)
} else {
//申請權(quán)限
requestPermission(needRequestList);
}
}
private List<String> checkPermission(Context context, String[] checkList) {
List<String> list = new ArrayList<>();
for (String s : checkList) {
if (PackageManager.PERMISSION_GRANTED != ActivityCompat
.checkSelfPermission(context, s)) {
list.add(s);
}
}
return list;
}
private void requestPermission(List<String> needRequestList) {
ActivityCompat
.requestPermissions(activity, needRequestList.toArray(new String[0]),
REQUEST_CODE));
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE_STORAGE) {
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
//已授權(quán)
} else {
//未授權(quán)
}
}
}
}
權(quán)限被禁止
如果用戶第一次拒絕權(quán)限后,第二次再申請權(quán)限時,系統(tǒng)提示框會出現(xiàn)一個不再詢問的按鈕,如下圖:

如果用戶勾選“不再詢問”,同時點(diǎn)擊拒絕后,相當(dāng)于權(quán)限被禁止了。下次再申請權(quán)限,會直接回調(diào)權(quán)限被拒絕。即 requestPermissions 調(diào)用后不會再彈出系統(tǒng)提示框,只能引導(dǎo)用戶去應(yīng)用設(shè)置界面進(jìn)行授權(quán)。
這時候可以通過 shouldShowRequestPermissionRationale 方法進(jìn)行判斷。
該方法的本意是,當(dāng)權(quán)限被拒絕后,你可以提示用戶為什么需要獲取該權(quán)限。有下面幾種場景:
- 沒有申請權(quán)限時,返回false
- 申請權(quán)限,但是被拒絕了,返回true
- 申請權(quán)限,但是被用戶禁止了,或者勾選了不再詢問,返回false
- 申請權(quán)限,用戶允許了,返回false
主要流程如下:
-
onRequestPermissionsResult權(quán)限申請回調(diào)后,判斷權(quán)限是否被用戶禁止。 - 引導(dǎo)用戶跳轉(zhuǎn)到應(yīng)用設(shè)置界面授權(quán)。
- 由于授權(quán)后返回應(yīng)用并沒有任何提示,所以需要重新再判斷權(quán)限。
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
@NonNull int[] grantResults) {
if (requestCode == REQUEST_CODE) {
for (int i = 0; i < permissions.length; i++) {
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
//用戶已授權(quán)
} else {
//判斷用戶是否勾選了不再詢問
if (VERSION.SDK_INT >= VERSION_CODES.M && !shouldShowRequestPermissionRationale(
permission.WRITE_EXTERNAL_STORAGE)) {
//跳轉(zhuǎn)到應(yīng)用設(shè)置界面授權(quán)
goToSetting();
}
}
}
}
}
/**
* 跳轉(zhuǎn)應(yīng)用設(shè)置界面進(jìn)行授權(quán)
*/
private void goToSetting() {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
Uri uri = Uri.fromParts("package", getPackageName(), null);
intent.setData(uri);
startActivityForResult(intent, REQUEST_CODE_SETTING);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_SETTING) {
//從設(shè)置界面回來,是不知道用戶是否有授權(quán)的,所以需要重新再判斷
List<String> needRequestList = checkPermission(this, PERMISSION_LIST);
if (needRequestList.isEmpty()) {
//已授權(quán)
}
}
}