Я буду первым, кто признает, что я не очень эксперт с Gradle и новой системой сборки Android, но, к сожалению, мне пришлось перейти к ней (из ant) из-за проблемы 21479 (https://code.google.com/p/android/issues/detail?id=21479) и комментарий "Это не будет исправлено. Мы фокусируемся на завершении системы сборки на основе Gradle, которая заменит Ant." К сожалению, после добавления медиа-рекламы Millenium Media я не смог собрать материал. Это было в дополнение к библиотеке Android OpenCV, библиотеке шифрования Chilkat и библиотеке поддержки v4, но библиотека MMedia была единственной, которая сломала все это.
Итак, я подумал, что это хорошая причина для перехода на новую систему сборки Gradle. К сожалению, несмотря на выход из строя системы ant, новая система пока не завершена; особенно поддержка ndk.
Приложение, над которым я работаю, использует OpenCV для некоторой части обработки изображения, и несколько операций работают слишком медленно, если они не скомпилированы в native (LOTS памяти перемещается и сравнивает, которые слишком медленны по границе JNI). Поэтому, вместо того, чтобы пытаться передать данные назад и вперед между виртуальной машиной и собственным кодом, я оставляю все это на родной стороне и просто получаю один вызов от виртуальной машины, чтобы получить результаты.
Первая проблема заключалась в том, чтобы компилировать материал ndk. Я не мог заставить настройки в закрытии ndk работать, поэтому мне пришлось прибегнуть к использованию команды ndk-build и выполнить это как задачу:
task ndkBuild(type: Exec) {
String MainDirectory = System.getProperty("user.dir") + '/app/src/main'
println "Main app directory for NDK build " + MainDirectory
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j'
}
else {
commandLine 'gradle-ndk-build', MainDirectory, '-j'
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
Это работает отлично; он компилирует код ndk и генерирует библиотеку .so без ошибок. К сожалению, он не поместит полученный файл .so в финальный пакет. Это ставит все остальные родные библиотеки в порядке, но не в этом - не знаю почему.
Я нашел много предполагаемых исправлений для этой проблемы, таких как:
tasks.withType(com.android.build.gradle.tasks.PackageApplication) { pkgTask ->
pkgTask.jniFolders = new HashSet<File>()
pkgTask.jniFolders.add(new File(buildDir, 'native-libs'))
}
Но добавление этого результата приводит только к файлу apk, где нет собственных библиотек. Я видел, что у других людей такая же проблема (например, https://groups.google.com/forum/#!msg/adt-dev/QbDHM41QT2E/J4jHCC_RuIEJ), но я пробовал все предлагаемые решения, и никто из них не работает для меня.
Поскольку я не изменяю собственный код очень часто, я только что сделал взломать, чтобы скопировать созданную собственную библиотеку (libndklib.so) из app/src/main/libs в /app/src/main/jni после его компиляции; то он попадает в пакет apk. Очевидно, это немного неприятно, так как, если кто-то возьмет этот код, им будет интересно, почему их изменения в собственном коде никогда не появляются в приложении.
Итак, мои вопросы: Есть ли что-то, что я могу запустить в Gradle script, который будет выполняться после того, как я запустил команду ndk (gradle -ndk-build), которая скопирует сгенерированный файл из приложения /src/main/libs/armeabi/libndklib.so to/app/src/main/jni/armeabi/libndklib.so(для каждой из архитектур - armeabi, armeabi-v7, x86, mips), так что это заканчивается в пакете apk?
ИЛИ
Есть ли способ сделать дескриптор закрытия Gradle ndk правильным файлом ndk: Application.mk
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := all
APP_PLATFORM := android-8
Android.mk
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=SHARED
include /home/myname/tools/OpenCV-2.4.8-android-sdk/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := ndklib
LOCAL_SRC_FILES := ndklib.cpp motion.cpp
LOCAL_LDLIBS += -lm -llog
include $(BUILD_SHARED_LIBRARY)
# Add prebuilt chilkat library
include $(CLEAR_VARS)
LOCAL_MODULE := lib-chilkat
LOCAL_SRC_FILES := $(TARGET_ARCH_ABI)/libchilkatemail.so
include $(PREBUILT_SHARED_LIBRARY)
Я посмотрел на источник Gradle для плагина, но я не мог видеть, что многие из этих директив поддерживаются.
ИЛИ
Можно ли добавить какой-то хак, который работает в конце Gradle script, который просто заставляет соответствующую копию libndklib.so(для правильной архитектуры) в сгенерированную apk? Я могу жить с последним, пока материал ndk не будет завершен для подключаемого модуля Android для сборки Gradle.
=======================================
Изменить - после ответа ph0b Это окончательный файл build.gradle с предлагаемым модулем. Создает .apk отлично build.gradle (в каталоге приложения)
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.9.+'
}
}
apply plugin: 'android'
import org.apache.tools.ant.taskdefs.condition.Os
android {
compileSdkVersion 19
buildToolsVersion "19.0.3"
signingConfigs {
debug {
storeFile file("dbgkeystore")
storePassword "nopass"
keyAlias "mainkeyname"
keyPassword "nopass"
}
release {
storeFile file("keystore")
storePassword "xxxxxxxx"
keyAlias "mainkeyname"
keyPassword "yyyyyyyy"
}
}
// Autoincrement the version properties file
// ******************************************
def versionPropsFile = file('version.properties')
def code = 1
def majorversion = 1
def minorversion = 1
defaultConfig {
versionCode code
versionName "${majorversion}.${minorversion}.${code}"
minSdkVersion 10
targetSdkVersion 19
}
buildTypes {
release {
runProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
signingConfig signingConfigs.release
}
debug {
runProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
packageNameSuffix ".debug"
versionNameSuffix "-debug"
signingConfig signingConfigs.debug
}
}
sourceSets {
main {
jni.srcDirs = []
// jniLibs.srcDir 'src/main/jni' // - Doesn't work, leaves out the .so files generated by ndk-build
jniLibs.srcDir 'src/main/libs'
}
}
flavorDimensions "version", "abi"
productFlavors {
pro {
flavorDimension "version"
packageName "org.somedomainname.myAppPro1"
}
lite {
flavorDimension "version"
packageName "org.somedomainname.myAppLite1"
}
arm {
flavorDimension "abi"
ndk {
abiFilter "armeabi"
}
if (versionPropsFile.canRead()){
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
code = versionProps['VERSION_CODE'].toInteger() + 1
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
versionCode code
versionName "${majorversion}.${minorversion}.${code}"
}
else {
throw new GradleException("Could not read version.properties!")
}
}
armv7 {
flavorDimension "abi"
ndk {
abiFilter "armeabi-v7a"
}
if (versionPropsFile.canRead()){
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
code = versionProps['VERSION_CODE'].toInteger() + 1
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
versionCode code
versionName "${majorversion}.${minorversion}.${code}"
}
else {
throw new GradleException("Could not read version.properties!")
}
}
x86 {
flavorDimension "abi"
ndk {
abiFilter "x86"
}
if (versionPropsFile.canRead()){
def Properties versionProps = new Properties()
versionProps.load(new FileInputStream(versionPropsFile))
code = versionProps['VERSION_CODE'].toInteger() + 1
versionProps['VERSION_CODE']=code.toString()
versionProps.store(versionPropsFile.newWriter(), null)
versionCode code
versionName "${majorversion}.${minorversion}.${code}"
}
else {
throw new GradleException("Could not read version.properties!")
}
}
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
repositories {
mavenCentral()
flatDir {
dirs '/home/myname/maindrive/work/dynamic/android/UtilLib/aarlib'
}
}
dependencies {
compile 'com.android.support:appcompat-v7:+'
compile fileTree(dir: 'libs', include: ['*.jar'])
// Note: org.somedomainname.UtilLib on the depency below is ignored when usng flatdir
compile 'org.somedomainname.UtilLib:library:[email protected]'
}
task ndkBuild(type: Exec) {
String MainDirectory = System.getProperty("user.dir") + '/app/src/main'
println '************************************************************************'
println "Main app directory for NDK build " + MainDirectory
println '************************************************************************'
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'gradle-ndk-build.cmd', MainDirectory, '-j'
}
else {
commandLine 'gradle-ndk-build', MainDirectory, '-j'
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
android.applicationVariants.all { variant ->
variant.assemble.doLast {
rename_and_moveout_apk(variant)
}
}
// allprojects {
// tasks.withType(Compile) {
// options.compilerArgs << "-Xlint:deprecation"
// }
// }
def rename_and_moveout_apk(targetVariant) {
// replace output apk name to <product>-<version>-<buildtype>-<githash>.apk
def versionSuffix = targetVariant.buildType.versionNameSuffix ? targetVariant.buildType.versionNameSuffix : ""
def versionName = targetVariant.mergedFlavor.versionName + versionSuffix;
if (targetVariant.zipAlign) {
def apkFinal = targetVariant.outputFile;
def apkFinalNewName = "myApp-" + apkFinal.name.replace(targetVariant.buildType.name, versionName);
copy {
from "$apkFinal"
into "$rootProject.projectDir/apk_release"
rename ("$apkFinal.name", "$apkFinalNewName")
println "*************** Renaming zipalign apk file from: ${apkFinal.name} to ${apkFinalNewName}"
}
}
}
gradle -ndk-build (измененная версия ndk-build, используемая для отладки параметров)
#!/bin/bash
export NDK_PROJECT_PATH=$1
export NDK_PROJECT_DIRECTORY=$1
bash -c "ndk-build"
Структура каталогов
------ apk_release
------ app
-- -- ---- src
-- ------ lite
-- -- -- ---- java
-- -- -- ---- org
-- -- -- ---- somedomainname
-- -- -- ---- myApp
-- ------ main
-- -- ------ assets
-- -- ------ java
-- -- -- -- ---- org
-- -- -- ------ chilkatsoft
-- -- -- -- ---- somedomainname
-- -- -- -- ---- myApp
-- -- ------ jni
-- -- -- ------ armeabi
-- -- -- ------ armeabi-v7a
-- -- -- ------ mips
-- -- -- -- ---- x86
-- -- ------ libs
-- -- -- ------ armeabi
-- -- -- ------ armeabi-v7a
-- -- -- ------ mips
-- -- -- -- ---- x86
-- -- ------ obj
-- -- -- -- ---- local
-- -- -- ------ armeabi
-- -- -- -- -- ---- objs
-- -- -- -- -- ---- ndklib
-- -- -- ------ armeabi-v7a
-- -- -- -- -- ---- objs
-- -- -- -- -- ---- ndklib
-- -- -- ------ mips
-- -- -- -- -- ---- objs
-- -- -- -- -- ---- ndklib
-- -- -- -- ---- x86
-- -- -- -- ---- objs
-- -- -- -- ---- ndklib
-- -- -- ---- res
-- -- ------ drawable
-- -- ------ drawable-hdpi
-- -- ------ drawable-ldpi
-- -- ------ drawable-mdpi
-- -- ------ drawable-xhdpi
-- -- ------ drawable-xxhdpi
-- -- ------ layout
-- -- ------ raw
-- -- ------ values
-- -- -- ---- xml
-- -- ---- pro
-- -- ---- java
-- -- ---- somedomainname
-- -- ---- myApp