I try this
I want generate few APK (x86, armeabi-v7a). In order to reduce the size of APK in Google Play
But its doesnt work. Android studia says import com.android.build.OutputFile - Cannot resolve symbol '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
Error:Cannot invoke method multiply() on null object
my gradle-file is
// 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. You should check the result of output.getFilter(OutputFile.ABI)
before applying multiplication in some manner like for example:
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:
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
:
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
. The examples in the docs say to use OutputFile.ABI
- as of more recent tools versions (I'm not sure which), this is wrong. The correct argument is OutputFile.FilterType.ABI
.
The getFilter
method is defined on the class ApkVariantOutputImpl
. As you can see in the source code for ApkVariantOutputImpl, it takes a single argument of type 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.
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. 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, i.e. check the multiplier for null and replace it with something meaningful like zero.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With