android6.0棉花糖,app將不會在安裝的時(shí)候授予權(quán)限。取而代之的是,app不得不在運(yùn)行時(shí)一個(gè)一個(gè)詢問用戶授予權(quán)限。
android {
compileSdkVersion 23
...
defaultConfig {
...
targetSdkVersion 23
...
}
}
如何app/build.gradle是23的話,在6.0上運(yùn)行一些權(quán)限,沒有做處理,會直接崩潰:
...
Caused by: java.lang.SecurityException: Permission Denial:
opening provider com.android.providers.contacts.ContactsProvider2 from ProcessRecord
{c3b3c66 16712:com.wuxiaolong.apksample/u0a62} (pid=16712, uid=10062)
requires android.permission.READ_CONTACTS or android.permission.WRITE_CONTACTS
...
如果targetSdkVersion 22,就不會發(fā)生這樣的錯(cuò)誤,下面就來實(shí)踐下這個(gè)6.0運(yùn)行的權(quán)限。
效果預(yù)覽
按照慣例,先上效果圖:

說明:第一次請求授權(quán),是沒有“不再詢問”,拒絕后,再次請求授權(quán),就會出現(xiàn)“不再詢問”。
實(shí)踐
AndroidManifest.xml
<uses-permission android:name="android.permission.READ_CONTACTS" />
代碼調(diào)用
在需要使用到權(quán)限之前調(diào)用以下代碼:
private void mayRequestContacts() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
switch (checkSelfPermission(Manifest.permission.READ_CONTACTS)) {
case PackageManager.PERMISSION_GRANTED:
// 已有授權(quán)
Log.i("wxl", "已有授權(quán)");
break;
case PackageManager.PERMISSION_DENIED:
// 沒有權(quán)限:尚未請求過權(quán)限,
// 或者請求授權(quán)被拒絕,
// 或者曾經(jīng)授權(quán)過,但被用戶在設(shè)置中禁用權(quán)限
Log.i("wxl", "沒有權(quán)限:尚未請求過權(quán)限,或者請求授權(quán)被拒絕," +
"或者曾經(jīng)授權(quán)過, 但被用戶在設(shè)置中禁用權(quán)限");
/**
* 如果用戶勾上了“不再詢問”,這時(shí)候就不應(yīng)彈請求權(quán)限的對話框,
* 可以在請求權(quán)限之前用
* shouldShowRequestPermissionRationale判斷用戶是否拒絕過,
* 如果返回true,表示用戶拒絕過。
*/
Log.i("wxl", "shouldShowRequestPermissionRationale=="
+ shouldShowRequestPermissionRationale(READ_CONTACTS));
if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
Snackbar.make(mEmailView,
R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
.setAction(android.R.string.ok, new View.OnClickListener() {
@Override
@TargetApi(Build.VERSION_CODES.M)
public void onClick(View v) {
requestPermissions(new String[]{READ_CONTACTS},
REQUEST_READ_CONTACTS);
}
}).show();
} else {
requestPermissions(new String[]{READ_CONTACTS},
REQUEST_READ_CONTACTS);
}
break;
default:
break;
}
}
}
checkSelfPermission:檢查權(quán)限
requestPermissions:請求權(quán)限
shouldShowRequestPermissionRationale:判斷用戶是否拒絕過
授權(quán)回調(diào)
不管是允許或拒絕,都會回調(diào):
@Override
public void onRequestPermissionsResult(int requestCode,
@NonNull String[] permissions,@NonNull int[] grantResults) {
if (requestCode == REQUEST_READ_CONTACTS) {
if (grantResults.length == 1 &&
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// 授權(quán)請求被通過,讀取通訊錄
Log.i("wxl", "授權(quán)請求被通過,讀取通訊錄");
} else {
Log.i("wxl", "授權(quán)請求不被通過");
}
}
}
多個(gè)權(quán)限
@TargetApi(Build.VERSION_CODES.M)
private void checkPermissions() {
List<String> permissionsNeeded = new ArrayList<>();
final List<String> permissionsList = new ArrayList<>();
if (deniedPermission(permissionsList, Manifest.permission.ACCESS_FINE_LOCATION))
permissionsNeeded.add("GPS");
if (deniedPermission(permissionsList, Manifest.permission.READ_CONTACTS))
permissionsNeeded.add("Read Contacts");
if (permissionsList.size() > 0) {
if (permissionsNeeded.size() > 0) {
// Need Rationale
String message = "You need to grant access to " + permissionsNeeded.get(0);
for (int i = 1; i < permissionsNeeded.size(); i++)
message = message + ", " + permissionsNeeded.get(i);
requestPermissions(permissionsList.toArray(new String[permissionsList.size()]), REQUEST_PERMISSIONS);
}
}
}
@TargetApi(Build.VERSION_CODES.M)
private boolean deniedPermission(List<String> permissionsList, String permission) {
if (checkSelfPermission(permission) == PackageManager.PERMISSION_DENIED) {
permissionsList.add(permission);
// true,表示用戶拒絕過
if (shouldShowRequestPermissionRationale(permission)) {
return true;
}
}
return false;
}
/**
* Callback received when a permissions request has been completed.
*/
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
if (requestCode == REQUEST_PERMISSIONS) {
Map<String, Integer> perms = new HashMap<String, Integer>();
// Initial
perms.put(Manifest.permission.ACCESS_FINE_LOCATION, PackageManager.PERMISSION_GRANTED);
perms.put(Manifest.permission.READ_CONTACTS, PackageManager.PERMISSION_GRANTED);
// Fill with results
for (int i = 0; i < permissions.length; i++)
perms.put(permissions[i], grantResults[i]);
// Check for ACCESS_FINE_LOCATION
if (perms.get(Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
&& perms.get(Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
// All Permissions Granted
Log.i("wxl", "授權(quán)請求被通過");
} else {
// Permission Denied
Log.i("wxl", "授權(quán)請求不被通過");
}
}
}
權(quán)限分組
權(quán)限那么多,如果一個(gè)個(gè)判斷,豈不是會瘋掉,如圖:
同一組的任何一個(gè)權(quán)限被授權(quán)了,其他權(quán)限也自動被授權(quán)。例如,一旦WRITE_CONTACTS被授權(quán)了,app也有READ_CONTACTS和GET_ACCOUNTS了。
附錄
Android M 新的運(yùn)行時(shí)權(quán)限開發(fā)者需要知道的一切
Android Runtime Permission測試
