Android深入学习之各种隐私权限判断和获取方法总结
16lz
2021-01-24
Android深入学习之各种隐私权限判断和获取方法总结
从Android SDK 23 开始, Android就改变了权限的管理模式。对于一些涉及用户隐私的权限则需要用户的授权才可以使用。在此之前,开发者只需要在AndroidManifest.xml中注册,如网络权限、wifi权限等等:权限即可,但是现在除了注册还需要进行手动的授权。
没有涉及用户隐私的权限申请的方式比较简单,即只需要在AndroidManifest.xml中注册,如网络权限、wifi权限等等:
本文主要研究涉及用户隐私权限的判断和申请方法,根据需要用户的操作不同,将这类权限分为三类:
- 在应用中直接打开权限申请框,由用户确定打开;
- 打开对应权限的设置页面,由用户找到指定应用并勾选;
- 打开应用对应的详情设置页面,由用户找到所需权限并打开。
1.在应用中直接打开权限申请框,由用户确定
以申请手机识别码和申请读写手机存储权限为例,具体代码如下:
boolean hasPhoneStatePermission = false;boolean hasWriteStorePermission = false;// 判断是否具有某权限的方法ContextCompat.checkSelfPermission()if (ContextCompat.checkSelfPermission()(this, Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) { hasPhoneStatePermission = true;}if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { hasWriteStorePermission = true;}if (hasPhoneStatePermission && hasWriteStorePermission) { return;}// 可一次申请多个权限的方法ActivityCompat.requestPermissions(),会依次弹出对应的权限弹框ActivityCompat.requestPermissions(this, { Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, CODE);
PS:权限必须在AndroidMainifest.xml里面声明,否则不生效:
2.打开对应权限的设置页面,由用户找到指定应用再勾选
首页需要判断是否已具有要申请的权限,不同的权限判断方法不同,需要单独区分权限,本文罗列几个常用权限通知栏读取权限、无障碍权限以及悬浮窗权限的判断方法:
是否具有通知栏读取权限判断方法:
public static boolean isNoticationEnabled(String packageName) { String allowedInfo = Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners"); if (allowedInfo == null || !allowedInfo.contains(packageName)) { return false; } else { return true; }}
是否具有无障碍权限判断方法:
public static boolean isAccessibilityServiceEnabled(String packageName) { AccessibilityManager accessibilityManager = (AccessibilityManager) getSystemService(Context.ACCESSIBILITY_SERVICE); List accessibilityServices = accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); for (AccessibilityServiceInfo info : accessibilityServices) { if (info != null && info.getId().contains(packageName)) { Toast.makeText(this, "恭喜你,你的应用已具有无障碍权限!!!", Toast.LENGTH_SHORT).show(); return true; } } return false;}
是否具有悬浮窗权限判断方法:
public static boolean checkAlertWindowsPermission(Context context) { try { Object object = context.getSystemService(Context.APP_OPS_SERVICE); if (object == null) { return false; } Class localClass = object.getClass(); Class[] arrayOfClass = new Class[3]; arrayOfClass[0] = Integer.TYPE; arrayOfClass[1] = Integer.TYPE; arrayOfClass[2] = String.class; Method method = localClass.getMethod("checkOp", arrayOfClass); if (method == null) { return false; } Object[] arrayOfObject1 = new Object[3]; arrayOfObject1[0] = 24; arrayOfObject1[1] = Binder.getCallingUid(); arrayOfObject1[2] = context.getPackageName(); int m = ((Integer) method.invoke(object, arrayOfObject1)); return m == AppOpsManager.MODE_ALLOWED; } catch (Exception ex) { } return false;}
在判断没有需要申请的权限的情况下,需要跳转到对应权限开启页面,由用户手动打开,本文罗列几个常用权限通知栏读取权限、无障碍权限以及悬浮窗权限的开启方法:
通知栏读取权限界面开启方法:
startActivity(new Intent(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS));
无障碍权限界面开启方法:
startActivity(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS));
悬浮窗权限界面开启方法:
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);intent.setData(Uri.parse("package:" + packageName)); // packageName为对应应用包名startActivity(intent);
3.打开应用对应的详情设置页面,打开需要申请的权限
首页需要判断是否已具有要申请的权限,这个类别的以通知栏显示权限的判断方法为例:
是否具有通知栏显示权限判断方法:
private static final String CHECK_OP_NO_THROW = "checkOpNoThrow";private static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";public static boolean areNotificationsEnabled(Context context) { boolean flag = true; NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= 24) { try { Class cls = Class.forName("android.app.NotificationManager"); Method method = cls.getDeclaredMethod("areNotificationsEnabled"); method.setAccessible(true); flag = (boolean) method.invoke(manager,new Object[]{}); } catch (Exception e) { e.printStackTrace(); } } else if (Build.VERSION.SDK_INT >= 19) { Object appOps = context.getSystemService("appops"); ApplicationInfo appInfo = context.getApplicationInfo(); String pkg = context.getApplicationContext().getPackageName(); int uid = appInfo.uid; try { Class<?> appOpsClass = Class.forName("android.app.AppOpsManager"); Method checkOpNoThrowMethod = appOpsClass.getMethod(CHECK_OP_NO_THROW, Integer.TYPE, Integer.TYPE, String.class); Field opPostNotificationValue = appOpsClass.getDeclaredField(OP_POST_NOTIFICATION); int value = (int) opPostNotificationValue.get(Integer.class); int v = (int) checkOpNoThrowMethod.invoke(appOps, value, uid, pkg); return v == 0; } catch (Exception e) { return true; } } return flag;}
打开应用对应的详情设置页面:
private void toSettingDetail() { Intent intent = new Intent(); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= 9) { intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); intent.setData(Uri.fromParts("package", Constants.PACKAGE_NAME, null)); } else if (Build.VERSION.SDK_INT <= 8) { intent.setAction(Intent.ACTION_VIEW); intent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails"); intent.putExtra("com.android.settings.ApplicationPkgName", packageName); // packageName为对应应用包名 } startActivity(intent);}
更多相关文章
- Android拷贝工程不覆盖原工程的配置方法
- Android(安卓)管理多个fragment(处理Activity被回收的情况)
- J2me游戏如何快速移植到Android(安卓)(2)
- 关于 android app 返回键模拟 home键 功能的介绍_仿QQ返回键 又
- 无标题文浅入浅出 Android(安卓)安全 (三) Android(安卓)本地用户
- android 地理位置共享服务
- Android的多媒体技术――MediaPlayer实现音频与视频的播放
- 【揭秘】极光推送ios、Android消息推送达率的原理
- Android热修复(一):底层替换、类加载原理总结 及 DexClassLoader类