精简我们的apk的方法
2015-11-29 00:16
691 查看
我们都知道安卓的65K方法坑。
最近搞的项目也是轻松超越,哎,现在的项目越来越大,功能越来越多,还没怎么用,要求一次上齐那么多功能也是挺奇葩的,加班也越来越多,无限的不理解,有点做得很没意思啊。。
虽然这些都是治标不治本的方法,
不过对于在这个边界65K左右的情况确实很好的一个方法!!
这里有一个包,用来帮助你查看各个package里面的方法数的,
这样你就可以根据这个做一个参考,替换更小的包等。
在我们的build.gradle 文件里面加多
配置好后,我们需要做的就是修改我们application类。
三种方案:
修改minifest文件,name为
修改我们的application继承于
修改我们的app的一个函数。
好了,总共就这样,我们的apk如果超过65k方法,就会被压成两个dex文件。
ANR
应用MultiDex后,这个程序在安装和开启过程会相对复杂,从而导致ANR问题,如果第二个dex文件比较大的话,在这种情况,你需要使用ProGurad来尽可能的减小dex的大小和移出些没用的代码!
安卓4.0无法启动
对于运行旧于4.0的系统,因为一个Dalvik linearAlloc的缺陷,会有可能无法启动。如果你要去支持这部分旧版系统,需要自己测试下,因为在特定累的加载过程都有可能导致bug。
内存消耗问题
采用multidex方案的会有更大的内存消耗从而导致程序崩溃,因为有这么一个Dalvik linearAlloc 限制的bug–78035,这个bug虽然在4.0被调整了。
如果你的gradle是低于1.1的(话说现在都出到2.0了,还用1.1也太旧了),还需要下面这个:
然后你的测试类需要继承这个,或者在你的onCreate里面改成下面这样
具体参考美团的帖子
美团Android DEX自动拆包及动态加载简介
另外提一点的是,很多大型的为了多团队的合作,快速的集成,交付等,实用的就是“插件化开发”,
你去看下微信的包,就各种库,各种插件。
因为需要减轻应用太大时候带来的内存和cpu占用问题。你看每次打开微信那卡的。简直。。。。。。
人家已经维持优化了很多还是这样,可见。安卓手机实在不给力啊。。。。
关于动态加载技术,网上有很多文章,刚兴趣的可以自己看下。
参考资料
谷歌的官方解释:Building Apps with Over 65K Methods
com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536 at com.android.dx.merge.DexMerger$6.updateIndex(DexMerger.java:484) at com.android.dx.merge.DexMerger$IdMerger.mergeSorted(DexMerger.java:261) at com.android.dx.merge.DexMerger.mergeMethodIds(DexMerger.java:473) at com.android.dx.merge.DexMerger.mergeDexes(DexMerger.java:161) at com.android.dx.merge.DexMerger.merge(DexMerger.java:188) at com.android.dx.command.dexer.Main.mergeLibraryDexBuffers(Main.java:504) at com.android.dx.command.dexer.Main.runMonoDex(Main.java:334) at com.android.dx.command.dexer.Main.run(Main.java:277) at com.android.dx.command.dexer.Main.main(Main.java:245) at com.android.dx.command.Main.main(Main.java:106)
最近搞的项目也是轻松超越,哎,现在的项目越来越大,功能越来越多,还没怎么用,要求一次上齐那么多功能也是挺奇葩的,加班也越来越多,无限的不理解,有点做得很没意思啊。。
解决方案:
1. 简单暴力版
删除没要so库,合并一些方法,去掉代码中没使用到的函数,去掉没有使用到的jar包,以及将类中成员由private换成public,减少set/get函数。虽然这些都是治标不治本的方法,
不过对于在这个边界65K左右的情况确实很好的一个方法!!
这里有一个包,用来帮助你查看各个package里面的方法数的,
这样你就可以根据这个做一个参考,替换更小的包等。
java -jar path\dex-method-counts.jar path\App.apk
2. multidex
谷歌在2014年就提出这个解决方案,这个还是很简单实惠的!在我们的build.gradle 文件里面加多
multiDexEnabled true,同时加多multidex包!
android { compileSdkVersion 21 buildToolsVersion '21.1.2' defaultConfig { applicationId "com.lifesense.happyrun" minSdkVersion 18 targetSdkVersion 21 versionCode 1 versionName "1.0.28" multiDexEnabled true } } dependencies { compile 'com.android.support:multidex:1.0.1' }
配置好后,我们需要做的就是修改我们application类。
三种方案:
修改minifest文件,name为
MultiDexApplication
<application android:name="android.support.multidex.MultiDexApplication" android:allowBackup="true" android:icon="@mipmap/icon_app"
修改我们的application继承于
MultiDexApplication
public class MyApp extend MultiDexApplication{ }
修改我们的app的一个函数。
public class MyApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); MultiDex.install(this); } }
好了,总共就这样,我们的apk如果超过65k方法,就会被压成两个dex文件。
MultiDex缺陷
但这方案还是有缺陷的,你需要测试下这个压缩包是否还有效!ANR
应用MultiDex后,这个程序在安装和开启过程会相对复杂,从而导致ANR问题,如果第二个dex文件比较大的话,在这种情况,你需要使用ProGurad来尽可能的减小dex的大小和移出些没用的代码!
安卓4.0无法启动
对于运行旧于4.0的系统,因为一个Dalvik linearAlloc的缺陷,会有可能无法启动。如果你要去支持这部分旧版系统,需要自己测试下,因为在特定累的加载过程都有可能导致bug。
内存消耗问题
采用multidex方案的会有更大的内存消耗从而导致程序崩溃,因为有这么一个Dalvik linearAlloc 限制的bug–78035,这个bug虽然在4.0被调整了。
优化建议
在生产的过程会相对的耗费大量的时间的,因为系统要做很多的决定和判断那些文件放到第一个dex,那些放到第二个DEX里面去。为了缩短build的时间,建议弄两个flavor,一个是开发测试环境,一个是生产环境的。开发环境设最小SDK为21,因为会使用ART技术来加快生产。对于生产环境就设置实际的android { productFlavors { dev { minSdkVersion 21 } prod { minSdkVersion 14 } } ... buildTypes { release { runProguard true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile 'com.android.support:multidex:1.0.1' }
测试问题
这带来的另外一个问题也是测试问题,当我们用instrumentation来测试时候,需要多额外的配置,具体如下
android { defaultConfig { ... testInstrumentationRunner "com.android.test.runner.MultiDexTestRunner" } }
如果你的gradle是低于1.1的(话说现在都出到2.0了,还用1.1也太旧了),还需要下面这个:
dependencies { androidTestCompile('com.android.support:multidex-instrumentation:1.0.1') { exclude group: 'com.android.support', module: 'multidex' } }
然后你的测试类需要继承这个,或者在你的onCreate里面改成下面这样
public void onCreate(Bundle arguments) { MultiDex.install(getTargetContext()); super.onCreate(arguments); ... }
3. 插件化
插件化是一个现对来说很重的一个解决方案,需要修改的地方很多。具体参考美团的帖子
美团Android DEX自动拆包及动态加载简介
另外提一点的是,很多大型的为了多团队的合作,快速的集成,交付等,实用的就是“插件化开发”,
你去看下微信的包,就各种库,各种插件。
因为需要减轻应用太大时候带来的内存和cpu占用问题。你看每次打开微信那卡的。简直。。。。。。
人家已经维持优化了很多还是这样,可见。安卓手机实在不给力啊。。。。
关于动态加载技术,网上有很多文章,刚兴趣的可以自己看下。
参考资料
谷歌的官方解释:Building Apps with Over 65K Methods
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories