前言
在我们请求用户权限时,很有可能会被用户有意无意地点了拒绝,而这个权限恰恰又是当前操作所以必须的,所以一般我们都会希望用户能手动去打开权限,以便我们能顺利的执行业务逻辑。
那么问题来了,我们要怎么快速地引导用户打开我们需要的权限呢。直接跟用户说我们需要这个权限,你给我去打开?别开玩笑了,有太多的用户根本找不到权限的开关,折腾了半天一无所获,然后放弃了这个操作,甚至放弃了这个应用。
还有没有更好的办法?目前很多一些应用都是采用提示法,告诉用户应该去『设置 - 应用列表 - 本应用 - 权限管理』中打开某某权限,还有一些会辅助跳转『应用信息』或者『应用列表』,再让用户自己找。
这些方法确实在一定程度上帮助了用户找到相应的权限开关,但是我觉得这还不够。为什么呢?因为在目前国内一些 ROM 中,权限开关根本不在『应用信息』或者『应用列表』里,他们另起炉灶,把权限管理放在了『安全中心』、『手机管家』、『权限管理』等一些系统应用入口中管理。虽然这样的定制方便了用户对权限的管理,却让开发者深感头疼,它们的权限管理界面既没有统一的名称,也没有统一的 API 来跳转。所以必须根据不同的国产 ROM (甚至是同一种 ROM 的不同版本)来定制不同的权限跳转或者提示方案。
关于识别 ROM 并获取其版本号的方案,可见 国产定制 ROM 的终极适配,识别 ROM 并获取版本号 。
权限界面的跳转
关于权限的界面跳转方面,我一开始的思路是参考了 『Android各大手机品牌手机跳转到权限管理界面』这篇文章。
通过 『ActivityTracker』来获取不同 ROM (甚至需要适配 ROM 版本)的权限界面组件名并进行跳转。部分 ROM 无法进行跳转的,和根据情况跳转到最方便用户操作的界面,比如可以通过『应用信息』界面进去的,可以跳转至『应用信息』在做进一步的提示即可。
public static boolean gotoPermissionSetting() {
boolean success = true;
Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
String packageName = LshAppUtils.getPackageName();
LshOSUtils.ROM romType = LshOSUtils.getRomType();
switch (romType) {
case EMUI: // 华为
intent.putExtra("packageName", packageName);
intent.setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity"));
break;
case Flyme: // 魅族
intent.setAction("com.meizu.safe.security.SHOW_APPSEC");
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.putExtra("packageName", packageName);
break;
case MIUI: // 小米
String rom = getMiuiVersion();
if ("V6".equals(rom) || "V7".equals(rom)) {
intent.setAction("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity");
intent.putExtra("extra_pkgname", packageName);
} else if ("V8".equals(rom) || "V9".equals(rom)) {
intent.setAction("miui.intent.action.APP_PERM_EDITOR");
intent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity");
intent.putExtra("extra_pkgname", packageName);
} else {
intent = getAppDetailsSettingsIntent(packageName);
}
break;
case Sony: // 索尼
intent.putExtra("packageName", packageName);
intent.setComponent(new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity"));
break;
case ColorOS: // OPPO
intent.putExtra("packageName", packageName);
intent.setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.PermissionManagerActivity"));
break;
case EUI: // 乐视
intent.putExtra("packageName", packageName);
intent.setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps"));
break;
case LG: // LG
intent.setAction("android.intent.action.MAIN");
intent.putExtra("packageName", packageName);
ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity");
intent.setComponent(comp);
break;
case SamSung: // 三星
case SmartisanOS: // 锤子
gotoAppDetailSetting(packageName);
break;
default:
intent.setAction(Settings.ACTION_SETTINGS);
LshLogUtils.i("没有适配该机型, 跳转普通设置界面");
success = false;
break;
}
try {
LshContextUtils.startActivity(intent);
} catch (Exception e) {
e.printStackTrace();
// 跳转失败, 前往普通设置界面
LshIntentUtils.gotoSetting();
success = false;
LshLogUtils.i("无法跳转权限界面, 开始跳转普通设置界面");
}
return success;
}
private static String getMiuiVersion() {
String propName = "ro.miui.ui.version.name";
String line;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + propName);
input = new BufferedReader(
new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
ex.printStackTrace();
return null;
} finally {
LshIOUtils.close(input);
}
LshLogUtils.i("MiuiVersion = " + line);
return line;
}
致歉
由于公司测试设备和个人时间问题,在权限跳转方面目前只测试成功了小米(V7 V8 V9)、华为、三星、锤子、魅族等机型,OPPO 机型目前没有成功跳转。所以在代码和适配方面仍需要继续进行开发和维护。由于目前的公司业务在适配方面的要求并不严格,所以近期内可能没有继续研究适配下去的希望。希望小伙伴们能给一些点赞和支持,如果发现自己的研究能被人所有还是很有动力的。
目前暂定喜欢数超过 10 算是得到大家肯定,继续把跳转步骤进行完整的封装,并适配主流 ROM 系统。希望觉得这篇文章有用的朋友不要吝啬点个喜欢就行,这也算是自己在开源项目的开发上得到的巨大鼓舞了吧。
附
关于权限跳转的详细代码已经抽取到个人工具类并上传到 GitHub,如有建议或问题,欢迎提 Issues 或 Pull requests。
本篇文章代码所在工具类:IntentUtils
随便提一下自己花了大量心血收集整理的工具类,本篇文章提到的 LshOSUtils 已经收集到该工具类,其中还包括许多其他日常经常使用到的工具类。在此不多赘述,感兴趣的可以点击下面链接查看。
个人收集的常用工具类:Utils-Everywhere