对于动态权限,大家应该都不陌生了,在Android6.0版本加入了动态权限的概念,在Android 6.0之前申明权限只需要在AndroidManifest清单中注册相应权限就可以;Android 6.0以上系统就需要根据权限的等级(普通权限和危险权限)进行权限注册,如果是普通权限还是依照之前的处理方式直接在AndroidManifest清单中注册即可,但是危险权限不仅需要在AndroidManifest清单中注册且还需要在使用时动态申请;
权限分级清单见
https://yilanjingwang.blog.csdn.net/article/details/102992896
其实现在主流权限管理框架有三个,分别为PermissionsDispatcher、RxPermissions(基于RxJava)和easypermissions(谷歌出品,必是XX);但是我比较推荐使用PermissionsDispatcher(因为它使用起来更简单,尤其是配合插件使用)。
添加依赖:
java:
dependencies {
implementation "org.permissionsdispatcher:permissionsdispatcher:${latest.version}"
annotationProcessor "org.permissionsdispatcher:permissionsdispatcher-processor:${latest.version}"
}
With Kotlin(advance with the times):
apply plugin: 'kotlin-kapt'
dependencies {
implementation "org.permissionsdispatcher:permissionsdispatcher:${latest.version}"
kapt "org.permissionsdispatcher:permissionsdispatcher-processor:${latest.version}"
}
另外如果还没用AndroidX的请用3.x的版本。
install之后restart(如果找不到位置,请自行百度……)
使用插件的方式很简单,在activity/fragment中右键
Usage with Kotlin
Here’s a minimum example, in which you register a MainActivity which requires Manifest.permission.CAMERA.
0. Prepare AndroidManifest
Add the following line to AndroidManifest.xml:
1. Attach annotationsPermissionsDispatcher introduces only a few annotations, keeping its general API concise:
NOTE: Annotated methods must not be private.
Annotation | Required | Description |
---|---|---|
@RuntimePermissions | ✓ | Register an Activity or Fragment to handle permissions |
@NeedsPermission | ✓ | Annotate a method which performs the action that requires one or more permissions |
@OnShowRationale | Annotate a method which explains why the permissions are needed. It passes in a PermissionRequest object which can be used to continue or abort the current permission request upon user input. If you don’t specify any argument for the method compiler will generate process N e e d s P e r m i s s i o n M e t h o d N a m e P r o c e s s R e q u e s t a n d c a n c e l {NeedsPermissionMethodName}ProcessRequest and cancel NeedsPermissionMethodNameProcessRequestandcancel{NeedsPermissionMethodName}ProcessRequest. You can use those methods in place of PermissionRequest(ex: with DialogFragment) | |
@OnPermissionDenied | Annotate a method which is invoked if the user doesn’t grant the permissions | |
@OnNeverAskAgain | Annotate a method which is invoked if the user chose to have the device “never ask again” about a permission |
@RuntimePermissions
class MainActivity : AppCompatActivity(), View.OnClickListener {
@NeedsPermission(Manifest.permission.CAMERA)
fun showCamera() {
supportFragmentManager.beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
.addToBackStack("camera")
.commitAllowingStateLoss()
}
@OnShowRationale(Manifest.permission.CAMERA)
fun showRationaleForCamera(request: PermissionRequest) {
showRationaleDialog(R.string.permission_camera_rationale, request)
}
@OnPermissionDenied(Manifest.permission.CAMERA)
fun onCameraDenied() {
Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_SHORT).show()
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
fun onCameraNeverAskAgain() {
Toast.makeText(this, R.string.permission_camera_never_askagain, Toast.LENGTH_SHORT).show()
}
}
Now generated functions become much more concise and intuitive than Java version!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById(R.id.button_camera).setOnClickListener {
// NOTE: delegate the permission handling to generated function
showCameraWithPermissionCheck()
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
// NOTE: delegate the permission handling to generated function
onRequestPermissionsResult(requestCode, grantResults)
}
Usage with Java
Here’s a minimum example, in which you register a MainActivity which requires Manifest.permission.CAMERA.
0. Prepare AndroidManifest
Add the following line to AndroidManifest.xml:
1. Attach annotationsPermissionsDispatcher introduces only a few annotations, keeping its general API concise:
NOTE: Annotated methods must not be private.
Annotation | Required | Description |
---|---|---|
@RuntimePermissions | ✓ | Register an Activity or Fragment to handle permissions |
@NeedsPermission | ✓ | Annotate a method which performs the action that requires one or more permissions |
@OnShowRationale | Annotate a method which explains why the permissions are needed. It passes in a PermissionRequest object which can be used to continue or abort the current permission request upon user input. If you don’t specify any argument for the method compiler will generate process N e e d s P e r m i s s i o n M e t h o d N a m e P r o c e s s R e q u e s t a n d c a n c e l {NeedsPermissionMethodName}ProcessRequest and cancel NeedsPermissionMethodNameProcessRequestandcancel{NeedsPermissionMethodName}ProcessRequest. You can use those methods in place of PermissionRequest(ex: with DialogFragment) | |
@OnPermissionDenied | Annotate a method which is invoked if the user doesn’t grant the permissions | |
@OnNeverAskAgain | Annotate a method which is invoked if the user chose to have the device “never ask again” about a permission |
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
@NeedsPermission(Manifest.permission.CAMERA)
void showCamera() {
getSupportFragmentManager().beginTransaction()
.replace(R.id.sample_content_fragment, CameraPreviewFragment.newInstance())
.addToBackStack("camera")
.commitAllowingStateLoss();
}
@OnShowRationale(Manifest.permission.CAMERA)
void showRationaleForCamera(final PermissionRequest request) {
new AlertDialog.Builder(this)
.setMessage(R.string.permission_camera_rationale)
.setPositiveButton(R.string.button_allow, (dialog, button) -> request.proceed())
.setNegativeButton(R.string.button_deny, (dialog, button) -> request.cancel())
.show();
}
@OnPermissionDenied(Manifest.permission.CAMERA)
void showDeniedForCamera() {
Toast.makeText(this, R.string.permission_camera_denied, Toast.LENGTH_SHORT).show();
}
@OnNeverAskAgain(Manifest.permission.CAMERA)
void showNeverAskForCamera() {
Toast.makeText(this, R.string.permission_camera_neverask, Toast.LENGTH_SHORT).show();
}
}
Upon compilation, PermissionsDispatcher generates a class for MainActivityPermissionsDispatcher([Activity Name] + PermissionsDispatcher), which you can use to safely access these permission-protected methods.
The only step you have to do is delegating the work to this helper class:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.button_camera).setOnClickListener(v -> {
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.showCameraWithPermissionCheck(this);
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}