1.簡介
在Android6.0之前版本看疙,權(quán)限請求較為簡單豆拨,僅在用戶安裝app時將自己需要使用的所有權(quán)限列出來告知用戶直奋,若用戶授權(quán),則app安裝后可隨時使用該權(quán)限施禾。自6.0開始脚线,一些涉及用戶隱私的敏感權(quán)限需在使用時動態(tài)申請,且用戶可選擇授權(quán)或拒絕弥搞。當然邮绿,權(quán)限的改進對用戶而言是好事,畢竟更能保護用戶隱私拓巧。但對于開發(fā)者而言斯碌,也多了一項動態(tài)權(quán)限申請的工作
2.權(quán)限分類
對開發(fā)者而言,權(quán)限則主要分為以下兩類:
1)普通權(quán)限(normal permissions): 只需在manifest中注冊
2)危險權(quán)限(dangerous permissions):仍需在manifest中注冊肛度,但具體授權(quán)分以下幾種情況
targetSdk<23 | targetSdk>=23 | |
---|---|---|
手機系統(tǒng)<23 | 安裝時默認獲得權(quán)限且用戶無法在安裝后取消權(quán)限 | 安裝時默認獲得權(quán)限且用戶無法在安裝后取消權(quán)限 |
手機系統(tǒng)>=23 | 安裝時默認獲得權(quán)限,但用戶可在安裝后取消授權(quán)( 取消時手機會提示用戶該APP是為舊版手機打造投慈,讓用戶謹慎操作 ) | 安裝時不會獲得權(quán)限而需在運行時向用戶動態(tài)申請承耿。用戶授權(quán)后仍可在設置界面中取消,取消授權(quán)后在app運行過程中可能會出現(xiàn)crash |
由上表可知當APP的targetSdk>=23且運行在Android>=6.0(API23)的手機上時必須使用動態(tài)申請權(quán)限
具體危險權(quán)限如下:
3.運行時權(quán)限申請(使用系統(tǒng)提供的API)
1)權(quán)限檢查
對于權(quán)限檢查伪煤,Android提供了以下3種方式
1.ContextCompat#checkSelfPermission
2.Context#checkSelfPermission
3.PermissionChecker#checkSelfPermission
需注意的是若應用targetSdk<23加袋,則第1、2種方式返回的永遠是PERMISSION_GRANTED抱既,即永遠返回已授權(quán)职烧。根據(jù)本文上面內(nèi)容知當targetSdk<23時,應用雖在安裝時就獲得授權(quán)防泵,但若運行在>=Android6.0的手機上時蚀之,用戶可在安裝后取消授權(quán),此時就不能使用第1捷泞、2種方式來檢查權(quán)限足删,而需使用第3種
public static boolean checkSelfPermission(String permission, Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//getTargetVersion是判斷app的targetSdk的方法
if (getTargetVersion(context) >= Build.VERSION_CODES.M) {
//應用的targetSdk>=23則使用Context#checkSelfPermission(permission)
return context.checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
} else {
//若targetSdk<23則使用PermissionChecker#checkSelfPermission
return PermissionChecker.checkSelfPermission(context, permission) == PermissionChecker.PERMISSION_GRANTED;
}
} else {//手機版本低于6.0的,安裝后即授權(quán)且用戶無法取消
return true;
}
}
2)請求權(quán)限
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
requestCode);
注意:1.Fragment中請求需使用自己的requestPermissions方法
3)處理請求結(jié)果
請求權(quán)限后系統(tǒng)會回調(diào)申請權(quán)限的Activity的onRequestPermissionsResult()锁右,若使用的是Fragment的requestPermissions方法失受,則回調(diào)對應Fragment的onRequestPermissionsResult()
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode != this.requestCode || grantResults.length = 0) {
return;
}
for (int i = 0; i < grantResults.length; i++) {
String permission = permissions[i];
if (grantResults[i] == PackageManager.PERMISSION_GRANTED) {
Toast.makeText(this, permission + "已被授權(quán)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, permission + "已被拒絕", Toast.LENGTH_SHORT).show();
if (shouldShowRequestPermissionRationale(permission)) {
//請求被用戶拒絕但用戶未勾選不再詢問框,可繼續(xù)請求權(quán)限
} else {
//請求被用戶拒絕且用戶勾選了不再詢問框咏瑟,需要用戶前往設置中授權(quán)
}
}
}
}
4)總結(jié)
用系統(tǒng)提供的api進行申請步驟較為繁瑣拂到,且請求和處理代碼不在相同位置,代碼量多了的話可讀性變差码泞。那有沒有什么好的方法既能簡化流程提高可讀性又能避免以上第二種情況呢兄旬?答案是肯定的,著名基佬交流網(wǎng)站github上就有豐富的權(quán)限請求庫供各位客官享用浦夷!
4.使用EasyPermissions進行權(quán)限申請
1)特點
- 鏈式操作
- 請求前會自動檢查是否已被授予 (這樣在請求前就不必再進行權(quán)限檢查了)
- 若請求的權(quán)限未在manifest中注冊辖试,將拋出明確的異常 (請求未在manifest注冊的權(quán)限將導致不彈出dialog而直接返回false辜王,有時我們可能對此十分懵逼,因為這既不報錯也不彈出dialog代碼也OK就是請求失敗罐孝,可能要很久才反應過來忘了在manifest中注冊)
- 自動重試(可配置項)呐馆,配置該選項后若請求被拒但用戶未勾選不再提示框時會自動重試直到用戶授權(quán)或勾選不再提示框
2)依賴
A.在項目根build.gradle中
allprojects {
repositories {
maven { url 'https://jitpack.io' }
}
}
B.添加依賴
dependencies {
implementation 'com.github.Ficat:EasyPermissions:v2.1.0'
}
3)使用
//requestEach方式
EasyPermissions
.with(activity)
.requestEach(Manifest.permission.CAMERA)
.result(new RequestEachExecutor.ResultReceiver() {
@Override
public void onPermissionsRequestResult(Permission permission) {
String name = permission.name;
if (permission.granted) {
//name權(quán)限被授予
} else {
if (permission.shouldShowRequestPermissionRationale) {
//name權(quán)限被拒絕但用戶未勾選不再提示框,可繼續(xù)請求
} else {
//name權(quán)限被拒絕且用戶勾選了不再提示框
//此時不能再次請求了莲兢,而需要user前往設置界面手動授權(quán)
EasyPermissions.goToSettingsActivity(activity);
}
}
}
});
//request方式汹来,請求的所有權(quán)限被用戶授權(quán)后返回true,否則返回false
EasyPermissions
.with(activity)
.request(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.autoRetryWhenUserRefuse(true, new BaseRequestExecutor.RequestAgainListener() {//是否自動重試
@Override
public void requestAgain(String[] needAndCanRequestAgainPermissions) {
//該監(jiān)聽回調(diào)中傳入的是再次請求的權(quán)限改艇,用以在重新請求時彈出說明框等信息(如
//向用戶說明為何要使用該權(quán)限)
for (String s : needAndCanRequestAgainPermissions) {
Log.e("TAG", "request again permission = "+s);
}
}
})
.result(new RequestExecutor.ResultReceiver() {
@Override
public void onPermissionsRequestResult(boolean grantAll, List<Permission> results) {
if (grantAll) {
Toast.makeText(MainActivity.this, "request permissions success!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "request permissions fail!", Toast.LENGTH_SHORT).show();
}
}
});