Android Studio中项目NDK原生部分整合方式

UPDATE 2016.11.14:
目前的新版Android Studio 2.2已经可以完美支持NDK原生代码整合,通过cmake以及lldb实现c/c++代码调试,并且支持代码补全等功能!

自从Android Studio出现以后,我就很少再使用Eclipse+ADT的组合做Android开发了,更快的反应速度和更人性化的操作方式以及智能感知方面等等的优势,确实体现出了Google最初宣传Android Studio时的大部分特点,不过这些种种优势目前还只是体现在Java应用开发部分,而对于需要用到C/C++的Android NDK开发时,目前还没有很好的支持,当然,参考目前Android Studio的版本迭代速度来看,这应该也只是时间问题,当初ADT刚出的时候也是问题多多,包括后来的CDT+NDK支持,最初也只是支持原生代码的编译生成so,过了很久很久的某次update才加入了原生代码的可视化调试功能(当时也是历尽万难才测试成功的,还只是很简单的混合ndk项目…)。

最近看到了ndk又更新到了r10b版本,而且又据说新版的Android Studio中已经加入了一些ndk支持,于是正好一次测试一下(Android Studio beta 0.8.14, android-ndk32-r10b-windows-x86_64):

最初想到的用Android Studio和NDK的方式是单独编译链接JNI部分代码,然后将生成的so想办法在Android Studio的gradle生成系统中加入进去,这样就能完成最JNI操作,后来发现Android Studio项目中的app.iml文件中有这样一句:

<sourceFolder url=”file://$MODULE_DIR$/src/debug/jni” isTestSource=”false” />

发现现在的版本应该是支持管理NDK部分代码的,于是直接将jni部分代码复制到app\src\main\jni下,执行生成项目操作,得到错误提示:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ‘:app:compileDebugNdk’.
> com.android.ide.common.internal.LoggedErrorException: Failed to run command:
D:\android-ndk-r10b\ndk-build.cmd NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=D:\Projects\…\app\build\intermediates\ndk\debug\Android.mk APP_PLATFORM=android-19 NDK_OUT=D:\Projects\…\app\build\intermediates\ndk\debug\obj NDK_LIBS_OUT=D:\Projects\…\app\build\intermediates\ndk\debug\lib APP_ABI=all
Error Code:
2
Output:
make.exe: *** No rule to make target `D:\Projects\…\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/app/D_\Projects\…\app\src\main\jni’, needed by `D:\Projects\…\app\build\intermediates\ndk\debug\obj/local/armeabi-v7a/objs/app/D_\Projects\…\app\src\main\jni\main.o’. Stop.
* Try:
Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

不难看出,默认情况下,存在src/main/jni文件夹时,gradle生成脚本会执行ndk编译生成操作,但是,编译生成方式并不是像以前那样用ndk-build去处理Android.mk Application.mk等做c/c++代码的编译链接,而是在临时文件路径中重新生成了一份带有jni文件夹中所有文件绝对路径的mk文件,并以此作为ndk编译项目,姑且不说生成mk中的参数是否正确,单就是一个绝对路径问题就导致了上面提示的错误,明显mk中的source没有被正确找到(据说新版ndk是可以识别绝对路径的,不过我这还是没试验成功),然后参考最后给出的stackoverflow问答,发现可以通过在app的build.gradle中加入配置:

sourceSets.main {
jni.srcDirs = []
jniLibs.srcDir ‘src/main/libs’
}

的方式来屏蔽掉默认的jni编译生成过程,这样执行gradle生成时就不会再处理jni中的原生代码,而由手动调用ndk-build方式去生成so动态链接库,同时下面的jniLibs.srcDir重定位生成库文件夹为ndk-build默认生成的libs文件夹(这个默认是src/main/jniLibs,当然是默认生成jni脚本执行成功的话,如果想保留不变的话也可以修改一下手动执行ndk-build时的生成路径),这时再调试运行就可以正确的嵌入native库文件执行了。最后stackoverflow的链接中还给出了额外配置整合到gradle脚本中的buildNative和cleanNative方法,随IDE一起执行自定义的生成操作,保证command line正确的话性质是一样的。

UPDATE1:

经过上述设置之后虽然打包so到apk的过程没有问题了,但是如果要进行ndk-gdb调试的话,还需要进入项目属性中设置JNI调试选项(如下图),否则会提示”ERROR: Non-debuggable application installed on the target device.Please re-install the debuggable version!”,也就是没有将Debug需要的gdbserver及gdb.setup打入包内。

QQ截图20141212095909
参考文章:

博主友情提示:

如在您的评论中需要提及如QQ号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具v2<<加密后发布,原文只有博主可以看到。