美文网首页Android
国产定制 ROM 的终极适配,识别 ROM 并获取版本号

国产定制 ROM 的终极适配,识别 ROM 并获取版本号

作者: 渊祥 | 来源:发表于2017-08-09 10:53 被阅读750次

    前言

    相信很多安卓开发者都会或多或少地对国产的 ROM 适配感觉很头疼,尽管我们大部分的代码只要遵循安卓原生系统的规范开发,大部分情况下都会相安无事。但总会有那么一些时候,同一段代码,不是在这个某米手机上崩了,就是在某为的手机上没有效果。虽然部分原因会出现在机型上,但是跟多时候都是国产手机的定制 ROM 在作怪。

    就拿目前发现最头疼的问题来说,对于安卓权限请求失败后如何提示用户打开权限,简直是抓破头的问题。不同手机品牌(其实是 ROM)的权限设置并不一定在一个地方,很多 ROM 厂商都对权限管理做了『私人定制』,导致权限管理的界面很难被找到。如果你是真心为广大用户着想的人,那么你就应该根据不同的 ROM 厂商去适配出不同的跳转权限管理的方法。

    Android 跳转权限设置界面的终极适配(适配各大定制 ROM) 就是在方法的基础上,判断出不同的 ROM,然后尽其所能地帮助开发者辅助用户找到权限管理界面。

    那么,咱们下面先看看要怎么最大程度上的识别不同 ROM 的吧。

    蛋疼的 ROM 识别

    首先,有没有一劳永逸的 ROM 识别方法?没有!如何有的话,估计轮不到我,大神们早就给出了完美的解决方案。ps. 这就是国内的乱象,很多国内定制的东西都没有统一的标准。

    而我也只是受到启发后,踩着前人的路子,抽出本应该出去玩的时间来不断地完善和扩展,希望能够帮助开发者提升用户体验。

    言归正传,很多时候我们进行适配的时候,大部分是判断不同的手机厂商,即通过 Build.MANUFACTURER 来判断。得出来的数据是该手机的硬件厂商,即小米手机对应的是 Xiaomi。不可否认,这样的判断大多时候是正确的,毕竟大部分手机的预设系统都是自己厂商的定制系统。

    但是,这时候我要敲黑板了,作为一个追求完美的开发者来说,这是一个偷懒的行为。因为我们要适配的时候 ROM,而不是手机。作为安卓开发者来说,对刷机肯定不会陌生。一部手机上可以刷不同的 ROM,只要你喜欢折腾。尽管刷机热潮早就褪去,但是不可避免的会出现一些手机上运行的 ROM 不是该手机厂商所预设的。并且有些厂商会在根据不同的时期和机型对手机预装不同的 ROM。

    下面我来介绍如何根据 build.prop 来判断 ROM 的吧。(撤了这么多终于来干货了)

    根据 build.prop 判断不同的 ROM

    安卓系统根目录下有一些 .prop 文件,囊括了一些系统或者硬件的配置。其中 build.prop 就是我们要找一个文件。

    我们可以在代码中通过 new File(Environment.getRootDirectory(), "build.prop") 来获取这个配置文件。

    其中本人一个小米5 测试机的配置内容如下:

    ...
    ro.build.version.incremental=7.6.15
    ro.build.version.sdk=24
    ro.build.version.release=7.0
    ...
    ro.product.model=MI 5
    ro.product.brand=Xiaomi
    ...
    #
    # ADDITIONAL_BUILD_PROPERTIES
    #
    ro.miui.version.code_time=1497456000
    ro.miui.ui.version.code=6
    ro.miui.ui.version.name=V8
    ...
    ro.product.manufacturer=Xiaomi
    ...
    ro.com.google.clientidbase=android-xiaomi
    ...
    

    有内容太长了,故将大部分用省略号代替了,只留下最有用的部分。

    首先,先挑出我们可能熟悉的部分,即我们代码中 Build.MANUFACTURER 的值就是取自 o.product.manufacturer 的值, Build.BRAND 对应 ro.product.brandBuild.VERSION.SDK_INT 对应 ro.build.version.sdk,其他的不再赘述。

    大部分 ROM 定制厂商都会加上了自己定制系统的相关配置,比如最基础的版本号(ro.miui.ui.version.name)等等。我们可以通过不同 ROM 自己配置的 KEY 是否存在来判断是否是该 ROM。确认是某一 ROM 品牌之后,根据他们定制的 KEY 找出他们的 ROM 版本号。

    下面以小米为例,展示一下完整的判断代码:

       // 小米 : MIUI
       private static final String KEY_MIUI_VERSION = "ro.build.version.incremental"; // "7.6.15"
       private static final String KEY_MIUI_VERSION_NANE = "ro.miui.ui.version.name"; // "V8"
       private static final String KEY_MIUI_VERSION_CODE = "ro.miui.ui.version.code"; // "6"
       private static final String VALUE_MIUI_CLIENT_ID_BASE = "android-xiaomi";
    
       public static ROM getRomType() {
           ROM rom = ROM.Other;
           FileInputStream is = null;
           try {
               Properties buildProperties = new Properties();
               is = new FileInputStream(new File(Environment.getRootDirectory(), "build.prop"));
               buildProperties.load(is);
    
               if (buildProperties.containsKey(KEY_MIUI_VERSION_NANE) || buildProperties.containsKey(KEY_MIUI_VERSION_CODE)) {
                   // MIUI
                   rom = ROM.MIUI;
                   if (buildProperties.containsKey(KEY_MIUI_VERSION_NANE)) {
                       String versionName = buildProperties.getProperty(KEY_MIUI_VERSION_NANE);
                       if (LshStringUtils.notEmpty(versionName) && versionName.matches("[Vv]\\d+")) { // V8
                           try {
                               rom.setBaseVersion(Integer.parseInt(versionName.split("[Vv]")[1]));
                           } catch (Exception e) {
                               e.printStackTrace();
                           }
                       }
                   }
                   if (buildProperties.containsKey(KEY_MIUI_VERSION)) {
                       String versionStr = buildProperties.getProperty(KEY_MIUI_VERSION);
                       if (LshStringUtils.notEmpty(versionStr) && versionStr.matches("[\\d.]+")) {
                           rom.setVersion(versionStr);
                       }
                   }
               }  else if (buildProperties.containsKey(KEY_CLIENT_ID_BASE)) {
                   String clientIdBase = buildProperties.getProperty(KEY_CLIENT_ID_BASE);
                   switch (clientIdBase) {
                       case VALUE_MIUI_CLIENT_ID_BASE:
                           return ROM.MIUI;
                   }
               }
           } catch (IOException e) {
               e.printStackTrace();
           } finally {
               LshIOUtils.close(is);
           }
           return rom;
       }
    

    根据系统应用包名判断不同的 ROM

    这是自己偶然间发现的一个很不错的方法,因为不同的定制 ROM 系统都会把很多原生的系统应用去掉,开发自己的系统应用,原因很大程度上是为了『符合国情』吧。

    所以,通过遍历所有系统应用,通过判断是否有某 ROM 的某些特定系统应用,也可判断出不同的 ROM 系统。

    由于最近比较忙,还没有付出实践,所以还没有将这种方法整合到代码当中。等忙过这几天,我会重新整合代码的。

    详细的代码已经抽取到工具类并上传到 GitHub,如有建议或问题,欢迎提 Issues 或 Pull requests。

    OSUtils - 适配国产定制 ROM

    随便提一下自己花了大量心血收集整理的工具类,本篇文章提到的 LshOSUtils 已经收集到该工具类,其中还包括许多其他日常经常使用到的工具类。在此不多赘述,感兴趣的可以点击下面链接查看。

    https://github.com/SenhLinsh/Utils-Everywhere

    相关文章

      网友评论

      • 闪耀的昌平野人:感谢lz分享,华为emui3.0我这里有区别,代码我改了下:
        String versionStr = buildProperties.getProperty(KEY_EMUI_VERSION);
        Matcher matcher1 = Pattern.compile("EmotionUI_([\\d.]+)").matcher(versionStr); // EmotionUI_3.0
        Matcher matcher2 = Pattern.compile("EmotionUI ([\\d.]+)").matcher(versionStr); // EmotionUI 3.0
        if (!TextUtils.isEmpty(versionStr)) {
        String version = null;
        if (matcher1.find()) {
        version = matcher1.group(1);
        } else if (matcher2.find()) {
        version = matcher2.group(1);
        }
        if (version != null) {
        rom.setVersion(version);
        rom.setBaseVersion(Integer.parseInt(version.split("\\.")[0]));
        }
        }
        渊祥:好的,多谢提醒~ 因为 ROM 识别较为麻烦,我近期已经将这个功能单独抽取出来成立新的项目,欢迎关注 https://github.com/SenhLinsh/Android-ROM-Identifier(未开发完成)
      • zac4j:这个真是好东西啊,多谢:joy:

      本文标题:国产定制 ROM 的终极适配,识别 ROM 并获取版本号

      本文链接:https://www.haomeiwen.com/subject/wrfwlxtx.html