[英]how generate multiple apk (using gradle , libGDX)
I want generate few APK (x86, armeabi-v7a). 我想生成几个APK(x86,armeabi-v7a)。 In order to reduce the size of APK in Google Play
为了减少Google Play中APK的大小
But its doesnt work. 但它不起作用。 Android studia says import com.android.build.OutputFile - Cannot resolve symbol 'OutputFile'.
Android studia说导入com.android.build.OutputFile - 无法解析符号'OutputFile'。 And in console i see.
在控制台我看到了。 I try search in google other instructions and tried to do something about it myself, but I'm not good at gradle
我尝试在google其他说明中搜索并尝试自己做一些事情,但我不擅长gradle
Error:Cannot invoke method multiply() on null object
my gradle-file is 我的gradle文件是
// map for the version code
ext.versionCodes = ['armeabi-v7a':1, 'armeabi':2, 'x86':3]
import com.android.build.OutputFile
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
output.versionCodeOverride =
project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 1000000 + android.defaultConfig.versionCode
}
}
android {
buildToolsVersion "20.0.0"
compileSdkVersion 20
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
instrumentTest.setRoot('tests')
}
defaultConfig {
versionCode 11
versionName '1.3'
}
productFlavors {
}
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'armeabi'
universalApk true
}
}
}
// needed to add JNI shared libraries to APK when compiling on CLI
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
pkgTask.jniFolders = new HashSet<File>()
pkgTask.jniFolders.add(new File(projectDir, 'libs'))
}
// called every time gradle gets executed, takes the native dependencies of
// the natives configuration, and extracts them to the proper libs/ folders
// so they get packed with the APK.
task copyAndroidNatives() {
file("libs/armeabi/").mkdirs();
file("libs/armeabi-v7a/").mkdirs();
file("libs/x86/").mkdirs();
configurations.natives.files.each { jar ->
def outputDir = null
if (jar.name.endsWith("natives-armeabi-v7a.jar")) outputDir = file("libs/armeabi-v7a")
if (jar.name.endsWith("natives-armeabi.jar")) outputDir = file("libs/armeabi")
if (jar.name.endsWith("natives-x86.jar")) outputDir = file("libs/x86")
if (outputDir != null) {
copy {
from zipTree(jar)
into outputDir
include "*.so"
}
}
}
}
task run(type: Exec) {
def path
def localProperties = project.file("../local.properties")
if (localProperties.exists()) {
Properties properties = new Properties()
localProperties.withInputStream { instr ->
properties.load(instr)
}
def sdkDir = properties.getProperty('sdk.dir')
if (sdkDir) {
path = sdkDir
} else {
path = "$System.env.ANDROID_HOME"
}
} else {
path = "$System.env.ANDROID_HOME"
}
def adb = path + "/platform-tools/adb"
commandLine "$adb", 'shell', 'am', 'start', '-n', 'com.mygdx.crazyball.android/com.mygdx.crazyball.android.AndroidLauncher'
}
// sets up the Android Eclipse project, using the old Ant based build.
eclipse {
// need to specify Java source sets explicitely, SpringSource Gradle Eclipse plugin
// ignores any nodes added in classpath.file.withXml
sourceSets {
main {
java.srcDirs "src", 'gen'
}
}
jdt {
sourceCompatibility = 1.6
targetCompatibility = 1.6
}
classpath {
plusConfigurations += [project.configurations.compile]
containers 'com.android.ide.eclipse.adt.ANDROID_FRAMEWORK', 'com.android.ide.eclipse.adt.LIBRARIES'
}
project {
name = appName + "-android"
natures 'com.android.ide.eclipse.adt.AndroidNature'
buildCommands.clear();
buildCommand "com.android.ide.eclipse.adt.ResourceManagerBuilder"
buildCommand "com.android.ide.eclipse.adt.PreCompilerBuilder"
buildCommand "org.eclipse.jdt.core.javabuilder"
buildCommand "com.android.ide.eclipse.adt.ApkBuilder"
}
}
// sets up the Android Idea project, using the old Ant based build.
idea {
module {
sourceDirs += file("src");
scopes = [COMPILE: [plus: [project.configurations.compile]]]
iml {
withXml {
def node = it.asNode()
def builder = NodeBuilder.newInstance();
builder.current = node;
builder.component(name: "FacetManager") {
facet(type: "android", name: "Android") {
configuration {
option(name: "UPDATE_PROPERTY_FILES", value: "true")
}
}
}
}
}
}
}
dependencies {
}
Looks like it fails on a try to get ABI for universal APK as there is no filter for it in your versionCodes
map. 看起来它试图获得通用 APK的ABI失败,因为你的
versionCodes
地图中没有过滤器。 You should check the result of output.getFilter(OutputFile.ABI)
before applying multiplication in some manner like for example: 你应该以某种方式应用乘法之前检查
output.getFilter(OutputFile.ABI)
的结果,例如:
android.applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
def abiFilter = output.getFilter(OutputFile.ABI)
def abiMultiplier = 0
if (abiFilter != null) {
abiMultiplier = project.ext.versionCodes.get(abiFilter)
}
output.versionCodeOverride =
abiMultiplier * 1000000 + android.defaultConfig.versionCode
}
}
TL;DR: TL; DR:
I just had the same problem, and for me the answer is thankfully simple. 我只是遇到了同样的问题,对我而言,答案很简单。 Instead of using
OutputFilter.ABI
in the call to output.getFilter
, use OutputFilter.FilterType.ABI
: 而不是在对
output.getFilter
的调用中使用OutputFilter.ABI
,而是使用OutputFilter.FilterType.ABI
:
android.applicationVariants.all { variant ->
variant.outputs.each { output ->
def defaultCode = android.defaultConfig.versionCode
def filter = output.getFilter(OutputFile.FilterType.ABI)
def abiMultiplier = project.ext.versionCodes.get(filter)
output.versionCodeOverride = abiMultiplier * 1000000 + defaultCode
}
}
What broke 什么破了
This is essentially what you have above, but refactored into a few more lines. 这基本上就是你所拥有的,但重构了几行。 The key difference is in the call to
output.getFilter
. 关键区别在于对
output.getFilter
的调用。 The examples in the docs say to use OutputFile.ABI
- as of more recent tools versions (I'm not sure which), this is wrong. 文档中的示例说使用
OutputFile.ABI
- 作为更新的工具版本(我不确定哪个),这是错误的。 The correct argument is OutputFile.FilterType.ABI
. 正确的参数是
OutputFile.FilterType.ABI
。
The getFilter
method is defined on the class ApkVariantOutputImpl
. getFilter
方法在类ApkVariantOutputImpl
上定义。 As you can see in the source code for ApkVariantOutputImpl , it takes a single argument of type OutputFile.FilterType
; 正如您在ApkVariantOutputImpl的源代码中所看到的 ,它接受一个类型为
OutputFile.FilterType
参数; OutputFile.ABI
is a String
, and Groovy (despite all the other bits of magic it does) evidently does not convert the constant string into the proper enum, resulting in a null value. OutputFile.ABI
是一个String
,而Groovy(尽管它所做的所有其他魔法)显然不会将常量字符串转换为正确的枚举,从而产生一个空值。
Disclaimer 放弃
Just FYI, I had to dig pretty extensively through different versions of the build tools to find the source link - it seems that this has been an area of API instability. 仅供参考,我不得不通过不同版本的构建工具进行广泛挖掘以找到源链接 - 这似乎是API不稳定的一个方面。 This works for me, with the following settings:
这适用于我,具有以下设置:
buildscript {
dependencies {
'com.android.tools.build:gradle:1.2.2'
}
}
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
// lots of stuff
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'mips'
}
}
}
If you want to build a universal APK (with all the different ABIs included), you'll need to account for the fact that the universal variant has no ABI filter, ie check the multiplier for null and replace it with something meaningful like zero. 如果你想构建一个通用的APK(包含所有不同的ABI),你需要考虑通用变量没有ABI过滤器这一事实,即检查乘数为null并用零有意义的东西替换它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.