您的位置:首页 > 移动开发 > Android开发

精简我们的apk的方法

2015-11-29 00:16 691 查看
我们都知道安卓的65K方法坑。

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  函数 apk 合并 android 65536