我和我的团队最近在我们的应用程序中达到了 64K 方法引用,这是 dex 文件中支持的最大数量。为了绕过这个限制,我们需要将部分程序分割成多个二级dex文件,并在运行时加载。
我们按照问题中提到的旧的、基于 Ant 的构建系统的博客文章进行操作,一切正常。但我们最近觉得有必要迁移到基于 Gradle 的新构建系统。
此答案并不打算用完整的示例替换完整的博客文章。相反,它将简单地解释如何使用 Gradle 来调整构建过程并实现相同的目标。请注意,这可能只是其中一种方式,也是我们目前在团队中的方式。这并不一定意味着它是唯一的方式。
我们的项目结构有些不同,这个示例作为一个单独的 Java 项目工作,它将所有源代码编译成 .class 文件,将它们组装成单个 .dex 文件,最后将单个 .dex 文件打包成.jar 文件。
开始吧……
在根目录 build.gradle 我们有以下代码来定义一些默认值:
ext.androidSdkDir = System.env.ANDROID_HOME
if(androidSdkDir == null) {
Properties localProps = new Properties()
localProps.load(new FileInputStream(file('local.properties')))
ext.androidSdkDir = localProps['sdk.dir']
}
ext.buildToolsVersion = '18.0.1'
ext.compileSdkVersion = 18
我们需要上面的代码,因为尽管该示例是一个单独的 Java 项目,但我们仍然需要使用 Android SDK 中的组件。稍后我们还将需要其他一些属性...所以,在主项目的 build.gradle 上,我们有这个依赖项:
dependencies {
compile files("${androidSdkDir}/platforms/android-${compileSdkVersion}/android.jar")
}
我们还简化了这个项目的源代码集,这对您的项目可能不是必需的:
sourceSets {
main {
java.srcDirs = ['src']
}
}
接下来,我们将内置 jar 任务的默认配置更改为仅包含 classes.dex 文件而不是所有 .class 文件:
configure(jar) {
include 'classes.dex'
}
现在我们需要一个新任务,将所有 .class 文件实际组装成一个 .dex 文件。在我们的例子中,我们还需要将 Protobuf 库 JAR 包含到 .dex 文件中。所以我在这里的例子中包括了它:
task dexClasses << {
String protobufJarPath = ''
String cmdExt = Os.isFamily(Os.FAMILY_WINDOWS) ? '.bat' : ''
configurations.compile.files.find {
if(it.name.startsWith('protobuf-java')) {
protobufJarPath = it.path
}
}
exec {
commandLine "${androidSdkDir}/build-tools/${buildToolsVersion}/dx${cmdExt}", '--dex',
"--output=${buildDir}/classes/main/classes.dex",
"${buildDir}/classes/main", "${protobufJarPath}"
}
}
另外,请确保您在 build.gradle 文件的某处(当然通常在顶部)有以下导入:
import org.apache.tools.ant.taskdefs.condition.Os
现在我们必须使jar 任务依赖于我们的dexClasses 任务,以确保我们的任务在最终的.jar 文件组装之前执行。我们用一行简单的代码来做到这一点:
jar.dependsOn(dexClasses)
我们完成了...只需使用通常的 assemble 任务调用 Gradle,您的最终 .jar 文件 ${buildDir}/libs/${archivesBaseName}.jar 将包含单个 classes.dex 文件(除了 MANIFEST .MF 文件)。只需将其复制到您的应用资产文件夹中(您始终可以像我们所做的那样使用 Gradle 自动执行该操作,但这超出了本问题的范围),然后按照博文的其余部分进行操作。
如果您有任何问题,请在 cmets 中留言。我会尽我所能提供帮助。