1.清单配置需要的权限:在AndroidManifest.xml中申请需要的权限
如:
...
2.检查是否拥有申请的权限
if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.WRITE_CALENDAR)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
}
在Android 10上,如果不进行checkSelfPermission而直接申请权限,可能出现permissions revoked而导致进程被kill:
04-15 14:01:56.574 992 4007 I ActivityManager: Killing 18761:com.android.messaging/u0a89 (adj 100): permissions revoked
具体现象为:在应用使用过程中,需要用到某些运行时权限,然后应用进行申请。但是在权限框弹出前,应用闪退或是黑屏接着显示权限申请框。
同样的应用在Android 9上没有这个问题;在Android 10上才存在这个问题。
关于checkSelfPermission,在Context中定义的抽象方法,在ContextImpl中实现(具体的关联下次再总结).
(Activity extends ContextThemeWrapper extends ContextWrapper extends Context)
3.没有权限,去申请权限
// Here, thisActivity is the current activity
if (ContextCompat.checkSelfPermission(thisActivity,
Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED) {
// Permission is not granted
// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
Manifest.permission.READ_CONTACTS)) {
// Show an explanation to the user *asynchronously* -- don't block
// this thread waiting for the user's response! After the user
// sees the explanation, try again to request the permission.
} else {
// No explanation needed; request the permission
ActivityCompat.requestPermissions(thisActivity,
new String[]{Manifest.permission.READ_CONTACTS},
MY_PERMISSIONS_REQUEST_READ_CONTACTS);
// MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
// app-defined int constant. The callback method gets the
// result of the request.
}
} else {
// Permission has already been granted
}
关于requestPermissions,在Activity中实现,具体如下:
public final void requestPermissions(@NonNull String[] permissions, int requestCode) {
if (requestCode < 0) {
throw new IllegalArgumentException("requestCode should be >= 0");
}
if (mHasCurrentPermissionsRequest) {
Log.w(TAG, "Can request only one set of permissions at a time");
// Dispatch the callback with empty arrays which means a cancellation.
onRequestPermissionsResult(requestCode, new String[0], new int[0]); //具体的Activity中实现
return;
}
Intent intent = getPackageManager().buildRequestPermissionsIntent(permissions);
startActivityForResult(REQUEST_PERMISSIONS_WHO_PREFIX, intent, requestCode, null);
mHasCurrentPermissionsRequest = true;
}
关于buildRequestPermissionsIntent,在PackageManager中实现:
public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
if (ArrayUtils.isEmpty(permissions)) {
throw new IllegalArgumentException("permission cannot be null or empty");
}
// ACTION_REQUEST_PERMISSIONS:
// public static final String ACTION_REQUEST_PERMISSIONS =
// "android.content.pm.action.REQUEST_PERMISSIONS";
// PackageInstaller中的GrantPermissionsActivity匹配这个Action
// 所以会打开PackageInstaller的GrantPermissionsActivity进行权限申请
// 也就是我们最常看见的权限申请界面了
Intent intent = new Intent(ACTION_REQUEST_PERMISSIONS);
intent.putExtra(EXTRA_REQUEST_PERMISSIONS_NAMES, permissions);
intent.setPackage(getPermissionControllerPackageName());
return intent;
}
4.覆写onRequestPermissionsResult方法,根据requestCode,permissions,grantResults判断我们是否申请成功
@Override
public void onRequestPermissionsResult(int requestCode,
String[] permissions, int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// permission was granted, yay! Do the
// contacts-related task you need to do.
} else {
// permission denied, boo! Disable the
// functionality that depends on this permission.
}
return;
}
// other 'case' lines to check for other
// permissions this app might request.
}
}
5.拒绝的时候利用shouldShowRequestPermissionRationale判断是否勾选'不再询问'
shouldShowRequestPermissionRationale在Activity中有定义,具体实现在PackageManagerService中。
6.如果勾选'不再询问',下次再申请此权限时默认返回拒绝。
需自定义dialog,让用户去设置里面开启权限。