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号、微信号、电子邮件地址或其他隐私敏感信息,欢迎通过>>博主专用加密工具<<加密后发布,原文只有博主可以看到。

  1. 你好!我现在想用android studio 进行NDK 调试,但是不知道如何调试,请求帮助!qq:2401261571 求大神指导

  2. 你好,我的QQ/微信是340007726 。我希望在android studio里运行一段C代码,但是这几天配置一直失败,麻烦你加一下我的QQ指导我一下,谢谢。。。已经疯了。。

  3. 我使用Android Studio,我的so已经放到设备上了,只是不知道怎么使用ndk-gdb,我照网上的设置了,我是在windows下的

  4. 哥们,有试过使用AS+NDK编译可执行程序么?现在的AS已经升级到1.2.1.1了。src/main/jni/Android.mk 里面,这文件貌似沦为只是个辅助的编译脚本了。而指定需要编译哪些模块,必须在 build.gradle 的 android { ndk { moduleName “xxx” }} 来指定。但是指定的 xxx 名字是动态库的名字,生成的文件会自动在这个名字前后加上 lib 和 .so 的前后缀。想编译生成一个可执行的 NDK 项目,有什么思路么?

    • 你好,Android Studio在我写这篇记录的时候就是没有像Eclipse那样直接调用ndk-build编译项目jni文件夹中的原生代码。看来新版本的又更进一步无视mk的方式了,可以试试屏蔽build.gradle中的默认jni处理逻辑,然后加入调用命令行ndk-build的方式在jni中执行mk编译,可以参考我上面写的方法。

  5. jni 调试进不去, None of the 1 split apks are compatible with the current device with density 480 and abis armeabi-v7a, armeabi.搞不清楚是什么原因,能帮我看看么? 我的Q是:741227905,多谢了!

  6. 你好,请问知道如何在android studio断点调试c++代码呢?还是AS不支持?能否加q聊聊,309190656

    • 你好,AS目前的版本,至少是我写这篇博文的时候是不支持调试原生代码的,一直在改进的也只是能顺便完成ndk-build的原生代码编译打包so进apk的工作。如果需要可视化调试android ndk代码的话建议使用VS+Visual GDB完成,可以接受命令行模式的话直接用ndk自带的ndk-gdb就可以。

  7. Starting LLDB server: run-as hejie.com.rsa /data/data/hejie.com.rsa/lldb/bin/start_lldb_server.sh /data/data/hejie.com.rsa/lldb /data/data/hejie.com.rsa/lldb/tmp/platform.port1446387419935 “lldb process:gdb-remote packets”
    Now Launching Native Debug Session
    Failed to attach native debugger: unknown error

  8. 我想用android studio 直接debug jni 但是不行,后又用VS2005+android studio还是不行,好苦恼。。。

  9. 你好,由于使用的第三方sdk只提供了armeabi和x86两个平台下的so文件,所以对其他第三方sdk也只保留了这两个平台下的so,在使用compile ‘com.facebook.fresco:fresco:0.8.1’集成fresco的时候,由于fresco包含了armeabi-v7a、x86_64平台下的so,所以导致在armeabi-v7a手机上找不到其他第三方so文件,报java.lang.UnsatisfiedLinkError错误,请问怎么配置能在打包的时候只打包armeabi和x86两个平台下的so文件。QQ 632689688 望指教万分感谢

  10. Error:(452) undefined reference to `AAsset_openFileDescriptor’
    Error:error: ld returned 1 exit status
    Error:Execution failed for task ‘:app:compileDebugNdk’.
    > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process ‘command ‘C:UsersCrazyBoaDownloadsandroid-ndk-r10endk-build.cmd” finished with non-zero exit value 2博主,我用别人的项目,总报这个错误,是什么问题,博主有空能不能回答我一下,谢谢啦

    • 就是我现在自己那个jni文件下面那个.h文件中#include<jni.h>一直报红,我在网上找了好久,有的说是要导入ndk,我导入了可是他还是报错,翻译后:
      错误:执行失败的任务“myapplication:compileDebugNdk”。
      > com.android.ide.common.process.ProcessException:org.gradle.process.internal.ExecException:过程‘命令’D: android-ndk64-r10-windows-x86_64 android-ndk-r10 ndk-build。cmd”完成了非零退出值2
      怎么就成这样了呢?求指教一下啊

      • 这个先手动执行一下命令行ndk-build,看看具体提示的是什么错误,看现象可能是ndk环境没有配置正确,也可以直接用ndk里的samples编译下看是否有问题。

  11. Pingback: Android Studio NDK开发环境配置 – Flass Blog

  12. 您好,我这个项目是公司之前同事用 eclipse写的,现在想转到AS,但是通过AS导入eclipase项目后,里面就一直报错,麻烦能不能加一下QQ帮看一下

    错误提示信息:
    Error:In file included from E:ASMyWorkspaceUserTextautostartLibraryCppsrcmainjnicommoncommon.c:11:0:
    D:/AS/androidstudio/androidNDK/android-ndk-r9d/toolchains/arm-linux-androideabi-4.6/prebuilt/windows-x86_64/bin/../lib/gcc/arm-linux-androideabi/4.6/include-fixed/stdio.h:50:23: fatal error: sys/cdefs.h: No such file or directory
    compilation terminated.
    make.exe: *** [E:ASMyWorkspaceUserTextautostartLibraryCppbuildintermediatesndkreleaseobj/local/armeabi-v7a/objs/autostartLibraryCpp/E_ASMyWorkspaceUserTextautostartLibraryCppsrcmainjnicommoncommon.o] Error 1

    FAILURE: Build failed with an exception.

    * What went wrong:
    Execution failed for task ‘:autostartLibraryCpp:compileReleaseNdk’.
    > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process ‘command ‘D:ASandroidstudioandroidNDKandroid-ndk-r9dndk-build.cmd” finished with non-zero exit value 2

    * Try:
    Run with –stacktrace option to get the stack trace. Run with –info or –debug option to get more log output.

    还有一个警告:
    Warning:Native C/C++ source code is found, but it seems that NDK option is not configured. Note that if you have an Android.mk, it is not used for compilation. The recommended workaround is to remove the default jni source code directory by adding:
    我在网上差了很多方法也没解决

  13. 我加了 sourceSets.main {
    jni.srcDirs = []
    jniLibs.srcDir ‘src/main/libs’
    } 但是 还是有那个警告

    警告:本机C / C++源代码是找到了,但似乎没有配置NDK选项。注意,如果你有一个Android.mk,它不是用来编译。建议的解决方法是通过添加删除默认的JNI的源代码目录:

    • 你好,先说刚才的编译问题,eclipse下是不会报错的么?或者建议先用ndk-build手动编译一下项目中的jni部分,看看有没有问题

      • Execution failed for task ‘:autostartLibraryCpp:compileReleaseNdk’.
        > com.android.ide.common.process.ProcessException: org.gradle.process.internal.ExecException: Process ‘command ‘D:ASandroidstudioandroidNDKandroid-ndk-r9dndk-build.cmd” finished with non-zero exit value 2

        返回值 为2 是什么意思呀 我对 eclipse不怎么懂 也不知道 之前是怎么写的

        • 这个是ndk-build报错了,就是刚才我说的手动编译一下jni部分,看看有没有问题,我写的这个方法其实就是不让AS内置的ndk功能进行原生代码编译,因为当时我用的版本这个功能很不完善,不知道现在的2.x是不是改进了。所以你必须保证ndk环境以及直接ndk-build你的项目时没有问题。