運行時權(quán)限:API 23之前的版本都是自動獲取權(quán)限寸宏,而從 Android 6.0 開始添加了權(quán)限申請的需求沛婴,更加安全呕乎。在android6.0以前,我們程序需要的權(quán)限我們一般只需要在AndroidManifest.xml中直接更新就好埠居,然而Android 6.0在我們原有的AndroidManifest.xml聲明權(quán)限的基礎(chǔ)上,又新增了運行時權(quán)限動態(tài)檢測事期。
如果你的程序在6.0以上的手機報權(quán)限的問題滥壕,解決方式有兩種:
第一種:簡單粗暴最有效的是在工程下的build.gradle中的 targetSdkVersion 改為21或22,因為Android6.0系統(tǒng)或以上默認為targetSdkVersion小于23的應(yīng)用默認授予了所申請的所有權(quán)限兽泣,
第二種:動態(tài)申請權(quán)限
測試1:比如我們有一個下載功能绎橘,需要寫SD卡的權(quán)限,
-
首先我們要聲明權(quán)限 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
然后我的build.gradle 中targetSdkVersion 為25
-
然后針對一個API>=23的手機唠倦,
-
然后demo的主要的功能是下載一個apk称鳞,并寫入sd卡涮较,在沒有動態(tài)權(quán)限聲明的時候,會報如圖的錯誤:
這就是表明我們需要動態(tài)權(quán)限:
-
然后在代碼中動態(tài)申請權(quán)限:
private static final int WRITE_EXTERNAL_STORAGE_REQUEST_CODE = 127;//這個值是自定義的一個int值冈止,在申請多個權(quán)限時要保證這個值不重復(fù)狂票,才能在回調(diào)時進行判斷
@Override
protected void onResume() {
super.onResume();
getPersimmion();
}
@TargetApi(23)
private void getPersimmion() {
// 如果應(yīng)用沒有獲得對應(yīng)權(quán)限
if (checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
//申請WRITE_EXTERNAL_STORAGE權(quán)限
//第一個字符串列是預(yù)申請的權(quán)限,第三個int是本次請求的辨認編號
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST_CODE);
}
}
-
此時重新運行程序:
點擊允許后程序就不會崩潰報錯了熙暴。
-
但是用戶要點擊拒絕呢闺属,如果程序不做處理,還是和沒有申請權(quán)限一樣在寫入sd卡時程序崩潰怨咪,所以要做后續(xù)的處理屋剑,比如不下載,或提示用戶去應(yīng)用設(shè)置界面手動開啟權(quán)限诗眨,toast彈框提示等唉匾,
-
此時我們要重寫一個方法onRequestPermissionsResult,用戶選擇允許或拒絕后,會回調(diào)onRequestPermissionsResult方法, 該方法類似于onActivityResult匠楚,
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
dealWithResult(requestCode,grantResults);
}
//我們接著需要根據(jù)requestCode和grantResults(授權(quán)結(jié)果)做相應(yīng)的后續(xù)處理
private void dealWithResult(int requestCode, int[] grantResults) {
if (requestCode == WRITE_EXTERNAL_STORAGE_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission Granted 用戶允許
} else {
// Permission Denied 用戶拒絕
}
}
}
測試2:有的時候我們需要獲取手機imei巍膘,程序中調(diào)用getDeviceId(),只在Manifest里添加android.permission.READ_PHONE_STATE權(quán)限是不夠的芋簿,如果不做權(quán)限的動態(tài)申請和處理峡懈,在API大于23的手機會報如下錯誤:
Caused by: java.lang.SecurityException: getDeviceId: Neither user 10084 nor current process has android.permission.READ_PHONE_STATE.
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at com.android.internal.telephony.ITelephony$Stub$Proxy.getDeviceId(ITelephony.java:4118)
at android.telephony.TelephonyManager.getDeviceId(TelephonyManager.java:801)
at com.an.test.MainActivity.mytest(MainActivity.java:51)
at java.lang.reflect.Method.invoke(Native Method)
java.lang.SecurityException,就是這個權(quán)限与斤,當(dāng)然這個只是android6.0 以上系統(tǒng)才會兒出現(xiàn)的錯誤
解決肪康,還是我們之前例子里那幾個重要的方法:checkSelfPermission去檢查app是不是具有xxx權(quán)限,撩穿;requestPermissions去動態(tài)申請權(quán)限磷支,onRequestPermissionsResult去回調(diào)結(jié)果
private static final int READ_PHONE_STATE_REQUEST_CODE =128 ;
if (checkSelfPermission(Manifest.permission.READ_PHONE_STATE)!=PackageManager.PERMISSION_GRANTED){
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE},READ_PHONE_STATE_REQUEST_CODE);
}
最后如果要批量申請權(quán)限,可以如下示例:
調(diào)用getPersimmions() ;
@TargetApi(23)
private void getPersimmions() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
ArrayList<String> permissions = new ArrayList<String>();
/*
* 讀寫權(quán)限和電話狀態(tài)權(quán)限非必要權(quán)限(建議授予)只會申請一次食寡,用戶同意或者禁止雾狈,只會彈一次
*/
// 讀寫權(quán)限
if (addPermission(permissions, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
permissionInfo += "Manifest.permission.WRITE_EXTERNAL_STORAGE Deny \n";
}
if (permissions.size() > 0) {
requestPermissions(permissions.toArray(new String[permissions.size()]), SDK_PERMISSION_REQUEST);
}
}
}
@TargetApi(23)
private boolean addPermission(ArrayList<String> permissionsList, String permission) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) { // 如果應(yīng)用沒有獲得對應(yīng)權(quán)限,則添加到列表中,準備批量申請
if (shouldShowRequestPermissionRationale(permission)){
return true;
}else{
permissionsList.add(permission);
return false;
}
}else{
return true;
}
}
@TargetApi(23)
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
// TODO Auto-generated method stub
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
參考文章:
Android 6.0以上系統(tǒng)-動態(tài)獲取權(quán)限獲取
Android7.0(android N)StrictMode API政策禁。