Li.Stony

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

众所周知,开发Android应用时,随着应用越来越大,迟早会遇到超过65535方法数的问题。虽然Google 给出了避免64K 方法数的解决方案,但是并不完美。

比如我们最近遇到的。在自动分包后,因为classes.dex太大,出现了在2.3设备上安装失败的现象。此时,adb 报的错误是 INSTALL_FAILED_DEXOPT 。这个现象的原因是 LinearAlloc 在 4.0 之前最多只能分配5M的空间。在4.0以后是8M或16M。而这个5M的大小和 classes.dex 文件本身的大小无关,与复杂性有关。有人给出的经验是如果方法数在 56000 以下,一般就可以在 5M 以内。(参考 https://ingramchen.io/blog/2014/09/prevention-of-android-dex-64k-method-size-limit.html

对于这个问题,我是这样解决的。

  1. 使用 dx 命令把一些jar包转成 classes2.dex,比如

 

dx --dex --output="ui/build_scripts/ext_dex/classes2.dex" "ui/libs2"

 

  1. 生成classes2.dex的jar只参与编译,不参与生成classes.dex。使用

 

provided fileTree(dir: 'libs2', include: ['*.jar'])

 

 

替代

 

compile fileTree(dir: 'libs2', include: ['*.jar'])

 

  1. build过程中打包classes2.dex到apk文件中

写了个简单的脚本,其实可以用 gradle task 实现吧,把 classes2.dex 复制到classes.dex所在目录,而且添加一些自定义task:

def overseaAutoMultidex = !buildOversea

// copy ext dex

def generateCopyDex2Task(baseName) {

   return tasks.create("copyDex2TaskFro${baseName}", Exec) {

       println 'begin copy classes2.dex'

       workingDir = 'build_scripts'

       commandLine 'python3', 'cp_ext_dex.py'

       doLast {

           String output = standardOutput.toString()

           println output

       }

   }

}

 

    def overseaDebugCopyTask = generateCopyDex2Task("Debug")

def overseaStagingCopyTask = generateCopyDex2Task("Staging")

def overseaReleaseCopyTask = generateCopyDex2Task("Release")

afterEvaluate() {

   if (!overseaAutoMultidex) {

        // 不同的工程,具体task名称不同,一般是 packageDebug

        // assembleRelease,transformClassesWithDexForDebug, transformClassesWithDexForRelease 等

       packageOverseaDebug.dependsOn overseaDebugCopyTask

       overseaDebugCopyTask.shouldRunAfter transformClassesWithDexForOverseaDebug



       packageOverseaStaging.dependsOn overseaStagingCopyTask

       overseaStagingCopyTask.shouldRunAfter transformClassesWithDexForOverseaStaging


       assembleOverseaRelease.dependsOn overseaReleaseCopyTask

       overseaReleaseCopyTask.shouldRunAfter transformClassesWithDexForOverseaRelease


   }

}

 

 

  1. 利用 multidex.jar 安装 classes2.dex,在 MyApplication 里调用下面的语句还是不能少的。

 

MultiDex.install(ctx);

 

 

 



这种方式有个很明显的缺点,就是参与生成classes2.dex的jar包不能与其他jar包一起使用proguard压缩。所以,这些jar包一般是第三方的jar包,已经proguard过的。

posted on 2016-04-28 15:28  Li.Stony  阅读(437)  评论(0编辑  收藏  举报