Android 跳转权限设置界面的终极适配(适配各大定制 ROM)

前言

在我们请求用户权限时,很有可能会被用户有意无意地点了拒绝,而这个权限恰恰又是当前操作所以必须的,所以一般我们都会希望用户能手动去打开权限,以便我们能顺利的执行业务逻辑。

那么问题来了,我们要怎么快速地引导用户打开我们需要的权限呢。直接跟用户说我们需要这个权限,你给我去打开?别开玩笑了,有太多的用户根本找不到权限的开关,折腾了半天一无所获,然后放弃了这个操作,甚至放弃了这个应用。

还有没有更好的办法?目前很多一些应用都是采用提示法,告诉用户应该去『设置 - 应用列表 - 本应用 - 权限管理』中打开某某权限,还有一些会辅助跳转『应用信息』或者『应用列表』,再让用户自己找。

这些方法确实在一定程度上帮助了用户找到相应的权限开关,但是我觉得这还不够。为什么呢?因为在目前国内一些 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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,716评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,558评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,431评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,127评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,511评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,692评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,915评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,664评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,412评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,616评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,105评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,424评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,098评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,096评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,869评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,748评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,641评论 2 271