新的运行时权限仅当我们设置targetSdkVersion to 23才起作用,app在6.0之前的设备依然使用旧的权限系统。
如果app的targetSdkVersion 低于 23,那将被认为app没有用23新权限测试过,那将被继续使用旧有规则:用户在安装的时候不得不接受所有权限,安装后app就有了那些权限!然后app像以前一样可以正常运行!注意,此时用户依然可以取消已经同意的授权!用户取消授权时,android 6.0系统会警告,但这不妨碍用户取消授权。
问题又来了,这时候你的app崩溃了!
同一组的任何一个权限被授权了,其他权限也自动被授权。
权限组列表:
Permission Group | Permissions |
---|---|
android.permission-group.CALENDAR |
|
android.permission-group.CAMERA |
|
android.permission-group.CONTACTS |
|
android.permission-group.LOCATION |
|
android.permission-group.MICROPHONE |
|
android.permission-group.PHONE |
|
android.permission-group.SENSORS |
|
android.permission-group.SMS |
|
android.permission-group.STORAGE |
|
android.permission.ACCESS_LOCATION_EXTRA_COMMANDS
android.permission.ACCESS_NETWORK_STATE
android.permission.ACCESS_NOTIFICATION_POLICY
android.permission.ACCESS_WIFI_STATE
android.permission.ACCESS_WIMAX_STATE
android.permission.BLUETOOTH
android.permission.BLUETOOTH_ADMIN
android.permission.BROADCAST_STICKY
android.permission.CHANGE_NETWORK_STATE
android.permission.CHANGE_WIFI_MULTICAST_STATE
android.permission.CHANGE_WIFI_STATE
android.permission.CHANGE_WIMAX_STATE
android.permission.DISABLE_KEYGUARD
android.permission.EXPAND_STATUS_BAR
android.permission.FLASHLIGHT
android.permission.GET_ACCOUNTS
android.permission.GET_PACKAGE_SIZE
android.permission.INTERNET
android.permission.KILL_BACKGROUND_PROCESSES
android.permission.MODIFY_AUDIO_SETTINGS
android.permission.NFC
android.permission.READ_SYNC_SETTINGS
android.permission.READ_SYNC_STATS
android.permission.RECEIVE_BOOT_COMPLETED
android.permission.REORDER_TASKS
android.permission.REQUEST_INSTALL_PACKAGES
android.permission.SET_TIME_ZONE
android.permission.SET_WALLPAPER
android.permission.SET_WALLPAPER_HINTS
android.permission.SUBSCRIBED_FEEDS_READ
android.permission.TRANSMIT_IR
android.permission.USE_FINGERPRINT
android.permission.VIBRATE
android.permission.WAKE_LOCK
android.permission.WRITE_SYNC_SETTINGS
com.android.alarm.permission.SET_ALARM
com.android.launcher.permission.INSTALL_SHORTCUT
com.android.launcher.permission.UNINSTALL_SHORTCUT
好了,下面我们来使用PermissionsDispatcher进行管理Android权限。
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 permission/s is/are needed. It passes in a PermissionRequest object which can be used to continue or abort the current permission request upon user input/ | |
@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/ | |
比如我们在MainActivity中使用,那么我们的MainActivity应该是这样的:
@RuntimePermissions public class MainActivity extends AppCompatActivity implements Runnable{ @NeedsPermission(Manifest.permission.READ_EXTERNAL_STORAGE) void doACacheNeedsPermission() { //处理当用户允许该权限时需要处理的方法 } @OnShowRationale(Manifest.permission.READ_EXTERNAL_STORAGE) void ACacheShowRationale(PermissionRequest request) { request.proceed(); // 提示用户权限使用的对话框 } @OnNeverAskAgain(Manifest.permission.READ_EXTERNAL_STORAGE) void ACacheOnNeverAskAgain() { Toast.makeText(this, "ACacheOnNeverAskAgain, Toast.LENGTH_SHORT).show(); } /** * 如果用户拒绝该权限执行的方法 */ @OnPermissionDenied(Manifest.permission.READ_EXTERNAL_STORAGE) void ACacheOnPermissionDenied() { Toast.makeText(this, "ACacheOnPermissionDenied", Toast.LENGTH_SHORT).show(); } /** * 权限请求回调,提示用户之后,用户点击“允许”或者“拒绝”之后调用此方法 * @param requestCode 定义的权限编码 * @param permissions 权限名称 * @param grantResults 允许/拒绝 */ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults); } }
我们看到了该Activity继承了AppCompatActivity,是的,如果使用PermissionsDispatcher进行权限管理,那么Activity就要继承AppCompatActivity。这就要使用到了兼容包里的类了。同样此时相应Activity中使用的主题,也需要进行修改,修改成相应兼容包里的主题。
那么我们来看看MainActivityPermissionsDispatcher类中是如何实现权限管理的,默认是没有此类的,需要编译下才会有此类。
final class MainActivityPermissionsDispatcher { //定义的权限编码,当PERMISSION_DOACACHENEEDSPERMISSION有N个权限,那么REQUEST_DOACACHENEEDSPERMISSION就会有多少值 private static final int REQUEST_DOACACHENEEDSPERMISSION = 1; //需要请求的权限名称 private static final String[] PERMISSION_DOACACHENEEDSPERMISSION = new String[] {"android.permission.READ_EXTERNAL_STORAGE"}; private MainActivityPermissionsDispatcher() { } /** * 检查用户设备是否拥有该权限 * @param target */ static void doACacheNeedsPermissionWithCheck(MainActivity target) { // 如果拥有该权限,那么调用用户注解为:@NeedsPermission的方法 if (PermissionUtils.hasSelfPermissions(target, PERMISSION_DOACACHENEEDSPERMISSION)) { target.doACacheNeedsPermission(); } else { // 如果用户设备没有该权限,那么请求提示用户是否赋予该权限 if (PermissionUtils.shouldShowRequestPermissionRationale(target, PERMISSION_DOACACHENEEDSPERMISSION)) { target.ACacheShowRationale(new DoACacheNeedsPermissionPermissionRequest(target)); } else { ActivityCompat.requestPermissions(target, PERMISSION_DOACACHENEEDSPERMISSION, REQUEST_DOACACHENEEDSPERMISSION); } } } /** * 权限请求回调 * @param target * @param requestCode 权限编码 * @param grantResults */ static void onRequestPermissionsResult(MainActivity target, int requestCode, int[] grantResults) { switch (requestCode) { case REQUEST_DOACACHENEEDSPERMISSION: if (PermissionUtils.getTargetSdkVersion(target) < 23 && !PermissionUtils.hasSelfPermissions(target, PERMISSION_DOACACHENEEDSPERMISSION)) { target.ACacheOnPermissionDenied(); return; } if (PermissionUtils.verifyPermissions(grantResults)) { target.doACacheNeedsPermission(); } else { if (!PermissionUtils.shouldShowRequestPermissionRationale(target, PERMISSION_DOACACHENEEDSPERMISSION)) { target.ACacheOnNeverAskAgain(); } else { target.ACacheOnPermissionDenied(); } } break; default: break; } } private static final class DoACacheNeedsPermissionPermissionRequest implements PermissionRequest { private final WeakReference<MainActivity> weakTarget; private DoACacheNeedsPermissionPermissionRequest(MainActivity target) { this.weakTarget = new WeakReference<>(target); } @Override public void proceed() { MainActivity target = weakTarget.get(); if (target == null) return; ActivityCompat.requestPermissions(target, PERMISSION_DOACACHENEEDSPERMISSION, REQUEST_DOACACHENEEDSPERMISSION); } @Override public void cancel() { MainActivity target = weakTarget.get(); if (target == null) return; target.ACacheOnPermissionDenied(); } } }
那么如果需要使用PermissionsDispatcher,需要在project的 build.gradle中添加
buildscript { dependencies { classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' } }
然后在app module中的build.gradle中添加:(必须在app module中添加)
apply plugin: 'android-apt' dependencies { compile 'com.github.hotchemi:permissionsdispatcher:${latest.version}' apt 'com.github.hotchemi:permissionsdispatcher-processor:${latest.version}' }
目前
${latest.version}
最新的是2.0.8。
最后奉上该库的github地址:https://github.com/hotchemi/PermissionsDispatcher
好了,PermissionsDispatcher的使用基本如此。希望可以帮助到大家,如果有不对的地方还望提出。