APK瘦身之九道工序

作者: BrotherTree | 来源:发表于2019-02-26 17:16 被阅读321次

    随着业务不断的增加,需求不断的迭代,我们的APP的体积也在不断的变大,越往后就越成长为一个庞然大物,此时开发者就需要关注到这个问题:如何在不影响使用功能的情况下精简APP的大小?还有就是。。。

    我为什么没有从项目一开始就注意体积优化
    
    image.png
    1. SVG

    Scalable Vector Graphics 可缩放矢量图,详情见谷歌官方文档
    SVG不会像位图一样因为缩放而让图片质量下降,优点在于节约空间和内存,常用于小图标。

    image.png
    image.png

    如果我们选择了Local file,使用了PSD文件,需要注意的是此时的SVG是不支持渐变和透明的。

    如上图,我们选择了一张ic_android_black_24dp矢量图标,完成之后如下图


    image.png

    Android Studio为我们自动生成的xml代码

    <vector xmlns:android="http://schemas.android.com/apk/res/android"
            android:width="24dp"
            android:height="24dp"
            android:viewportWidth="24.0"
            android:viewportHeight="24.0">
        <path
            android:fillColor="#FF000000"
            android:pathData="M6,18c0,0.55 0.45,1 1,1h1v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L11,19h2v3.5c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5L16,19h1c0.55,0 1,-0.45 1,-1L18,8L6,8v10zM3.5,8C2.67,8 2,8.67 2,9.5v7c0,0.83 0.67,1.5 1.5,1.5S5,17.33 5,16.5v-7C5,8.67 4.33,8 3.5,8zM20.5,8c-0.83,0 -1.5,0.67 -1.5,1.5v7c0,0.83 0.67,1.5 1.5,1.5s1.5,-0.67 1.5,-1.5v-7c0,-0.83 -0.67,-1.5 -1.5,-1.5zM15.53,2.16l1.3,-1.3c0.2,-0.2 0.2,-0.51 0,-0.71 -0.2,-0.2 -0.51,-0.2 -0.71,0l-1.48,1.48C13.85,1.23 12.95,1 12,1c-0.96,0 -1.86,0.23 -2.66,0.63L7.85,0.15c-0.2,-0.2 -0.51,-0.2 -0.71,0 -0.2,0.2 -0.2,0.51 0,0.71l1.31,1.31C6.97,3.26 6,5.01 6,7h12c0,-1.99 -0.97,-3.75 -2.47,-4.84zM10,5L9,5L9,4h1v1zM15,5h-1L14,4h1v1z"/>
    </vector>
    

    svg是由xml定义的,标准svg根节点为<svg>,在Android中通过vector实现对svg的支持,根节点为<vector>获得一张SVG需要进行转换才能在Android当中使用。
    如果想把机器人的颜色改为红色,只需要修改fillColor的值为FFFF0000即可。

    批量转换SVG

    Android Studio上单个转换SVG图像很方便,那么有多个SVG需要转化成Android的Vector,我们就需要借助第三方工具

    具体的命令执行:

    java -jar svg2vector-cli-1.0.0.jar -d . -o convert -h 20 -w 20
    
    -jar jar文件路径
    -d 指定SVG文件所在目录
    -f 指定单个SVG文件
    -h 设置转换后SVG的高
    -w 设置转换后SVG的宽
    -o 输出Android Vector图像目录
    
    SVG兼容两种方式
    image.png

    app/build.gradle中添加

    // 将SVG图片生成制定维度的png图片
    vectorDrawables.generatedDensities('xhdpi','xxhdpi')
    // 使用support-v7兼容
    vectorDrawables.useSupportLibrary=true
    implementation 'com.android.support:appcompat-v7:28.0.0'
    

    布局中用法

    app:srcCompat="@drawable/ic_netease"
    
    2. Tint
    3. 资源打包配置

    resource.asrc
    由于第三方库,如appcompat-v7的引入,库中包含了大量的国际化资源,根据业务情况可以通过配置删除

    resConfigs 'zh-rCN' // 只保留中文资源
    
    4. 动态库打包配置

    如果项目中包含了第三方SDK或者自己使用了NDK,如果不进行配置会打包全CPU架构的动态库进apk,对于真机,只需要保留一个armeabi(armeabi-v7)就可以了。

    ndk{
        abiFilters('armeabi', 'armeabi-v7')
    }
    
    5. 移除无用资源

    Refactor -> Remove Unused Resources

    一键移除,涉及到动态ID资源会出问题,所以不推荐使用。

    Analyze -> Run Inspection by Name

    键入Unused resources后,选中并执行

    6. 开启代码压缩
    minifyEnabled true
    proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    

    其中,proguard-rules.pro文件内容为混淆代码,详见语法

    -ignorewarnings
    
    -dontskipnonpubliclibraryclassmembers
    
    -keepattributes SourceFile,LineNumberTable
    
    -keep class * implements java.io.Serializable {
        *;
    }
    
    -keep class **.R$* {*;}
    
    #supportv4
    -dontwarn android.support.v4.**
    -keep class android.support.v4.** { *; }
    
    # fastjson
    -dontwarn com.alibaba.fastjson.**
    -keep class com.alibaba.fastjson.** { *; }
    ...
    ...
    ...
    
    7. 启用资源缩减
    shrinkResources true
    
    8. 启用webp转换插件

    webp格式是谷歌推出的一种有损压缩格式,这种图片格式相比png或者jpg的图片损失的质量几乎可以忽略不计,但是压缩后图片的体积比png或jpg要小很多,且质量没有明显损失。目前谷歌已经将这种压缩格式集成到了AS中,开发者能够很方便快捷的使用该插件。

    选中需要转换的png图片右击,选择 Convert to WebP...

    image.png

    选择有损或无损编码。无损编码只在minSdkVersion大于等18可用。选择有损编码可以设置编码质量,并且可以勾选对转换后的图片在保存之前进行预览。
    可以选择跳过如果转换后的图片大于原图和跳过包含透明通道的图片。因为AS只允许minSdkVersion大于等于18时创建透明度Webp图片,当minSdkVersion小于18会默认勾选跳过包含透明通道的图片。
    9-patch图片不能转换为WebP图片。转换工具总是会自动跳过9-patch图片

    9. 资源混淆和7zip压缩

    资源混淆配合7zip压缩,减小apk大小,增加破解难度

    通过resource.arsc文件格式,混淆步骤为
    1. 解析arsc文件,主要为全局与资源名字符串池
    2. 修改字符串池中的字符串,以无意义的a/b替换
    3. 修改apk中的res目录资源文件名
    4. 打包(7zip)、对齐、签名

    可以使用微信团队开源的AndResGuard进行资源混淆
    具体用法:
    项目根目录下build.gradle中,添加插件的依赖

    classpath 'com.tencent.mm:AndResGuard-gradle-plugin:1.2.15'
    

    在app目录下,创建and_res_guard.gradle文件(也可以直接将内容写入build.gradle文件)

    apply plugin: 'AndResGuard'
    andResGuard {
        // mappingFile = file("./resource_mapping.txt")
        mappingFile = null
        use7zip = true
        useSign = true
        // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
        keepRoot = false
        whiteList = [
            // for your icon
            "R.drawable.icon",
            // for fabric
            "R.string.com.crashlytics.*",
            // for google-services
            "R.string.google_app_id",
            "R.string.gcm_defaultSenderId",
            "R.string.default_web_client_id",
            "R.string.ga_trackingId",
            "R.string.firebase_database_url",
            "R.string.google_api_key",
            "R.string.google_crash_reporting_api_key",
    
            // 我在实际项目中遇到第三方使用getIdentifier访问的资源的问题,将指定的资源放入白名单后,虽然不闪退了,但还是会出现无法理解的错误。所以只好全部id都放入白名单
             "R.id.*"
        ]
        compressFilePattern = [
            "*.png",
            "*.jpg",
            "*.jpeg",
            "*.gif",
        ]
        sevenzip {
             artifact = 'com.tencent.mm:SevenZip:1.2.15'
             //path = "/usr/local/bin/7za"
        }
    
        /**
        * 可选: 如果不设置则会默认覆盖assemble输出的apk
        **/
        // finalApkBackupPath = "${project.rootDir}/final.apk"
    
        /**
        * 可选: 指定v1签名时生成jar文件的摘要算法
        * 默认值为“SHA-1”
        **/
        // digestalg = "SHA-256"
    }
    

    在build.gradle文件中引用

    apply from: 'and_res_guard.gradle'
    

    集成完AndResGuard后,在app的gradle的tasks中,多了一个叫做andresguard的task

    如果打debug包,执行resguardDebug指令;
    如果打preview包,执行resguardPreview指令;
    如果打release包,执行resguardRelease指令。

    我们双击执行resguardRelease指令,执行完毕后,我们可以在app目录下的/build/output/apk/release/AndResGuard_{apk_name}/ 文件夹中找到混淆后的Apk

    相关文章

      网友评论

        本文标题:APK瘦身之九道工序

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