The new NDK support in Android Studio 1.3

原文地址: http://ph0b.com/new-android-studio-ndk-support/


During Google I/O 2015, end of May, Google announced a new support for the NDK by Android Studio 1.3, integrating Jetbrains CLion capabilities, and the Android gradle plugin. This support has been released only in July, and while it’s really promising, it’s still in heavy development.

The new NDK support requires the use of Android Studio 1.3 RC1+/2.0+ and the android gradle-experimental plugin. This article is for those who are willing to give it a try. If you’re looking into the NDK support while using the gradle(-stable) plugin, you can check this older (but still up-to-date) article on the NDK and Android Studio.

article last updated on 2016/01/26 (gradle-experimental 0.6.0-alpha7 – Android Studio 2.0 preview 7, support for native dependencies!)

Migrating to the gradle-experimental plugin and the new com.android.model.*

The gradle-experimental 0.6.0-alpha7 requires using gradle-2.10. Start by setting it from your project settings:

gradle-2-5

Or inside gradle/wrapper/gradle-wrapper.properties:

Then, change the reference to the android gradle plugin to the new gradle-experimental plugin, from ./build.gradle:

The gradle-experimental plugin introduces a change in the DSL. The android plugins com.android.model.application and com.android.model.library are replacing the former com.android.application and com.android.library plugins.

You need to migrate your apps and libs build.gradle files to use these new plugins. Here is an example of the same configuration, with the old DSL (top) and the new (bottom):

To summarize the changes required: all the android declarations are now going under model {}, the various assignments now have to use explicitly ‘=, collections must not be overwritten, use .removeAll(), .add(), .addAll() instead. Variants and other new configurations have to be declared using ‘create()‘. Properties like xxxSdkVersion have changed to xxxSdkVersion.apiLevel.

As it’s experimental, you can expect regular changes around the DSL across versions. For example, minifyEnabled has been changed to isMinifyEnabled, then to minifyEnabled again, and now there is also useProguard; jniDebuggable has been changed to isJniDebuggable and then to ndk.debuggable (and is now set by default for debug builds).

You’ll notice that with both DSLs, there is a configuration block for the NDK. This is the place where you’re supposed to set all the NDK configuration when using gradle, as by default Android.mk and Application.mk files will be simply ignored.

Enjoying the new C++/NDK support in Android Studio

To activate the C++/NDK support inside Android Studio, you only need to have a NDK module declared inside your application or library build.gradle:

Once it’s done, you can go to your Java sources, create a method prefixed with the native keyword, and press ALT+Enter to generate its C or C++ implementation:

AS-ndk-demo

Yes, it’s that magical :)

The implementation will be added under ‘jni‘, inside an existing cpp file if there is one, or inside a new one.

In order to get started with NDK modules, you can have a look at all the samples that have been ported to use the new gradle-experimental plugin: https://github.com/googlesamples/android-ndk

Here is everything you can configure for a ndk module:

Debugging a NDK project

In order to get the debug capabilities of AS, create and use a new Run/Debug configuration from the “Android Native” default. While it was possible to use GDB in Android Studio 1.3, now only the LLDB backend is available.

native-debug-config

Use it with your debug variant, which will have ndk.debuggable flag set to true by default.

Going further with the NDK with Android Studio

Many advanced features, such as the ability to have dependencies between native libraries, reuse prebuilts, tune specific toolchain options and having dynamic version codes while still having a project in a good shape is a bit complex, as the gradle-experimental plugin is still undergoing a lot of improvements across versions.

Getting the APP_PLATFORM right

When you’re building a NDK module, the android platform you’re compiling it against is a quite important setting, as it basically determines the minimum platform your module will be guaranteed to run on.

With earlier versions than gradle-experimental:0.3.0-alpha4, the chosen platform was the one set as compileSdkVersion. Fortunately with subsequent releases, you can now set android.ndk.platformVersion independently, and you should make it the same as your minSdkVersion.

Using external libraries and separate modules

with sources

If you have access to your 3rd party libraries source code, you can embed it into your project and make it statically compile with your code.

There is an example of this with the native_app_glue library from the NDK, inside the native-activity sample. For example, you can copy the library sources inside a subfolder inside your jni folder and add a reference to its directory so the includes are properly resolved:

with sources in different modules

Now with 0.6.0-alpha7 version, you can finally have clean dependencies between native libraries, by setting the dependency on another module from your model:

In order to keep debugging working, you may have to edit your app-native run configuration, to add /build/intermediates/binaries/release/obj/[abi] to the symbol directories.

with native prebuilts

This technique works with static and shared prebuilts too! Inside your model, you’ll have to add a “lib repository”:

And declare the dependency on this library:

Shared linkage is the default, but of course you can use static prebuilts by using a static linkage, and declaring StaticLibraryBinary/staticLibraryFile variables.

Multiple APKs

When you publish multiple APKs (per architecture, per density, etc), you have to give them different version Version Codes. I couldn’t find a way to do it with the current DSL, neither when using splits or abiFilters and flavors. If you do see a way, plese contact me and I’ll add it there. For now, I would advise to go back using the stable gradle plugin.

The good news is you can mix use of the stable gradle plugin, and the new experimental one, even while keeping debug features working! Please follow this gist.

Using Android.mk/Application.mk

If the built-in gradle support isn’t suitable to your needs, you can get rid of it, while keeping the goodness of Android Studio C++ editing.

Declare a module that correctly represents your configuration, as this will help AS to correctly resolve all the symbols you’re using and keep the editing capabilities:

Then, set the jni sources location to a non-existing folder, and the jniLibs location to libs, the default directory in which ndk-build will put the generated libs:

This way, you can call ndk-build(.cmd) yourself from the root of your src/main directory, that will use your usual Android.mk/Application.mk files under the jni folder. Your libs will be generated inside libs/<ABI> as usual and get included inside your APK.

You can also add this call to ndk-build inside your gradle configuration:

Additional Resources

Tweet about this on Twitter Share on Google+ Share on Facebook Share on LinkedIn Share on Reddit Email this to someone

Published by

Xavier Hallade

Software Engineer working at Intel Software and Service Group (SSG) in Paris, France. Google Developer Expert for Android.Helping developers to make a better use of Intel-based platforms, with a focus on the Android NDK. View all posts by Xavier Hallade

Posted on August 17, 2015 Categories Android Tags Android, Android Build System, Android Studio, gradle, NDK

37 thoughts on “The new NDK support in Android Studio”

  1. Perfect tutorial! Thanks Xavier!
    Any idea when this plugin becomes will be officially released?

    1. Thanks Nelson!
      Everything is already released and advertised as “the official way”, even if the gradle-experimental plugin is.. experimental.
      I don’t know when the experimental plugin and the new DSL will replace the current stable ones.
      I’d expect this to happen around the Marshmallow release timeframe.

  2. John Anderson says:

    Thanks for the tutorial! I tried following the “Using Android.mk/Application.mk” and was hoping to see my C++ source files in Android Studio but when I set my jni.srcDirs to a non-existent folder the sources are removed from my project. Do you know if there is there a way to keep the sources in Android Studio for editing/debugging but have the build done by ndk-build?

  3. Alex Cohn says:

    To fall back to Android.mk/Application.mk, I prefer to provide the actual jni directory (or directories), but disable the build step:

    tasks.all {
    task -> if (task.name.contains('compileDebugNdk') || task.name.contains('compileReleaseNdk')) task.enabled = false
    }

  4. Steve Madsen says:

    I wanted to try to use Android.mk/Application.mk as outlined above, so downloaded the new samples from:
    https://github.com/googlesamples/android-ndk
    and modified the Teapot sample as follows:
    * Copied Android.mk and Application.mk from the legacy sample project
    * Added task ndkBuild(type: Exec) as described on your legacy ndk page
    * Defined NDK_APP_OUT and NDK_APP_LIBS_OUT in Application.mk (because new lib location is e.g.
    app/build/intermediates/binaries/debug/arm7/lib/armeabi-v7a)

    Anyway, by setting those values the .apk is built automatically (ndk-build is called as usual, no manual command line required) and runs OK, but C++ debugging doesn’t work; by restoring android.sources.main.jni.source.srcDirs so it points to the actual jni folder (and commenting out the ndk-build task) C++ debugging works properly in Android Studio.

    Any ideas what I’m doing wrong? Thank you

  5. Francesco says:

    Hey Xavier.
    Nice tutorial. Thanks for that!
    We are currently struggling around with getting a referenced JNI Android library module inside the same Android Studio project debuggable in another Android application module. We currently are using “compile project()” to reference the JNI lib. You are already mentioning that debugging external libraries are not supported yet. You solution would be to copy the source code into some folder of the actual Android module. We really don’t want to copy the files to achieve that. Isn’t there any other solution that come to your mind?

  6. Steve Madsen says:

    I tried your updated instructions for using Android.mk/Application.mk with experimental gradle (goal is C++ debugging in Android Studio to retire Eclipse). But, getting this error:

    Would prefer to not have to use workarounds if possible, do you have any ideas? (Thank you again for maintaining these pages, they are very useful resource)

    1. Steve Madsen says:

      P.S.
      Tried adding this to app/build.gradle but to no avail:

  7. Steve Madsen says:

    P.S.2
    By changing jniLibs I avoid the duplicate error above, and the app builds and runs — but no C++ debugging in android studio (breakpoints ignored, though the pause/start buttons in the Debugger window work)

    And of course, the build variant shouldn’t be hardcoded like this (debug, arm should be replaced by variables)

  8. Steve Madsen says:

    Having troble setting main.jniLibs.source.srcDirs as instructed above — using this:

    I get this error:

    For some reason the gdb.setup is problematic, an attempt is usually made to install it twice resulting in some sort of “duplicate” error.

    1. Koki says:

      Hi,
      This is really nice tutorial.
      I wonder if there has been any findings on this issue.
      I’ve been facing exactly the same message, i.e. “Failed to add /……./gdb.setup”, and I can’t find any other site mentioning this message.
      My setup is gradle 2.6 with experimental-plugin 0.3.0-alpha7 targeting native debugging.

  9. Steve Madsen says:

    Just a followup to a previous comment: I think some of the problems I was having may have been due to attempting to include the (incompatible?)

    switch to ndk-build e.g.

    (Still can’t get breakpoints to work, just start/pause control from Android Studio debugger panel)

    1. Hi Steve,
      I’ve got the same troubles to get NDK debugging working with AS 1.4/1.5 and the gradle-experimental plugin while keeping Makefiles.
      It was working for me before 1.4 release when using GDB backend, which doesn’t seem to be available anymore.

      1. Ronnie Erickson says:

        Any idea how to get around this? I am dealing with trying to move a really complex build that uses a lot of common code for other platforms over to Android Studio. I can build it fine with using my own Android.mk/Application.mk like I did with ADT. But I can’t build with the experimental gradle because I can’t find a way to define all of the common files that are needed that sit outside of the jni directory. Any thoughts on how I could build about 300 cpp files in multiple directories that are not inside the jniSource directory? In addition to that, our make files pull in some static libraries that we use.

        I’ve been scouring the web since Google really hasn’t had great documentation…especially in terms of their definition of “NDK Support”. Your blog has been the most useful. Thanks!

        1. Victor Mak says:

          Hi, Ronnie. I am encountering the same situation, any clues yet? Thanks!

        2. Here is a snippet that may help you to add all your external source directories to your build:

          def extSourcesDirsPath = “…”
          cppFlags += “-I${file(extSourcesDirsPath)}”.toString()
          file(extSourcesDirsPath).eachDirRecurse { dir ->
          cppFlags += “-I${file(dir)}”.toString()
          }

      2. Steve Madsen says:

        Thank you Xavier — I noticed a couple of weeks ago the SDK added module “LLDB” in SDK Tools — hopefully this will eventually restore functionality lost when gdb support was removed from Android Studio 1.4.

  10. Rocky says:

    Thanks Xavier!
    I followed the step to create a native method and press ALT+Enter
    but it always generate a .c file.
    How can I use ALT+Enter to generate a .cpp file?

    1. Hua says:

      I encountered the same problem as you.

  11. Feisal says:

    I have some c++ source code with dependencies to OpenCV, would I be able to link them using gradle build?

  12. Anthony says:

    Great post, thanks for keeping up with the updates and going into more than cursory detail. Where do you get the information on each new release? I can follow the releases on the repository, but I can’t seem to find any release notes anywhere.

  13. Krishna says:

    Hello Xavier, Thanks for the detailed steps.. its a cake walk.
    In the tutorial you mentioned – “you can go to your Java sources, create a method prefixed with the native keyword, and press ALT+Enter to generate its C++ implementation:”
    when i did the same, its generating C implementation instead of C++; I have some C++ dependencies. How to get the C++ implementation instead of C implementation.

    Reply is appreciated.

    1. You’re right, it’s generating a C implementation when you don’t have sources yet, not a C++ one.
      I don’t know a way to automatize this, but you can simply rename the file to cpp, and change the (jniEnv*)->XXX(env, …) calls to jniEnv->XXX(…) to make it C++.

  14. Olivier Roblin says:

    Hi Xavier,
    Thanks a lot for the post!
    I have an issue with the native debugger (it just doesn’t work, doesn’t stop at breakpoints, etc…). The issue occurs either if I build native code with gradle or with Android.mk/Application.mk like you describe.
    The problem may be due to my specific overall architecture : The app module depends to a library module in which I have my native .so libs. For debugging, I run the app with the native debugger but the native code to attach the debugger is inside the library module.
    In the Debug configuration, I add ‘moduleLib/src/main/obj/local/armeabi-v7a’ directory to the “Symbol directories”.
    This used to work with ADT.
    Do you have an idea of what is wrong ?
    Have you ever tried to debug native code inside a Java Library module ?

    Thanks,

    1. Hi,

      I’m using a library module in one of my projects too and I got debug working well.

      I had to add ./build/intermediates/binaries/*release*/obj/[abi] to the Symbol directories.

      Here is a gist extracted from my project: https://gist.github.com/ph0b/0575b30b67e04f2ec10f

  15. Olivier Roblin says:

    Yes it works!
    I added symbols from src/main/obj/local/[abi] in the case of Android.mk/Application.mk build. It doesn’t work.
    For the gradle build case, I don’t remember which symbol directory I added but certainly not the good one. With ‘./build/intermediates/binaries/*release*/obj/[abi]’, it’s ok.
    Thanks Xavier.

  16. Jimmy says:

    I went through the tutorial over and over again, tried every permutation of the solutions in StackOverflow, and I’m still getting the message:

    Error:Gradle version 2.9 is required. Current version is 2.10.

    Do you have any idea of what could be wrong? I changed gradle-wraper.properties manually, tried to set it on the module settings, went to every single line over and over again, but still nothing.

    1. There are strong requirements regarding the various versions you’re using between gradle, gradle-experimental plugins and gradle itself.
      You can use gradle-experimental:0.6.0-alpha7 and/or gradle:2.0.0-alpha7 with gradle 2.10 – I’ve updated the article accordingly.
      Earlier alphas (I don’t remember which one exactly) needed gradle 2.9 – I’m trying to stick to the latest versions of everything, until anything becomes stable :)

      1. Jimmy says:

        Hi Xavier, thanks for the help! Now I get the following error:

        Error:Exception thrown while executing model rule: BaseComponentModelPlugin.Rules createBinaryTasks
        java.lang.NullPointerException (no error message)

        Do you have any idea of what could be wrong? I have been using eclipse for Android Development for 4 years, and I can’t believe that I have such difficulty switching to AS. I have 3 days working on this :S

        1. That’s the problem with the alpha status, the error messages are still mostly cryptic.. Maybe there is a syntax error somewhere, like in this issue: https://github.com/googlesamples/android-ndk/issues/146

  17. Olivier Roblin says:

    Hi Xavier,
    I have another question :
    * When I build my native code with former Android.mk/Application.mk, I don’t succeed in attaching the symbols and the debugger doesn’t work. (I add myLib/src/main/obj/local/[abi], which contains the symbolicated .so, to the Symbol directories).
    Do you know if it should work ? Have you ever tried this ?
    * The problem is actually critical, because I would have to include pure assembly files in my build. You already answered to someone (here : http://stackoverflow.com/questions/32092144/how-to-compile-android-ndk-with-gradle-that-contain-arm-assembly-optimizaions) that it’s probably not supported by gradle build. Still not more information about this ?

    Olivier

    1. You mean that you need to have breakpoints and symbols resolution working in your ndk code compiled with Android.mk/Application.mk, inside AS?
      I have tried it a bit and failed, like you did. Maybe there is a way to make it work, but I haven’t found it.

      For your use case, I’d generate static prebuilts using ndk-build, that are only including your assembly files and make them usable to other modules that will be compiled using gradle (see this gist for native dependencies: https://gist.github.com/ph0b/418132cb2f3f03a5534c). This way you will not have symbols and debugging from AS for all of your code, but at least you’ll have it for most of it.

  18. Olivier Roblin says:

    Yes that’s exactly what I currently do.
    But I wondered if you had a solution because you say “If the built-in gradle support isn’t suitable to your needs, you can get rid of it, while keeping the goodness of Android Studio C++ editing/debugging.”
    I thought you succeeded in debugging build from manual ndk-build.

    Thanks anyway,
    Olivier

    1. I actually did earlier, when it was possible to use the gdb backend. Now that only lldb is available I couldn’t make it work with Android.mk/Application.mk – I’ll update the article accordingly.

  19. Olivier Roblin says:

    Do you know if it’s possible to add ABI specific options in gradle ? For example, adding
    cppFlags.add(“-DUSE_NEON=1”) for armv7 build
    and cppFlags.add(“-DUSE_IPP”) for x86 build ?

    Of course, having different flavors would do the job, but I would prefer to have my x86 and armv7 libs in a single apk.

    Is it possible to test the ABI in gradle, somethink like :
    if (abi == “x86”) cppFlags.add(“-DUSE_IPP”) ?

    Beside, is it possible to add cppFlags for some files only ?

    Or the only way to do that is having different flavors and different apk ?

    1. I don’t see a way to do this yet outside of Android.mk or flavors.
      Although in your case, if it’s only to have various defines depending on the ABI, you could include a config header through cppFlags (-include xxx.h), and in that header, have your defines defined according to each ABI.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值