关闭

如何将apk大小减少6M的

标签: android包大小瘦身apk
7587人阅读 评论(3) 收藏 举报

如何做到将apk大小减少6M

我们的apk去年业务需求增长迅速,伴随而来的是apk大小由年初的20M以下,增长到年底的30M。

包大小增长的坏处有:

  1. 过大的下载包会降低新用户的下载兴趣
  2. 增加下载安装中失败的风险
  3. 提高各个渠道下载发布的成本(渠道是会根据你的包大小设置收费规则的)

因此,减少包大小的工作看上去不痛不痒,其实还挺重要的。

接下来,我将分享下我在包大小瘦身方面的努力。

技术列表


  1. lint检查
  2. 微信资源压缩
  3. webp本地图片处理
  4. tiny图片处理
  5. proguard

lint检查清除冗余


实践方式

Android Studio

Analyze -> Run Inspection by Name

unusedResources

unused declaration

结果:

我们apk里引用了近一百的aar。我对他们进行逐一检查。

发现了300+冗余文件 节省了700+KB字节占用

pic

建议:

各业务团队因养成定期检查的良好习惯。即减少了冗余,又能减少平时开发业务中无用代码的干扰。

微信资源压缩


简单原理介绍:

apk代码运行时,是通过 code ->R ->res找到对应资源的。
而R ->res的映射关系是打包时写在resources.arsc里的。

所以对生成的apk进行的操作如下:

  1. 先解压缩包
  2. 然后对res目录下的文件夹和文件进行名称替换
  3. 同时修改resources.arsc里对应的R与资源的映射关系
  4. 然后再打包签名生成新的apk

使用说明

命令:
java -jar andresguard-1.1.jar mogujie.apk -config
weixinResShrinkConfig.xml

输入:

andresguard-1.1.jar
需要处理的apk文件
配置文件config.xml

输出:

处理后的apk
mapping文件,记录名称变动前后对应关系

config.xml配置了

whitelist  (com.mogujie.R.XXX.XXX)
sign (签名文件路径和密码)
其他相关处理(如:是否压缩资源,是否用7Z压缩等)

结果:

能将apk包大小减少2M+

处理后的apk资源变成混淆名称,起到一定的安全保护作用

pic

日常维护注意事项:

代码中有通过getIdentifier 获取的资源文件需要添加白名单

pic

推广:

微信资源压缩工具与业务代码无关,我们已经把这部分技术处理整合到打包系统里,推荐大家在发布你们的apk时加入微信资源压缩,效果杠杠的。

附:

微信Android资源混淆打包工具原理:

http://mp.weixin.qq.com/s?__biz=MzAwNDY1ODY2OQ==&mid=208135658&idx=1&sn=ac9bd6b4927e9e82f9fa14e396183a8f#rd

github地址:

https://github.com/shwenzhang/AndResGuard/blob/master/README.zh-cn.md

webp本地图片处理


背景

Android4.0+原生支持,无需修改代码。
相同图片效果,webp的文件占用空间更小。
解码和渲染时间比png,jpg高出几倍,但用户体验几乎不受影响。

关于webp与png,jpg详细对比评测,可参考腾讯团队webp探索之路:
http://isux.tencent.com/introduction-of-webp.html

wep命令的安装与使用,参考:
https://developers.google.com/speed/webp/

实践

pic

文件夹名称 文件夹描述 大小
p drawable-xhdpi-v4里的jpg和png图片 1409张 3.8M
cwebpp 通过webp有损压缩全部图片后的文件夹 1409张 2M
webpp-lossless 通过webp无损压缩后的文件夹 1396张 3.5M

经过大量的测试,最后将webp处理设置为:有损,质量75

cwebp -q 75 -m 6 a.png -o a.webp

考虑到drawable-xhdpi-v4以外的文件夹下的图片,webp压缩能减少2M+的apk空间

应用

因为webp的图片格式没有默认的图片浏览器,必须通过chrome浏览器打开,影响了平时业务开发的便捷性。因此,我设计将webp图片处理工作放在了主客build时进行。

gradle build主客时,有一个mergeXXXResource Task,它将主客和aar中所有的res资源统一整合到/build/intermediates/res/flavorName/{buildType}目录下。

pic

因此,我写了一个gradle plugin插件 webpConvertPlugin,在mergeXXXResource Task执行后,processXXXResource Task前,插入新的webpConvertPlugin Task 将上述目录下中drawable项目目录里的png,jpg图片(不包含.9图片,webp转换后显示效果不佳)批量处理成webp图片。这样最后打包生成的apk里就是webp图片了。

问题:

在我们上线webp插件时遇到了一个无法规避的严重问题。有alpha值的jpg图片,经过webp转换后,无法在4.0,4.1的Android系统上运行。经过调研从http://developer.android.com/guide/appendix/media-formats.html中找到了答案:

pic

只有在4.2.1+以上的机型,才能解析无损或者有透明度调整的webp图片

然后我又用imagemagick的命令遍历apk中所有图片,统计出1500+张的图片只有80多张图片没有alpha值。

因此,在4.0 4.1目前还有大量用户的前提下,webp本地图片批量替换的方案无法上线。

推广

webp批量处理本地图片的插件适用于各个Android项目,我们开源了自写的webp插件,请参考:

https://github.com/mogujie/WebpConvert_Gradle_Plugin

tiny图片处理


https://tinypng.com/
目前所知图片压缩效果最好的网站。谁用谁知道。

为解决日常开发中,大家手动去此网站挨个处理图片的困扰。我利用tiny提供的jar包做了个批量处理本地图片的tinyPIC gradle plugin。它在build 中插入一个新的tinyPicPlugin task.遍历寻找项目res中以drawable开头的文件夹中的图片资源,调用tiny API进行压缩工作并替换原来的文件。

重要文件

tinypic_white_list.txt(白名单,可设置不进行处理的图片)
tinypic_compressed_list.txt(记录处理过的图片,避免重复压缩)

推广

tinyPIC插件适用于各个Android项目,我们也开源了自写的tiny 插件,接入方法请参考:
https://github.com/mogujie/TinyPIC_Gradle_Plugin

Proguard


Proguard是编译时对java代码进行压缩,混淆,优化,预编译等操作的集成化工具。达到删除冗余,增加安全防护,减小大小的功效。具体介绍,可参考
http://mobile.mogujie.org/doc/android/mixup.html

项目的应用

pic

1. mogu_proguard_annotations.pro 支持proguard注解的使用
(你可以在~/Android/sdk/tools/proguard/examples/annotations/lib中找到配置文件annotations.pro)

2. mogu_proguard.pro 保证功能正常运行的相关配置(根据项目自行配置)

如何写proguard.pro的配置

mogu_proguard.pro的配置主要是为了解决项目在proguard使用中遇到的问题。

遇到的问题又分为两个阶段:

  • 编译时的报错 Problems while processing

    常见于第三方API的Warning: can’t find referenced class

    解决方法如:

    -dontwarn com.google.**
    -keep class  com.google.** { *;}
    
  • 运行时异常 Problems at run-time

    原因基本都是原本需要具体名字的上下文,混淆后找不到造成的。主要有,native方法失效,注解失效,json数据解析失败,反射失效。

    解决方法:

    无源代码的第三方API,添加对应的-dontwarn -keep

    自有代码使用注解,注解前build.gradle里加入

    dependencies {  
        compile "com.infstory:proguard-annotations:1.0.2"  
    }
    

    或在~/Android/sdk/tools/proguard/examples/annotations/lib里找到并引入annotations.jar

    你的xxx.pro配置文件里

    -keep class  proguard.annotation.* {*;}
    

    然后分别按照下面的情况使用注解

    1. .so native方法找不到引起的问题

      请将有.so native的类加上

      @proguard.annotation.KeepClassMembers
      
    2. 注解类失效

      请将注解类加上

      @proguard.annotation.Keep
      
    3. 根据写死的或者重服务器传过来的类名称 反射实例化类相关的功能失效

      请将需要反射的类加上

      @proguard.annotation.Keep
      
    4. json数据解析,数据展示不出来

      请将需要json解析的类加上

      @proguard.annotation.KeepClassMembers  
      

更多关于注解的使用,可参考:https://github.com/yongjhih/proguard-annotations

异常日志的转义

混淆后的错误日志会变成这样

java.lang.NoSuchFieldError: USER_COMMENT

at e.a.a.a(Unknown Source) 

为了定位问题代码,需要使用mapping文件。

简单点的日志可直接在mapping中搜索e.a.a.a,获取对应的源文件

复杂点的就要用到proguardgui.jar这个工具了。在你的Android sdk/tools/proguard/lib
目录中可以找到。

pic

因业务代码不断更新,无法统计具体数值,故大致给出每个技术减少的合理效果范围

成果


技术名称 减少大小范围
lint检查删除冗余 700kb ~ 800kb
微信资源压缩 2M左右
微信webp本地图片处理压缩 未上线
tiny图片处理 0.8M ~ 1.3M
proguard 1.8M ~ 2.3M
总计 6M左右

微信资源压缩和proguard 提供了Android apk 一定的资源文件和源代码的安全保护能力

结语


以上就是目前想到并运用的瘦身技术,写这个的目的是希望能帮助到需要瘦包的同学,望能给您带来一点启示。

任何不清楚明白的或者有更好的apk瘦身建议的技术讨论,欢迎@伯约 与我交流 boyue@mogujie.com

7
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:9404次
    • 积分:154
    • 等级:
    • 排名:千里之外
    • 原创:4篇
    • 转载:0篇
    • 译文:1篇
    • 评论:3条
    最新评论