如何使用 Android NDK 和 Gradle 构建单个 APK
How to build single APK with Android NDK and Gradle
我正在使用 OpenCV(C++ 而不是 Java)开发一个新的 android 应用程序,我是 opencv 和 NDK 的新手。我使用下面的 Gradle 文件成功构建(和 运行),在 Android Studio 中我可以 select 一个变体并点击构建(例如 x86)。
我有两个问题:
- 有没有一种方法可以构建支持所有架构的 APK 变体? (我知道文件会更大)
我可以在不为每个变体指定所有相同库的情况下实现构建吗?有什么方法可以让构建系统每次都只获取库,因为它们都在项目中并按体系结构名称组织?
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.0.0"
defaultConfig {
applicationId "uk.co.xxx.androidcppimagereader"
minSdkVersion 17
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
def libsDir = projectDir.path + "/libs/"
productFlavors {
x86 {
versionCode Integer.parseInt("3" + defaultConfig.versionCode)
ndk {
abiFilter "x86"
moduleName "Processing"
stl "gnustl_static"
cFlags "-I/opt/local/include/opencv -I/opt/local/include"
ldLibs libsDir + "x86/libopencv_core.a"
ldLibs libsDir + "x86/libopencv_ts.a"
ldLibs libsDir + "x86/libopencv_contrib.a"
ldLibs libsDir + "x86/libopencv_ml.a"
ldLibs libsDir + "x86/libopencv_java.so"
ldLibs "log"
ldLibs "z", "jnigraphics"
}
}
armv7 {
versionCode Integer.parseInt("2" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi-v7a"
moduleName "Processing"
stl "gnustl_static"
cFlags "-I/opt/local/include/opencv -I/opt/local/include"
ldLibs libsDir + "armeabi-v7a/libopencv_core.a"
ldLibs libsDir + "armeabi-v7a/libopencv_ts.a"
ldLibs libsDir + "armeabi-v7a/libopencv_contrib.a"
ldLibs libsDir + "armeabi-v7a/libopencv_ml.a"
ldLibs libsDir + "armeabi-v7a/libopencv_java.so"
ldLibs "log"
ldLibs "z", "jnigraphics"
}
}
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi"
moduleName "Processing"
stl "gnustl_static"
cFlags "-I/opt/local/include/opencv -I/opt/local/include"
ldLibs libsDir + "armeabi/libopencv_core.a"
ldLibs libsDir + "armeabi/libopencv_ts.a"
ldLibs libsDir + "armeabi/libopencv_contrib.a"
ldLibs libsDir + "armeabi/libopencv_ml.a"
ldLibs libsDir + "armeabi/libopencv_java.so"
ldLibs "log"
ldLibs "z", "jnigraphics"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}
在 build.gradle 文件中定义了计划包含在 apk 中的所有架构后,请使用关键字 "fat",如下面代码中突出显示的那样。这将构建一个 FAT 二进制文件。观看此视频了解更多详情 https://www.youtube.com/watch?v=kFtxo7rr2HQ
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi"
moduleName "Processing"
stl "gnustl_static"
cFlags "-I/opt/local/include/opencv -I/opt/local/include"
ldLibs libsDir + "armeabi/libopencv_core.a"
ldLibs libsDir + "armeabi/libopencv_ts.a"
ldLibs libsDir + "armeabi/libopencv_contrib.a"
ldLibs libsDir + "armeabi/libopencv_ml.a"
ldLibs libsDir + "armeabi/libopencv_java.so"
ldLibs "log"
ldLibs "z", "jnigraphics"
}
fat // <- HERE
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
为了正确链接您的库,您必须像当前所做的那样为每个体系结构声明不同的 ldLib。
不幸的是,如果您同时为所有架构构建,则无法从 gradle 使用当前插件执行此操作。
在我看来,最好的解决方案是停用内置(目前已弃用)ndk 支持并改用常规 Android.mk / Application.mk 文件。您的 build.gradle 将如下所示:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1"
defaultConfig {
applicationId "uk.co.xxx.androidcppimagereader"
minSdkVersion 17
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
sourceSets.main {
jniLibs.srcDir 'src/main/libs' //set libs as default directory for .so files inclusion, instead of jniLibs
jni.srcDirs = [] //disable automatic ndk-build call
}
// call regular ndk-build(.cmd) script from app directory
task ndkBuild(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
} else {
commandLine 'ndk-build', '-C', file('src/main').absolutePath
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
}
我正在使用 OpenCV(C++ 而不是 Java)开发一个新的 android 应用程序,我是 opencv 和 NDK 的新手。我使用下面的 Gradle 文件成功构建(和 运行),在 Android Studio 中我可以 select 一个变体并点击构建(例如 x86)。
我有两个问题:
- 有没有一种方法可以构建支持所有架构的 APK 变体? (我知道文件会更大)
我可以在不为每个变体指定所有相同库的情况下实现构建吗?有什么方法可以让构建系统每次都只获取库,因为它们都在项目中并按体系结构名称组织?
apply plugin: 'com.android.application' android { compileSdkVersion 21 buildToolsVersion "21.0.0" defaultConfig { applicationId "uk.co.xxx.androidcppimagereader" minSdkVersion 17 targetSdkVersion 21 versionCode 1 versionName "1.0" } def libsDir = projectDir.path + "/libs/" productFlavors { x86 { versionCode Integer.parseInt("3" + defaultConfig.versionCode) ndk { abiFilter "x86" moduleName "Processing" stl "gnustl_static" cFlags "-I/opt/local/include/opencv -I/opt/local/include" ldLibs libsDir + "x86/libopencv_core.a" ldLibs libsDir + "x86/libopencv_ts.a" ldLibs libsDir + "x86/libopencv_contrib.a" ldLibs libsDir + "x86/libopencv_ml.a" ldLibs libsDir + "x86/libopencv_java.so" ldLibs "log" ldLibs "z", "jnigraphics" } } armv7 { versionCode Integer.parseInt("2" + defaultConfig.versionCode) ndk { abiFilter "armeabi-v7a" moduleName "Processing" stl "gnustl_static" cFlags "-I/opt/local/include/opencv -I/opt/local/include" ldLibs libsDir + "armeabi-v7a/libopencv_core.a" ldLibs libsDir + "armeabi-v7a/libopencv_ts.a" ldLibs libsDir + "armeabi-v7a/libopencv_contrib.a" ldLibs libsDir + "armeabi-v7a/libopencv_ml.a" ldLibs libsDir + "armeabi-v7a/libopencv_java.so" ldLibs "log" ldLibs "z", "jnigraphics" } } arm { versionCode Integer.parseInt("1" + defaultConfig.versionCode) ndk { abiFilter "armeabi" moduleName "Processing" stl "gnustl_static" cFlags "-I/opt/local/include/opencv -I/opt/local/include" ldLibs libsDir + "armeabi/libopencv_core.a" ldLibs libsDir + "armeabi/libopencv_ts.a" ldLibs libsDir + "armeabi/libopencv_contrib.a" ldLibs libsDir + "armeabi/libopencv_ml.a" ldLibs libsDir + "armeabi/libopencv_java.so" ldLibs "log" ldLibs "z", "jnigraphics" } } } buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) compile 'com.android.support:appcompat-v7:21.0.3' }
在 build.gradle 文件中定义了计划包含在 apk 中的所有架构后,请使用关键字 "fat",如下面代码中突出显示的那样。这将构建一个 FAT 二进制文件。观看此视频了解更多详情 https://www.youtube.com/watch?v=kFtxo7rr2HQ
arm {
versionCode Integer.parseInt("1" + defaultConfig.versionCode)
ndk {
abiFilter "armeabi"
moduleName "Processing"
stl "gnustl_static"
cFlags "-I/opt/local/include/opencv -I/opt/local/include"
ldLibs libsDir + "armeabi/libopencv_core.a"
ldLibs libsDir + "armeabi/libopencv_ts.a"
ldLibs libsDir + "armeabi/libopencv_contrib.a"
ldLibs libsDir + "armeabi/libopencv_ml.a"
ldLibs libsDir + "armeabi/libopencv_java.so"
ldLibs "log"
ldLibs "z", "jnigraphics"
}
fat // <- HERE
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
为了正确链接您的库,您必须像当前所做的那样为每个体系结构声明不同的 ldLib。
不幸的是,如果您同时为所有架构构建,则无法从 gradle 使用当前插件执行此操作。
在我看来,最好的解决方案是停用内置(目前已弃用)ndk 支持并改用常规 Android.mk / Application.mk 文件。您的 build.gradle 将如下所示:
import org.apache.tools.ant.taskdefs.condition.Os
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1"
defaultConfig {
applicationId "uk.co.xxx.androidcppimagereader"
minSdkVersion 17
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
sourceSets.main {
jniLibs.srcDir 'src/main/libs' //set libs as default directory for .so files inclusion, instead of jniLibs
jni.srcDirs = [] //disable automatic ndk-build call
}
// call regular ndk-build(.cmd) script from app directory
task ndkBuild(type: Exec) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
commandLine 'ndk-build.cmd', '-C', file('src/main').absolutePath
} else {
commandLine 'ndk-build', '-C', file('src/main').absolutePath
}
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn ndkBuild
}
}