58同城厂商内置包大小减少实战

作者: 于卫国 | 来源:发表于2019-09-26 10:43 被阅读0次

    本文介绍了几种减少包大小的技术方案,希望能够帮到你。

    本文首发:http://yuweiguocn.github.io/

    《虞美人·春花秋月何时了》
    春花秋月何时了?往事知多少。
    小楼昨夜又东风,故国不堪回首月明中。
    雕栏玉砌应犹在,只是朱颜改。
    问君能有几多愁?恰似一江春水向东流。
    -五代,李煜

    前言

    何为厂商内置包?厂商内置包是公司和厂商之间的一种商务合作,可以将应用内置到出厂的手机上,可以带来新增用户和提升日活。

    58同城每年都会基于线上最新版本按照厂商的要求做出厂商内置包,毕竟会占用用户的存储空间,所以厂商对于包大小有着严格的要求,随着时间的推进和应用版本不断的迭代更新,应用大小变得越来越大,满足厂商包大小的要求也越来越困难。

    备注:应用通常会预装到较高系统版本的手机上,例如android 9.0及以上版本,所以我们只需要考虑android 9.0及以上版本的兼容性即可。

    保留指定资源

    先来看一下如何配置,在gradle文件中配置我们需要保留的资源。

    android {
        defaultConfig {
            ...
            resConfigs "zh", "xxhdpi", "ldltr", "desk"
        }
    }
    

    接下来对上述配置进行一一说明,由于依赖的support库包含了很多其它非中文资源,所以我们添加了zh配置用于只保留中文资源,添加上这个配置后竟然减少了1M的大小。

    添加xxhdpi配置用于只保留一套图片资源,例如如果有xhdpi和xxhdpi的两套图片,会只保留xxhdpi的图片,如果有hdpi和xhdpi两套图片,会只保留xhdpi的图片。

    如果应用没有适配RTL(从右到左)布局,可以在清单文件添加以下属性禁止RTL布局方式:

    <application
      ...
      android:supportsRtl="false" />
    

    如果应用使用了react native,可以添加下面的代码禁用RTL布局:

    //禁止RN页面RTL
    I18nUtil sharedI18nUtilInstance = I18nUtil.getInstance();
    sharedI18nUtilInstance.allowRTL(mApplication, false);
    

    相应的RTL的资源也可以通过添加ldltr配置移除。

    如果应用没有适配watch手表,可以通过添加desk配置将watch相关资源移除。

    图片转为WebP

    Android从4.3开始对于WebP的decode、encode是完全支持的,包括半透明的WebP图片。所以可以使用Android Studio自带的工具将工程内的图片转换为WebP,压缩比可以采用75%。

    工程内的图片可以手动转换,对于依赖的第三库中图片怎么办?

    可以使用开源库https://github.com/smallSohoSolo/McImage,McImage可以在打包过程中对图片进行压缩,也可以将图片转换为WebP格式。

    自动化清理无用资源

    通过lint可以检测出工程无用资源的结果,使用python脚本可以自动化清理无用资源。传送门:https://github.com/yuweiguocn/android-resource-remover

    使用lint检查无用资源

    通常我们可以使用lint检查工程内无用资源,但执行lint命令发现只检查了主Module的无用资源,并没有检查子Module的无用资源。

    针对这个问题可以使用下面的配置,对应用的依赖也执行检查:

    lintOptions {
        checkReleaseBuilds false
        abortOnError false
        checkDependencies true //对依赖的资源也执行检查,注意也会对引用aar检查,如果是子module打开源码依赖即可
        check "UnusedResources" //只检查无用资源,提升执行速度
    }
    

    然后执行lint命令进行检查无用资源:

    ./gradlew lint
    

    然后我们可以在build下的reports目录下找到lint的结果。

    配置

    首先将本工程clone到你的项目工程的根目录中,然后根据你项目使用反射获取的资源在resouceCleanConfig.json文件中进行配置:

    {
        "projects": [
            "/app/",
            "/push/"
        ],
        "pathIncludes": [
            ".jpg",
            ".png",
            ".xml"
        ],
        "pathExcludes": [
            "------common-config-start--------",
            "/layout/"
        ]
    }
    
    • projects:表示要清理无用资源的路径需要包含的子Module工程名称,因为依赖检查也会对引用的所有aar进行检查,所以我们需要指定打开源码的子Module的名称。
    • pathIncludes:表示要清理的无用资源的路径需要匹配的规则。
    • pathExcludes:表示要清理的无用资源的路径不能包含的字符串,也就是白名单。

    以上三个条件为并列条件,只有同时满足才会被清理。上述json配置的文件表示清理app和push Module下文件后缀为.jpg或.png或xml的资源,但不删除布局文件。

    白名单

    目前发现工程使用代码获取资源的方法有以下两种,代码中使用下列方法获取的图片名称需要添加配置文件白名单中。

    //第一种
    item.resId = mContext.getResources().getIdentifier(name, "drawable", mContext.getPackageName());
    //第二种
    public static Integer getResourceDrawableId(String resource) {
        if(TextUtils.isEmpty(resource)){
            return -1;
        }
        try {
            String name = resource.trim();
            Field field = R.drawable.class.getField(name);
            return field.getInt(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return -1;
    }
    

    建议对新增的资源在使用代码获取时对名称添加统一前缀reflect_

    自动化

    此步骤请谨慎操作,删除的资源无法恢复,使用前请添加版本控制。

    配置好后执行如下命令自动清理无用资源:

    python android_clean_app.py --xml ../app/build/reports/lint-results.xml
    

    参数--xml指定为你的lint结果文件的路径。

    解决打包失败问题

    lint的检测结果包含无用代码对资源的引用,如果只是将无用资源删除后可能会引起打包失败。
    针对这个问题我们会自动添加一个unused_ids.xml文件保存删除的资源id,这不仅可以保证不会由于删除无用资源引起的打包失败,也对自动清理的无用资源进行了记录。

    总结

    58同城厂商内置包使用了上述的减少包大小的方案,配合移除so文件较大的依赖库功能,最终满足了厂商对包大小的要求。

    参考

    相关文章

      网友评论

        本文标题:58同城厂商内置包大小减少实战

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