Android 6.0动态权限大总结(续集)
来源:互联网 发布:淘宝虚拟对话生成器 编辑:程序博客网 时间:2024/06/05 21:18
前段时间写过一篇文章《Android 6.0动态权限大总结》,参考了网上众多博客文章的结晶。
在公司项目中应用时,还是被同事质疑了。当然了,是好事。后来在同事修改的基础上,我又进行了优化处理,现在看了是好用多了。下面分享下最后的工具类,和用法。
我就不上传代码了,直接贴给你看。
一、工具类:
DynamicPermissionCompat.java
/** * @Author: duke * @DateTime: 2017-06-08 10:51 * @Description: android 6.0 权限适配 */public class DynamicPermissionCompat { private Activity activity; private String[] permissions; private int requestCode; private OnPermissionListener listener; private DynamicPermissionCompat(Activity activity) { this.activity = activity; } /** * 获取实例对象(非单例) * * @param activity * @param permissionManager 此参数的目的是为了避免重复创建 * @return */ public static DynamicPermissionCompat getInstance(Activity activity, DynamicPermissionCompat permissionManager) { if (permissionManager != null) { return permissionManager; } if (activity == null) { throw new IllegalArgumentException("activity not allow null"); } return new DynamicPermissionCompat(activity); } public DynamicPermissionCompat setRequestCode(int requestCode) { this.requestCode = requestCode; return this; } public DynamicPermissionCompat setPermissions(String... permissions) { this.permissions = permissions; return this; } public DynamicPermissionCompat setOnPermissionListener(OnPermissionListener listener) { this.listener = listener; return this; } /** * 开始申请权限 */ public void start() { if (!isNeedAdapt()) { succeed(); } else if (permissions == null) { failed(new ArrayList<String>()); } else { String[] deniedPermissions = getDeniedPermissions(activity, permissions); if (deniedPermissions.length > 0) { //has没有授权 ActivityCompat.requestPermissions(activity, deniedPermissions, requestCode); } else { //全部都已经授权过了 succeed(); } } } /** * 是否需要6.0权限适配 * * @return */ private static boolean isNeedAdapt() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } /** * 向用户申请打开系统设置和浮框权限 * * @param activity * @return true:申请成功,false:申请失败 */ @TargetApi(Build.VERSION_CODES.M) public static boolean adaptWriteSettingAndOverlay(Activity activity) { if (activity == null) { //失败,不可以继续执行 return false; } if (!isNeedAdapt()) { //不需要适配,确定可以继续走 return true; } if (Settings.canDrawOverlays(activity) && Settings.System.canWrite(activity)) { //已经适配,确定可以继续走 return true; } if (!Settings.canDrawOverlays(activity)) { Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + activity.getPackageName())); activity.startActivity(intent); } if (!Settings.System.canWrite(activity)) { Intent intentWrite = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + activity.getPackageName())); activity.startActivity(intentWrite); } activity.finish(); android.os.Process.killProcess(android.os.Process.myPid()); //不确定是否打开权限,不可以继续执行,等待下次启动app来判断 return false; } /** * 是否需要申请权限 * * @param context * @param permissions * @return */ public static boolean isNeedRequestGrantPermission(Context context, String... permissions) { if (context == null || permissions == null || permissions.length == 0 || !isNeedAdapt() || getDeniedPermissions(context, permissions).length == 0) { return false; } return true; } /** * 获取未授权列表 * * @return */ private static String[] getDeniedPermissions(Context context, String... permissions) { if (context == null || permissions == null || permissions.length == 0) { return new String[]{}; } ArrayList<String> deniedList = new ArrayList<>(1); for (String permission : permissions) { if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) { deniedList.add(permission); } } return deniedList.toArray(new String[deniedList.size()]); } /** * 向用户弹出解释对话框 <br/> * ******************************************************************************* * ** 应用安装后第一次访问,直接返回false; ** * ** 第一次请求权限时用户拒绝了,下一次返回 true, ** * ** 这时候可以显示一些为什么需要这个权限的说明; ** * ** 第二次请求权限时,用户拒绝了,并选择了“不再提醒”的选项时,返回 false; ** * ** 设备的系统设置中禁止当前应用获取这个权限的授权,返回false; ** * ** 注意:第二次请求权限时,才会有“不再提醒”的选项, ** * ** 如果用户一直拒绝,并没有选择“不再提醒”的选项, ** * ** 下次请求权限时,会继续有“不再提醒”的选项,并且会一直返回true ** * ******************************************************************************* * * @param permissions 需要提示解释的权限申请 * @return 需要提示:true,不需要:false */ private static boolean shouldShowRationalePermissions(Activity activity, ArrayList<String> permissions) { if (!isNeedAdapt()) { return false; } if (activity == null || permissions == null || permissions.size() == 0) { return false; } for (String permission : permissions) { boolean rationale = ActivityCompat.shouldShowRequestPermissionRationale(activity, permission); if (rationale) { return true; } } return false; } /** * 权限授权成功 */ private void succeed() { if (listener != null) { listener.success(requestCode); } } /** * 用户拒绝了某个或者某些权限 * * @param deniedList */ private void failed(ArrayList<String> deniedList) { /** * shouldShowRationalePermissions(activity, deniedList): * true:是第一次拒绝 ~ 勾选不再提醒之前。 * false:为拒绝 ~ 勾选不再提醒之后。 */ if (!shouldShowRationalePermissions(activity, deniedList)) { if (listener != null) { listener.alwaysDenied(requestCode, deniedList); } } else { if (listener != null) { listener.failAndTipUser(requestCode, deniedList); } } } /** * 授权的回调 * * @param permissions * @param grantResults */ public void onRequestPermissionsResult(String[] permissions, int[] grantResults) { if (permissions.length != grantResults.length) { failed(null); return; } ArrayList<String> deniedList = new ArrayList<>(permissions.length); for (int i = 0; i < grantResults.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { deniedList.add(permissions[i]); } } deniedList.trimToSize(); if (deniedList.isEmpty()) { succeed(); } else { failed(deniedList); } } /** * 如果用户勾选了不再提示,打开APP设置,引导用户手动开启 */ public static void showSetting(Activity activity, int requestCode) { if (activity == null) { return; } Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); Uri uri = Uri.fromParts("package", activity.getPackageName(), null); intent.setData(uri); activity.startActivityForResult(intent, requestCode); } public static abstract class OnPermissionListener { /** * 全部授权成功 * * @param requestCode */ public abstract void success(int requestCode); /** * 有权限被拒绝,提示用户 * * @param requestCode * @param deniedPermissions 被拒绝的权限集合 */ public void failAndTipUser(int requestCode, List<String> deniedPermissions) { } /** * 用户拒绝权限,并勾选了下次不再提醒 * * @param requestCode * @param deniedPermissions 被拒绝的权限集合 */ public void alwaysDenied(int requestCode, List<String> deniedPermissions) { } }}
核心东西没变,只是封装优化了。看下面的用法吧:
permissionManager = DynamicPermissionCompat.getInstance(this, permissionManager);创建工具类对象,建议有一个Activity中创建一个对象就好。
permissionManager.setOnPermissionListener(permissionListener) .setPermissions(permissions) .setRequestCode(requestCode) .start();以构建者模式,调起授权的代码。你不用判断是否是6.0以上版本,里面的逻辑中判断了,向下兼容的。
@Overridepublic void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (permissionManager != null) { permissionManager.onRequestPermissionsResult(permissions, grantResults); }}在当前Activity或者bese Activity中重写这个函数,接受回调处理。
授权回调:private DynamicPermissionCompat.OnPermissionListener permissionListener = new DynamicPermissionCompat.OnPermissionListener() { @Override public void success(int requestCode) { boolean is1 = ApkManager.copyAssetsFileTo(ApkInstallActivity.this, "other.apk", new File(otherFilePath)); boolean is2 = ApkManager.copyAssetsFileTo(ApkInstallActivity.this, "me.apk", new File(myFilePath));// ApkManager.installApk(ApkInstallActivity.this, new File(otherFilePath)); } @Override public void failAndTipUser(int requestCode, List<String> deniedPermissions) { Toast.makeText(ApkInstallActivity.this, "用户拒绝了", Toast.LENGTH_SHORT).show(); } @Override public void alwaysDenied(int requestCode, List<String> deniedPermissions) { Toast.makeText(ApkInstallActivity.this, "用户勾选了\"不再提醒\"", Toast.LENGTH_SHORT).show(); }};
瞧瞧回调函数,里面有三个方法:授权成功、用户拒绝、用户勾选了不再提醒。
+++++++++完了,就这些。与上一版本相比,是不是简单多了?+++++++++++++++++++++++++++++++++++++++++++++++++++++
下面再说说6.0权限的另一部分吧。
其实android6.0动态权限不止普通权限、动态权限两类,还有一个系统等级的权限,这个是没办法动态申请的,但是用户不打开,程序的系统设置、系统浮窗功能就是用不了,比喻修改屏幕亮度、音量等等。如果没有权限的话,你会在控制台上看到TYPE_SYSTEM_ALERT 或 WRITE_SETTINGS等权限提示。
下面提供一个封装的工具类:
SystemSettings.java
/** * @Author: duke * @DateTime: 2017-06-16 14:25 * @Description: 系统设置工具类 <br/> * 下面三张系统表,读取时都不需要权限,写入时分别需要的权限如下 <br/> * Settings.System -- WRITE_SETTINGS <br/> * Settings.Global -- WRITE_SETTINGS or WRITE_SECURE_SETTINGS <br/> * Settings.Secure -- WRITE_SETTINGS or WRITE_SECURE_SETTINGS <br/> */public class SystemSettings { public static final String TAG = SystemSettings.class.getSimpleName(); public static boolean isNeedCompatPermission() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; } /** * 判断是否有 WRITE_SETTINGS or WRITE_SECURE_SETTINGS 权限 * * @param context * @return */ @TargetApi(Build.VERSION_CODES.M) public static boolean hasWritePermission(Context context) { if (context == null) { return false; } if (!isNeedCompatPermission() || Settings.System.canWrite(context)) { return true; } return false; } /** * 判断是否有 设置系统浮窗 权限 * * @param context * @return */ @TargetApi(Build.VERSION_CODES.M) public static boolean hasOverlaysPermission(Context context) { if (context == null) { return false; } if (!isNeedCompatPermission() || Settings.canDrawOverlays(context)) { return true; } return false; } @TargetApi(Build.VERSION_CODES.M) public static void guideUserWritePermission(Context context) { if (context == null || !isNeedCompatPermission() || hasWritePermission(context)) { return; } Intent intentWrite = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + context.getPackageName())); context.startActivity(intentWrite); } @TargetApi(Build.VERSION_CODES.M) public static void guideUserOverlaysPermission(Context context) { if (context == null || !isNeedCompatPermission() || hasOverlaysPermission(context)) { return; } Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + context.getPackageName())); context.startActivity(intent); } public static String getAndroidId(Context context) { if (context == null) { return ""; } try { return Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID); } catch (Exception e) { Log.e(TAG, "SystemSettings.getAndroidId() is exception of" + e.getMessage()); e.printStackTrace(); } return ""; } public static int getAccelerometerRotation(Context context) { if (context == null) { return 0; } try { return Settings.System.getInt(context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, 0); } catch (Exception e) { Log.e(TAG, "SystemSettings.getAccelerometerRotation() is exception of" + e.getMessage()); e.printStackTrace(); } return 0; } public static void putAccelerometerRotation(Context context, int val) { if (context == null) { return; } if (!hasWritePermission(context)) { // TODO: 2017/6/16 需确定提示文本 Toast.makeText(context, "暂无屏幕自动切换的权限", Toast.LENGTH_LONG).show(); guideUserWritePermission(context); return; } try { Settings.System.putInt(context.getContentResolver(), Settings.System.ACCELEROMETER_ROTATION, val); } catch (Exception e) { Log.e(TAG, "SystemSettings.putAccelerometerRotation() is exception of" + e.getMessage()); e.printStackTrace(); } } //使用的地方已被注释 public static int getScreenBrightness(Context context) { if (context == null) { return 0; } try { return Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0); } catch (Exception e) { Log.e(TAG, "SystemSettings.getScreenBrightness() is exception of" + e.getMessage()); e.printStackTrace(); } return 0; } //使用的地方已被注释 public static void putScreenBrightness(Context context, int val) { if (context == null) { return; } if (!hasWritePermission(context)) { // TODO: 2017/6/16 需确定提示文本 Toast.makeText(context, "暂无设置系统亮度的权限", Toast.LENGTH_LONG).show(); guideUserWritePermission(context); return; } try { Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, val); } catch (Exception e) { Log.e(TAG, "SystemSettings.putScreenBrightness() is exception of" + e.getMessage()); e.printStackTrace(); } } //使用的地方已被注释 public static int getScreenBrightnessMode(Context context) { if (context == null) { return 0; } try { return Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, 0); } catch (Exception e) { Log.e(TAG, "SystemSettings.getScreenBrightnessMode() is exception of" + e.getMessage()); e.printStackTrace(); } return 0; } //使用的地方已被注释 public static void putScreenBrightnessMode(Context context, int val) { if (context == null) { return; } if (!hasWritePermission(context)) { // TODO: 2017/6/16 需确定提示文本 Toast.makeText(context, "暂无设置系统亮度模式的权限", Toast.LENGTH_LONG).show(); guideUserWritePermission(context); return; } try { Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, val); } catch (Exception e) { Log.e(TAG, "SystemSettings.putScreenBrightnessMode() is exception of" + e.getMessage()); e.printStackTrace(); } }}
拿WRITE_SETTINGS权限来,下面大概讲解下核心部分。
public static boolean isNeedCompatPermission() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; }这是6.0的权限,也需要版本判断。
/** * 判断是否有 WRITE_SETTINGS or WRITE_SECURE_SETTINGS 权限 * * @param context * @return */ @TargetApi(Build.VERSION_CODES.M) public static boolean hasWritePermission(Context context) { if (context == null) { return false; } if (!isNeedCompatPermission() || Settings.System.canWrite(context)) { return true; } return false;判断有没有修改系统设置权限的核心方法:Settings.System.canWrite(context)
如果没有呢?
@TargetApi(Build.VERSION_CODES.M) public static void guideUserWritePermission(Context context) { if (context == null || !isNeedCompatPermission() || hasWritePermission(context)) { return; } Intent intentWrite = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS, Uri.parse("package:" + context.getPackageName())); context.startActivity(intentWrite); }通过intent,引导用户去系统设置界面了。
/** * 下面三张系统表,读取时都不需要权限,写入时分别需要的权限如下 <br/> * Settings.System -- WRITE_SETTINGS <br/> * Settings.Global -- WRITE_SETTINGS or WRITE_SECURE_SETTINGS <br/> * Settings.Secure -- WRITE_SETTINGS or WRITE_SECURE_SETTINGS <br/> */WRITE_SETTINGS权限,其实就是对Settings下的System,Global,Secure的三张表修改的权限。读取不需要权限。
故,像所有Settings.xxx.putxxx()这类方法,都需要权限。建议把所有对Settings下三张表进行读写的操作都集中到这个类里面,统一进行判断处理。例如:
public static void putScreenBrightness(Context context, int val) { if (context == null) { return; } if (!hasWritePermission(context)) { // TODO: 2017/6/16 需确定提示文本 Toast.makeText(context, "暂无设置系统亮度的权限", Toast.LENGTH_LONG).show(); guideUserWritePermission(context); return; } try { Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, val); } catch (Exception e) { Log.e(TAG, "SystemSettings.putScreenBrightness() is exception of" + e.getMessage()); e.printStackTrace(); } }
还有一个系统浮窗的权限,正在整理中,后续再发布。
阅读全文
0 0
- Android 6.0动态权限大总结(续集)
- Android 6.0动态权限大总结
- Android 7.0动态权限大总结
- android动态权限总结
- Android动态权限获取总结
- Android 6.0动态权限
- android 6.0动态权限
- android 6.0 动态权限
- Android 6.0 动态权限
- android 6.0动态权限
- Android-6.0动态权限
- android 6.0 动态权限
- Android 6.0动态权限
- Android 6.0动态权限
- android 6.0动态权限
- Android 6.0 权限总结
- Android 6.0 动态申请权限
- android 6.0权限动态管理
- SSM当JSON数据遇上懒加载
- PAT程序设计考题——甲级1001( A+B Format ) C++实现
- wildfly服务器系列--org.dom4j.DocumentFactory cannot be cast to org.dom4j.DocumentFactory报错问题的解决
- Activity生命周期
- Java程序员应该知道的10个面向对象原则(转载)
- Android 6.0动态权限大总结(续集)
- EJB学习笔记-2-Session Bean stateless/remote
- bzoj4920: 薄饼切割
- 自适应滤波器学习笔记
- smarty模板总结一
- Solr入门到熟练
- C++实现多线程及其三种方法实现多线程同步
- js小牛必备图谱
- 仿QQ记住密码,自动登录