Android|Smaller apk

本文翻译于 google developer 官方教程

build.gradle
android {
    ...
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

首先应该打开 (minifier)压缩开关,例如:minifyEnabled true ,这个开关会清除不使用的类以及类成员,同时会是用短名称重命名类以及类成员,这都会是apk体积减小,但是重命名会是调试变得非常困难,所以建议只是用 下面的混淆配置(如果出现ClassNotFoundException 需要在混淆配置里加混淆保护)

shrinkResources true 会清除掉代码不使用的资源引用

特别像这种字符串引用,也要加混淆保护:

<android.support.v7.widget.RecyclerView
    app:layoutManager=”android.support.v7.widget.GridLayoutManager”
    ...
/>

如果你创建的aar库需要使用在第三方项目里面,为了使用Proguard规则对AAR生效,你需要使用 comsumerProguardFiles 属性,这样,人和人使用你的AAR时,就不用担心需要手动添加规则了

android {
    ...
    defaultConfig {
        consumerProguardFiles “proguard-rules.txt”
    }
}

step two:Tracking down dependencies

待补充

step three:removing unused resources:

android {
    ...
    buildTypes {
        release {
            '''shrinkResources true'''
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

它能分析所有已经被引用的资源并清除那些没有被Layout, Drawable , code 所使用的资源
it can also analyze which resources are actually being used and strip those that are never included in your layouts, drawables, code, etc.

就像删除代码一样,有时候工具出现不知道使用哪个资源错误,有可能错误的删掉资源,所以,你可以告诉系统一想要保留的资源,只需要使用 tools:keep 这样的类似ProGuard keep的配置就可以做到,你可以在任何具有 resource 节点的文件或者新建一个带resource节点的xml:

res/raw/keep.xml

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
   tools:keep="@layout/l_used*_c,@layout/l_used_a,@layout/l_used_b*"
/>

你也可以指定要删除的资源:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools"
    tools:shrinkMode="safe"
    tools:discard="@layout/unused2"
/>

Removing unused configurations with ResConfigs:

android {
    defaultConfig {
        ...
        resConfigs "en", "fr"
    }
}

很多库都会被翻译成多种语言,如果你只想在特定的语言时长发布,则如上配置,系统会去掉所有不在配置列表里的其他语言资源

Sparse configurations in resources.arsc

这个问题通常只会发生在体积很大的App上,成百上千的字符资源,样式,以及Id都会进入resources.arsc文件,如果你突然发现Apk占用的体积增大,可能表明,你有很多分散的配置,比如,你有五个字符串定义在默认的配置中(vlaues/string.xml),这些字符资源会被系统定义到字符资源池中,并且有另外配置文件会生成指向这些字符资源的地址(你可以认为是引用),像下面这样:

String pool: "My App", "Hello", "Exit", "Settings", "Feature"
                  Default config: 
string/myapp      0x00000001
string/hello      0x00000002
string/exit       0x00000003
string/settings   0x00000004
string/feature    0x00000005

现在想象一下,你只需要在API21+上新增一个功能,这个功能需要显示 feature 为不同的消息,所以你就在values-v21/strings.xml 上覆盖这个字符串,并重新编译,你可能会认为,只是在字符池中新增了一个字符串,并且只生成了一个指向地址(你可以认为是引用),但是很遗憾,这不是resources.arsc文件格式的工作原理,你可能会看到这样的结果:

String pool: "My App", "Hello", "Exit", "Settings", "Feature", "New feature"
                  Default config:         -v21 config:
string/myapp      0x00000001              NO_ENTRY
string/hello      0x00000002              NO_ENTRY
string/exit       0x00000003              NO_ENTRY
string/settings   0x00000004              NO_ENTRY
string/feature    0x00000005              0x00000006

                  ==========              ==========
Config size:      20 bytes                20 bytes!

就像上面这样,每个配置(-v21, -land, -en-land-v21)都额外保存了每一个资源的引用,实际上这些引用是空的(无效的),一个空的占用4bytes,就如我一开始说的,占用多大的控件,取决于你在app里定义了多少资源,例如上面在 -v21配置中有4*4byte,也就是16bytes浪费在空的引用上。
然而真实的场景是如果一个app定义了3500 个strings,并且有一个单独的landscape配置并且只有一个字符资源被翻译成50种语言(例如: values-en-land, -pl-land, -de-land, -fr-land…)将会失去:
4bytes*3500 null entryes*50 languages = 700 kilobytes
只需要删除一个字符资源,就可以节约700kilobytes,删除3个,就可以节约2.5M
话说回来,如果你把一个资源放在一个单独的配置里,意味着你确实需要它并且它确实是合适的处理方式,但是如果能判断这些资源能减少大量的体积,你可能会考虑把他们去掉以节约体积。
有一种在代码中根据不同版本来使用不同字符资源的不太优雅的方法,只针对特别的场景。例如,在你的values/strings.xml你可能由两个字符串:string/my_feature and string/my_feature_land, 然后根据运行时当前屏幕方向来动态选择字符资源。
已经有工具能帮你找到分散的资源配置并找到哪些资源导致resources.arsc增大:
https://github.com/google/android-arscblamer

你需要 安装Bazel来编译ArscBlamer,你可以编译可运行这个命令:

$ bazel run //java/com/google/devrel/gmscore/tools/apk/arsc:ArscDumper --apk=/FULL_PATH_TO_APK/bar.apk - keys > output.csv

这里写图片描述
可以看到所有的Null Entries,去掉是很可观的

Multi-APK through ABI and density splits:
Android 生态系统丰富多样,手机到平板,再到电视,每种设备都有自己的硬件特性,比如屏幕尺寸,屏幕密度,以及cpu架构,尽管在规范文档中,我们鼓励大家去创建支持所有设备的app,但是有时候把apk“分割”开,却能最大限度的节省空间。比如,如果用户的手机是ARM架构的处理器,则我们就可以不必为用户提供X86架构的本地代码库,或者如果用户的手机的分辨率为mdpi的,则我们不必为用户提供xxhdpi密度的资源也为用户节约了带宽。

你可以找到详细的资料,关于Multi_APK是怎样工作的,以及Play Store支持什么样的过滤条件以及一些版本号管理的重要规则,理解Multi-APK 的工作原理至关重要(http://developer.android.com/google/play/publishing/multiple-apks.html#HowItWorks),作为开发者你应该要判断使用如此法则的版本管理和处理流程会给用户带来怎样的好处。最简单的Multi-APK方式是通过Android Studio配置选项来分割,splits 就是你在build.gradle添加的能为不同密度或者不同ABIS(CPU 架构)创建单独的APK的一段配置区域。

密度分割

在你开始准备分割你的apk之前,如果你需要一个样例来验证分割的效果,我建议你看看Topeka on Github,这个样例已经对包括图片在内的资源针对不同密度的设备做了处理,是splits的完美例证。
打开 app/build.gradle文件,并添在build.gradle中添加如下代码:

android {
    ...
    splits {
        density {
            enable true
            exclude 'ldpi', 'tvdpi', 'xxxhdpi'
//alternatively use the following two lines to only include:
//            reset()
//            include 'mdpi', 'hdpi', 'xhdpi', 'xxhdpi'
            compatibleScreens 'small', 'normal', 'large', 'xlarge'
        }
    }
}

配置非常简单:
1. 打开密度分割的开关
2. 然后包括或者去除特定密度配置
3. 最后指定屏幕兼容性,必须从小到达(small,normal, large, xlarge)

……待完成

Multi-APK through product flavors:

待完成

SmallerAPK, Part 6: Image optimization, Zopfli & WebP

待完成

Image optimization, Shape and VectorDrawables

待完成

Native libraries, open from APK

待完成

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值