use*_*906 48 android-ndk android-studio android-gradle-plugin
新的Android gradle插件(0.7)似乎包含对NDK的新支持,但在文档中几乎没有提到它(我发现的唯一参考是一个名为test的测试 ndkSanAngeles).
看起来gradle正在寻找我已经包含在我的PATH中的NDK.但是,构建项目失败了
- 出了什么问题:任务执行失败':OGLTests:compileDefaultFlavorDebugNdk'.NDK未配置
如何在gradle中配置NDK?
我当前的build.gradle看起来像这样:
task nativeLibsToJar(type: Zip, description: 'create a jar with native libs') {
destinationDir file("$buildDir/native-libs")
baseName 'native-libs'
extension 'jar'
from fileTree(dir: 'src/main/libs', include: '**/*.so')
from fileTree(dir: 'src/main/libs', include: '**/gdb*')
into 'lib/'
}
tasks.withType(JavaCompile) {
compileTask -> compileTask.dependsOn nativeLibsToJar
}
dependencies {
compile fileTree(dir: "$buildDir/native-libs", include: '*.jar')
}
android {
compileSdkVersion 19
buildToolsVersion '19.0.0'
defaultConfig {
minSdkVersion 14
targetSdkVersion 19
versionCode 1
versionName "0.1"
}
buildTypes {
release {
runProguard false
}
debug {
// jniDebugBuild true
runProguard false
debuggable true
}
}
productFlavors {
defaultFlavor {
proguardFile 'proguard-rules.txt'
}
}
}
Run Code Online (Sandbox Code Playgroud)
谢谢.
rea*_*ore 76
通过gradle插件代码,我发现以下内容帮助我使用了NDK和预构建的本机库:
要在Prebuilt Native Libraries中简单链接,只需在任务中添加一个ndk部分即可.例如,我在productFlavors中添加了它.abiFilter是libs存储的文件夹名称.abiFilters意味着来自逗号分隔列表的libs将被添加到你的最终APK中(理论上你可以有"armeabi","armeabi-v7a","x86"和" mips"all in one APK,O/S将在安装时选择支持的架构lib:
productFlavors {
arm {
ndk {
abiFilters "armeabi", "armeabi-v7a"
}
}
x86 {
ndk {
abiFilter "x86"
}
}
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,arm构建将创建一个带有V5和V7A arm库的APK,而x86构建将创建一个仅包含x86库的APK.这将搜索项目jniLibs目录中的本机库.jniLibs目录应该是旧jni目录的结构,即:
[project]/[app]/src/main/jniLibs/armeabi/libmyNative.so
[project]/[app]/src/main/jniLibs/armeabi-v7a/libmyNative.so
[project]/[app]/src/main/jniLibs/x86/libmyNative.so
Run Code Online (Sandbox Code Playgroud)
然后你可以用Java加载它,如下所示:
static
{
loadLibrary("myNative");
}
Run Code Online (Sandbox Code Playgroud)
现在,假设一个本地库依赖于另一个.您必须(如果将最小API设置为API 17或更低版本)首先加载依赖库:
static
{
loadLibrary("myDependency");
loadLibrary("myNative");
}
Run Code Online (Sandbox Code Playgroud)
您还可以将ndk {}部分放在defaultConfig或buildType中(例如调试或发布或您可能使用的任何其他内容).例如:
buildTypes {
debug {
ndk {
abiFilters "armeabi", "armeabi-v7a"
}
}
}
Run Code Online (Sandbox Code Playgroud)
通过预先构建,我指的是您下载的第三方库或使用NDK工具链或您自己的ARM工具链(而不是ndk-build脚本本身)构建的库.
在API 18中,他们修复了一个长期存在的体系结构问题,该问题阻止了本机lib加载程序"自动"加载依赖项,因为它不知道应用程序的lib目录(安全性原因等).在API 18及更高版本中,如果myNative依赖于上面的myDependency,则可以只调用loadLibrary("myNative"),操作系统将处理加载myDependency.但是,请不要依赖此,直到运行API 17及更低版本的设备的市场渗透率达到您可接受的低数量.
要在当前版本的Android Studio中显式构建源代码中的NDK库,您可以执行以下操作:
如前所述,将local.properties中的ndk.dir值设置为指向NDK home.有谁知道你是否可以直接在local.properties中使用env vars?:)
在build.gradle文件中,将类似的内容添加到您的任务中(同样,可以是defaultConfig,debug,release,productFlavor等):
ndk {
moduleName "myNDKModule"
stl "stlport_shared"
ldLibs "log", "z", "m"
cFlags "-I/some/include/path"
}
Run Code Online (Sandbox Code Playgroud)
这是当前支持的类型(moduleName,stl,ldLibs和cFlags)的基本结构.我看起来并没有找到更多.我相信ldLibs存在一个问题,因为它会自动将"-l"添加到上面每个字段的前面.你可以欺骗它(我不得不)说:ldLibs"log -lz -lm -Wl,-whole-archive -l/path/to/someOtherLib -Wl,-no-whole-archive"
在这一行中,您只是标记到第一个参数的末尾以添加不以-l开头的参数,因此您现在可以使用.在上面的例子中,我将整个静态库链接到我的NDK模块,以便在Java中使用.我已经要求谷歌开发人员添加其他功能,以允许甚至将您自己的Android.mk文件合并到NDK构建过程中,但由于这是全新的,可能需要一段时间.
目前,无论你在build.gradle中放置什么都会删除临时构建目录并每次都重新创建它,所以除非你想下载和修改gradle android插件源代码(这很有趣),否则会有一些"make due"的像这样需要将你的东西复制到构建中.提供此ndk支持的android gradle脚本实质上会生成一个Android.mk文件,并使用NDK系统在临时目录中构建.
Sidetracked一秒.moduleName应匹配jni目录下项目中的ac或cpp文件,如:
[project]/[app]/src/main/jni/myNDKModule.cpp
Run Code Online (Sandbox Code Playgroud)
如果要将stlport库用于C++,则应将stl值设置为"stlport_shared"或"stlport_static"的值.如果您不需要扩展的C++支持,可以将stl保留.记住Android默认情况下提供非常基本的C++支持.对于其他受支持的C++库,请在您下载的NDK中查看NDK文档指南.请注意,通过在此处将其设置为stlport_shared,gradle将libstlport_shared.so lib从NDK的sources/cxx-stl/stlport/libs目录复制到APK的lib目录.它还处理编译器中的include路径(从技术上讲,gradle不会完成所有这些,但是Android NDK构建系统).所以不要将自己的stlport副本放入jniLibs目录中.
最后,我认为cFlags非常明显.
你不能在Mac OSX上设置ANDROID_NDK_HOME(见下文),但是从我做过的一些研究看来,这可能仍适用于其他操作系统.它将被删除.
我想发表评论,但还没有声誉.丹尼斯,环境变量被完全忽略,而不仅仅是被覆盖.实际上,您没有得到任何环境变量.据我所知,Android Studio IDE只使用几个特定的环境变量创建自己的环境(检查System.getenv()并从gradle脚本中打印出来).
我在这里写了一个错误,因为使用env vars从cmd行构建得很好:https://code.google.com/p/android/issues/detail? id
= 65213
但正如您所看到的,Google决定他们根本不想让IDE使用环境变量; 我仍然坚持这个决定.更新local.properties指向可以在我的gradle脚本中加载的绝对路径让我的生活变得痛苦,我仍然没有想到如何做(但是看起来并不那么难).这意味着我要么强迫我的团队成员使用与我相同的路径,玩链接,让他们在每次拉回购物时都输入它们,或添加自动化脚本.我认为这是一个糟糕的决定,任何依赖于env vars的开发人员都会花费时间,这些开发人员在微观层面可能很小,但在宏观层面却很大.
groundloop,我相信IDE很快就会更新,能够将NDK文件夹路径添加到你的项目中,并且它将自动生成local.properties文件(至少如果他们没有想到它就没有意义这个).
有关Google的更多详细示例,请参阅以下最新示例(搜索jni或ndk):https://docs.google.com/viewer ?a = v& pid = sites & ssidid = YW5kcm9pZC5jb218dG9vbHN8Z3g6NDYzNTVjMjNmM2YwMjhhNA
使用NDK的跨平台胖子APK:
最后,使用gradle并且无法提供自己的Android.mk文件存在缺陷,因此您只能将第三方本机库从单个体系结构链接到NDK.注意我说"链接".您可以使用"abiFilters"命令在多个体系结构中构建NDK模块(上面的moduleName),它们将被放置在您的应用程序中,以便可以在多个体系结构上使用相同的APK.如果你需要在自己的第三方库中链接,或者根据你的架构有不同的cFlags值,那就没有一个简单的方法.
我尝试了以下内容,它似乎首先工作,但后来我发现它只是通过从两个ndk部分(或类似的东西,它以某种方式构建多个架构库,但它确实构建了多个架构库)来构建NDK:
android {
compileSdkVersion 23
buildToolsVersion '23.0.1'
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 28
versionName "3.0"
}
buildTypes {
def commonLibs = " -lfoo -lbar -lwhatever"
def armV7LibsDir = "/whatever/armv7a/libs"
def armX86LibsDir = "/whatever/x86/libs"
def armV7IncDir = "/whatever/armv7a/include"
def x86IncDir = "/whatever/x86/include"
debug {
ndk {
cFlags = "-I" + armV7IncDir
moduleName "myNativeCPPModule"
stl "stlport_shared"
abiFilter "armeabi-v7a"
ldLibs "log -L" + armV7LibsDir + commonLibs
}
ndk {
cFlags = "-I" + armX86IncDir
moduleName "myNativeCPPModule"
stl "stlport_shared"
abiFilter "x86"
ldLibs "log -L" + armX86LibsDir + commonLibs
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
在试图用gradle和本地第三方库创建一个干净的庄园中的胖二进制之后,我终于得出结论,谷歌Play的内置多架构支持APK无论如何都是最好的路径,所以创建每个架构的个人APK.
所以我创建了多个buildTypes,没有产品风格,并添加了以下代码来生成每种类型的版本代码.
// This is somewhat nasty, but we need to put a "2" in front of all ARMEABI-V7A builds, a "3" in front of 64-bit ARM, etc.
// Google Play chooses the best APK based on version code, so if a device supports both X86 and
// ARM, it will choose the X86 APK (preferred because Inky ARM running on an X86 with Houdini ARM Emulator crashes in our case)
android.applicationVariants.all { variant ->
if (variant.buildType.name.equals('release')) {
variant.mergedFlavor.versionCode = 2000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debug')) {
variant.mergedFlavor.versionCode = 2000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debugArmV8a')) {
variant.mergedFlavor.versionCode = 3000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('releaseArmV8a')) {
variant.mergedFlavor.versionCode = 3000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debugMips')) {
variant.mergedFlavor.versionCode = 5000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('releaseMips')) {
variant.mergedFlavor.versionCode = 5000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debugMips64')) {
variant.mergedFlavor.versionCode = 6000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('releaseMips64')) {
variant.mergedFlavor.versionCode = 6000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debugX86')) {
variant.mergedFlavor.versionCode = 8000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('releaseX86')) {
variant.mergedFlavor.versionCode = 8000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('debugX86_64')) {
variant.mergedFlavor.versionCode = 9000 + defaultConfig.versionCode
} else if (variant.buildType.name.equals('releaseX86_64')) {
variant.mergedFlavor.versionCode = 9000 + defaultConfig.versionCode
}
}
Run Code Online (Sandbox Code Playgroud)
现在,您所要做的就是在defaultConfig对象中设置versionCode的值,就像您通常那样,并根据构建类型将其附加到特定于体系结构的版本字符串的末尾.版本字符串对于所有版本保持不变,但会改变代码以提供从ARM一直到X86_64的优先顺序.它有点hackish或硬编码,但它完成了工作.请注意,这为您提供了多达999个版本,因此如果您需要更多版本,请将上面的数字乘以10,不确定您可以为版本代码添加的最大值.
就我而言,我们有一个相当复杂的构建系统.我们为9个架构构建了CPython,其中3个是Android,然后构建了一堆我们自己的库,并将它们全部链接到每个架构的单个库中.我们使用ndk命令行构建工具,automake和python来构建所有内容,而不是Android.mk文件.然后将最终的库链接到单个JNI接口cpp文件(上面称为myNativeCPPModule).只需单击一下按钮,一切都可以同时构建,非常漂亮的Android Studio.
use*_*906 34
找到了答案.包括ndk.dir=path/to/ndk在local.properties文件中做了伎俩.
更新: 在最新版本的Android Studio上,您可以直接在项目结构> SDK位置设置值.
| 归档时间: |
|
| 查看次数: |
59180 次 |
| 最近记录: |