Android

Android通过.nomedia文件禁止多媒体库扫描指定文件夹下的多媒体文件 Android应用内存泄露分析、改善经验总结 修改Eclipse导入项目的默认工程名 自定义Android Studio工程模板 使用Nexus Repository搭建属于自己公司的私有maven服务器 Android Studio编译过程中mergeDebugResources时报“png-cruncher_*”异常的解决方案 Eclipse转Android Studio的过程中有必要弄明白的一些问题 Android开发经验总结 Android Studio使用过程中遇到的一些问题及解决方案 Android各个Support Library介绍 调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案 提升进入界面的速度 使用软引用解决Handler内存泄露和显示Popupwindow、Dialog时提示"Unable to add Window-token is null"的问题 SharedPreferences在多进程中的使用及注意事项 Android性能测试工具列表 Android View双缓冲绘制时清除Bitmap上的内容的方法 解决JPinyin在APK被加密后不能正常使用的问题 Android APP内存优化之图片优化 Android EditText的使用及值得注意的地方 Android应用内多进程的使用及注意事项 Android设置应用内文字的默认颜色和大小 关于APK瘦身值得分享的一些经验 Android通过ClipDrawable实现图片裁剪功能 Android通过广播更新文件和文件夹到媒体库 每个Android开发者都应该了解的资源列表 selector的使用方法及注意事项 通过批处理批量clone代码 Android清除数据、清除缓存、一键清理的区别 Android将数据库保存到SD卡的实现 Android多分辨率适配经验总结 通过观察者模式监听媒体库的变化实现APP本地数据自动更新 Android ADB命令大全(通过ADB命令查看wifi密码、MAC地址、设备信息、操作文件、查看文件、日志信息、卸载、启动和安装APK等) Android通过ADB查看wifi密码 Android一个APK多个入口(多个桌面图标)的实现 使用Python脚本批量卸载第三方应用和清除log缓存 Android CheckList Android模仿打字机效果的自定义View实现 在Activity的onCreate方法中显示PopupWindow导致异常的原因分析及解决方案 Android手写优化-更为平滑的签名效果实现 Android手写优化-平滑的签名效果实现 不要在Android的Application对象中缓存数据! 大量Android面试题目来袭 一种不需要Google账号、不需要关联手机、不需要在手机上安装Google的服务直接能够下载Google Play上APK的方法 在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案 Android程序和数据分离的实现方案 按Home按键退出应用后重新启动该应用无法返回到最后打开页面的解决方案 Eclipse下Android项目不能生成R.java的解决方法汇总 android:descendantFocusability属性在ListView中的妙用 去掉SrollView、GrdiView、ListView、ViewPager等滑动到边缘的光晕效果 Android开发经验谈-Eclipse使用技巧 Android开发经验谈-很少有人会告诉你的Android开发基本常识 Android开发经验谈-Android工程目录介绍 在Android的string.xml中使用转义字符实现想要的显示效果 修改ViewPager调用setCurrentItem时,滑屏的速度 Android监听Home按键消息 Android手写开源项目和资料搜集 Android通过资源文件名获取资源ID Android中Bitmap、Drawable、bytes数组之间相互转换 想过但未实现的一些Idea 读写文件编码方式不一致导致文件乱码的解决方案 Android字符串格式化开源库phrase介绍 Android实现带箭头的自定义Progressbar Android模拟键盘输入功能的实现 与Android应用程序相关的各种文件存储路径介绍 Android开发者网址导航

标签

Android 65

Android通过.nomedia文件禁止多媒体库扫描指定文件夹下的多媒体文件 Android应用内存泄露分析、改善经验总结 修改Eclipse导入项目的默认工程名 自定义Android Studio工程模板 使用Nexus Repository搭建属于自己公司的私有maven服务器 Android Studio编译过程中mergeDebugResources时报“png-cruncher_*”异常的解决方案 Eclipse转Android Studio的过程中有必要弄明白的一些问题 Android开发经验总结 Android Studio使用过程中遇到的一些问题及解决方案 Android各个Support Library介绍 调用AsyncTask的excute方法不能立即执行程序的原因分析及改善方案 提升进入界面的速度 使用软引用解决Handler内存泄露和显示Popupwindow、Dialog时提示"Unable to add Window-token is null"的问题 SharedPreferences在多进程中的使用及注意事项 Android性能测试工具列表 Android View双缓冲绘制时清除Bitmap上的内容的方法 解决JPinyin在APK被加密后不能正常使用的问题 Android APP内存优化之图片优化 Android EditText的使用及值得注意的地方 Android应用内多进程的使用及注意事项 Android设置应用内文字的默认颜色和大小 关于APK瘦身值得分享的一些经验 Android通过ClipDrawable实现图片裁剪功能 Android通过广播更新文件和文件夹到媒体库 每个Android开发者都应该了解的资源列表 selector的使用方法及注意事项 通过批处理批量clone代码 Android清除数据、清除缓存、一键清理的区别 Android将数据库保存到SD卡的实现 Android多分辨率适配经验总结 通过观察者模式监听媒体库的变化实现APP本地数据自动更新 Android ADB命令大全(通过ADB命令查看wifi密码、MAC地址、设备信息、操作文件、查看文件、日志信息、卸载、启动和安装APK等) Android通过ADB查看wifi密码 Android一个APK多个入口(多个桌面图标)的实现 使用Python脚本批量卸载第三方应用和清除log缓存 Android CheckList Android模仿打字机效果的自定义View实现 在Activity的onCreate方法中显示PopupWindow导致异常的原因分析及解决方案 Android手写优化-更为平滑的签名效果实现 Android手写优化-平滑的签名效果实现 不要在Android的Application对象中缓存数据! 大量Android面试题目来袭 一种不需要Google账号、不需要关联手机、不需要在手机上安装Google的服务直接能够下载Google Play上APK的方法 在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案 Android程序和数据分离的实现方案 按Home按键退出应用后重新启动该应用无法返回到最后打开页面的解决方案 Eclipse下Android项目不能生成R.java的解决方法汇总 android:descendantFocusability属性在ListView中的妙用 去掉SrollView、GrdiView、ListView、ViewPager等滑动到边缘的光晕效果 Android开发经验谈-Eclipse使用技巧 Android开发经验谈-很少有人会告诉你的Android开发基本常识 Android开发经验谈-Android工程目录介绍 在Android的string.xml中使用转义字符实现想要的显示效果 修改ViewPager调用setCurrentItem时,滑屏的速度 Android监听Home按键消息 Android手写开源项目和资料搜集 Android通过资源文件名获取资源ID Android中Bitmap、Drawable、bytes数组之间相互转换 想过但未实现的一些Idea 读写文件编码方式不一致导致文件乱码的解决方案 Android字符串格式化开源库phrase介绍 Android实现带箭头的自定义Progressbar Android模拟键盘输入功能的实现 与Android应用程序相关的各种文件存储路径介绍 Android开发者网址导航

关于APK瘦身值得分享的一些经验

2015年04月06日

从APK的文件结构说起

  APK在安装和更新之前都需要经过网络将其下载到手机,如果APK越大消耗的流量就会越多,特别是对于使用移动网络的用户来讲,消耗流量越多就代表需要花更多的钱去购买流量。同时一些第三方应用商城也会对上传的APK大小有限制,所以为了能够让产品能够更受商城和用户欢迎,APK瘦身是第一步,更小的APK标示着更多地用户愿意去下载和体验。

  为了能够减小APK的大小,首先需要知道APK由哪些部分构成,然后针对每个部分做相应的优化工作,下图是一个APK解压后的文件结构:

图一:APK结构

  各文件的介绍如下:

  • classes.dex:classes.dex是java源码编译后生成的java字节码文件。但由于Android使用的dalvik虚拟机与标准的java虚拟机是不兼容的,dex文件与class文件相比,不论是文件结构还是opcode都不一样。目前常见的java反编译工具都不能处理dex文件。Android模拟器中提供了一个dex文件的反编译工具,dexdump。用法为首先启动Android模拟器,把要查看的dex文件用adb push上传的模拟器中,然后通过adb shell登录,找到要查看的dex文件,执行dexdump xxx.dex。另,有人介绍到Dedexer是目前在网上能找到的唯一一个反编译dex文件的开源工具,需要自己编译源代码。

  • resources.arsc:编译后的二进制资源文件

  • AndroidManifest.xml:该文件是每个应用都必须定义和包含的,它描述了应用的名字、版本、权限、引用的库文件等等信息,如要把apk上传到Google Market上,也要对这个xml做一些配置。在apk中的AndroidManifest.xml是经过压缩的,可以通过AXMLPrinter2工具解开,具体命令为:java -jar AXMLPrinter2.jar AndroidManifest.xml

  • proguard.cfg:代码混淆配置文件;

  • project.properties:标示APK的target sdk和依赖关系,这里的依赖关系指示的是该APK依赖到了哪些工程;

  • assets:assets目录可以存放一些配置文件(比如webview本地资源、图片资源等等),这些文件的内容在程序运行过程中可以通过相关的API获得。具体的方法可以参考SDK中的例子:在sdk的 \SDK\1.6\android-sdk-windows-1.6_r1\platforms\android-1.6\samples\ApiDemos 例子中,有个com.example..android.apis.content 的例子,在这个例子中他把一个text文件放到工程的asset目录下,然后把这个txt当作普通文件处理。处理的过程在ReadAsset.java中。同理,asset也可以放置其他文件。

  • lib:lib目录下的子目录armeabi存放的是一些so文件。这个地方多讲几句,都是在开发过程中摸索出来的。eclipse在打包的时候会根据文件名的命名规则(lib**.so)去打包so文件,开头和结尾必须分别为“lib”和“.so”,否则是不会打包到apk文件中的。其他非eclipse开发环境没有测试过。如果你是用SDK和NDK开发的话,这部分很重要,甚至可以通过把一些不是so文件的文件通过改名打包到apk中,具体能干些什么那就看你想干什么了,呵呵呵!

  • META-INF:META-INF目录下存放的是签名信息,用来保证apk包的完整性和系统的安全。在eclipse编译生成一个apk包时,会对所有要打包的文件做一个校验计算,并把计算结果放在META-INF目录下。这就保证了apk包里的文件不能被随意替换。比如拿到一个apk包后,如果想要替换里面的一幅图片,一段代码, 或一段版权信息,想直接解压缩、替换再重新打包,基本是不可能的。如此一来就给病毒感染和恶意修改增加了难度,有助于保护系统的安全。

  • res:res目录存放资源文件。包括图片、字符串、raw文件夹下面的音频文件、各种xml文件等等。

  从图一可知,APK中classes.dex、lib、资源文件是大头,APK瘦身主要就是优化这三类,关于这三种类型的文件比较成熟的优化方法有:

  • classes.dex:通过代码混淆,删掉不必要的jar包和代码实现该文件的优化;

  • lib:一个硬件设备对应一个架构(mips、arm或者x86),只保留与设备架构相关的库文件夹(主流的架构都是arm的,mips属于小众,默认也是支持arm的so的,但x86的不支持),这样可以大大降低lib文件夹的大小;

  • 资源文件:通过Lint工具扫描代码中没有使用到的静态资源。

  上面介绍的三种类型文件的优化方案的确能够在一定程度上减小APK的大小,但在最近做项目的过程中经过研究发现还可以更进一步优化APK的大小,具体方案如下:

  • 多分辨率适配:我之前写过一篇关于多分辨率适配的文章Android多分辨率适配经验总结,一套图、一套布局,多套dimens.xml文件,在使用最小资源的情况下搞定多分辨率适配;

  • 预置数据:和游戏一样,程序和数据分离,进入模块时下载预置数据(下载的策略需要注重用户体验,在需要使用数据的地方下载);

  • 图片资源:使用tinypng和webP,下面详细介绍图片资源优化的方案。

图片资源优化攻略

  图片资源的优化原则是:在不降低图片效果、保证APK显示效果的前提下缩小图片文件的大小。

使用tinypng优化大部分图片资源:

  tinypng是一个支持压缩png和jpg图片格式的网站,通过其独特的算法(通过一种叫“量化”的技术,把原本png文件的24位真彩色压缩为8位的索引演示,是一种矢量压缩方法,把颜色值用数值123等代替。)可以实现在无损压缩的情况下图片文件大小缩小到原来的30%-50%。压缩率和压缩后的效果如下:

图二:tinypng图片压缩率展示

图上:tinpng图片压缩前后效果对比

  上面的图片对比举例不太好,不过可以看到压缩前后图片效果并没有变化,需要说明的是:tinypng支持png和jpg图片的压缩,并且也支持9图的压缩。

  tinypng的缺点是在压缩某些带有过渡效果(带alpha值)的图片时,图片会失真,这种图片可以将png图片转换为下面介绍的webP格式,可以在保证图片质量的前提下大幅缩小图片的大小。

  tinypng提供了开放接口供开发者开发属于自己的压缩工具,不过这是付费服务,对于普通用户来说,tinypng为每个用户提供的每月图片免费压缩数量已经足够了。

使用webP图片格式:

  WebP是谷歌研发出来的一种图片数据格式,它是一种支持有损压缩和无损压缩的图片文件格式,派生自图像编码格式 VP8。根据 Google 的测试,无损压缩后的 WebP 比 PNG 文件少了 45% 的文件大小,即使这些 PNG 文件经过其他压缩工具压缩之后,WebP 还是可以减少 28% 的文件大小。目前很多公司已经将webP技术运用到Android APP中,比如FaceBook、腾讯、淘宝。webP相比于png最明显的问题是加载稍慢,不过现在的智能设备硬件配置越来越高,这都不是事儿。

  假如你打算在 App 中使用 WebP,除了 Android4.0 以上提供的原生支持外,其他版本以可以使用官方提供的解析库webp-android-backport编译成so使用。

  通常UI提供的图片都是png或者jpg格式,我们可以通过智图或者isparta将其它格式的图片转换成webP格式,isparta可实现批量转换,墙裂推荐!

使用tintcolor实现按钮反选效果:

  通常按钮的正反旋图片我们都是通过提供一张按钮正常图片和一张按钮反选图片,然后通过selector实现,两张图片除了alpha值不一样外其它的内容都是重复的,在Android 5.0及以上的版本可以通过tintcolor实现只提供一张按钮的图片,在程序中实现按钮反选效果,前提是图片的内容一样,只是正反选按钮的颜色不一样。

参考资料

  本文重点讲述图片资源的优化,关于APK瘦身可以从多个方面入手,下面是一些关于APK瘦身值得阅读的文章,本文也作了一些参考。只要用心专研,APK的大小肯定会控制下来的。