Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[Xavier Hallade] Mastering the NDK with Android...

[Xavier Hallade] Mastering the NDK with Android Studio 1.3+ and the gradle-experimental plugin

Presentation from GDG DevFest Ukraine 2015 - the biggest Google related event in the country. October 23-24, Lviv. Learn more at http://devfest.gdg.org.ua/

Avatar for Google Developers Group Lviv

Google Developers Group Lviv

October 24, 2015
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Programming

Transcript

  1. Mastering the NDK with Android Studio 1.3+ and the gradle-experimental

    plugin Xavier Hallade Developer Evangelist @ Intel
  2. #dfua Mastering the NDK - Agenda The Android NDK Brief

    history of Android Studio support of the NDK What we can do now with Android Studio Migrating to the gradle-experimental plugin Configuring your projects Q&A
  3. #dfua Java Native Interface (JNI) Java side • System.loadLibrary() •

    native keyword C/C++ side - #include <jni.h> • Java primitive types, objects, methods • JNIEnv*, JavaVM*
  4. #dfua 6 Mapping C/C++ implementations to Java methods use and

    return Java primitives and objects jint xxx(JNIEnv* env, jclass cls, …) use a specific function name: Java_com_example_hellojni_MainActivity_method or do a manual registration using JNIEnv->RegisterNatives()
  5. #dfua Uses Android.mk and Application.mk Makefiles. The NDK will generate

    optimized code for all target ABIs You can also pass APP_ABI variable to ndk-build, and specify each ABI: ndk-build APP_ABI=x86 all32 and all64 are also possible values. ndk-build(.cmd) Build ARM64 libs Build x86_64 libs Build mips64 libs Build ARMv7a libs Build ARMv5 libs Build x86 libs Build mips libs
  6. #dfua Classic* execution flow 1. .so files loaded in memory

    by System.loadLibrary() 1. C/C++ functions ó Java native methods 2. DVM/ART encounters a call to a native method 1. its C/C++ implementation is executed 2. then, Java code execution goes on * android.app.NativeActivity/ native_activity.h allow to develop without having Java code inside the app.
  7. #dfua Android Studio and the NDK – a brief history

    • December 2013: gradle 0.7.3 - sort of support for the NDK • December 2014: Eclipse ADT no longer in development • May 2015: Integration of CLion announced at Google I/O • July 2015: beta available! • October 2015: still quite WIP (-experimental), but usable!
  8. #dfua Solutions to use the NDK with gradle/AS gradle(-stable) plugin,

    deprecated Android NDK support gradle(-stable) plugin, manual call to NDK build gradle(-experimental) plugin, WIP-but-already-great Android NDK support gradle(-experimental) plugin, manual call to NDK build
  9. #dfua gradle(-stable) plugin, manual call to NDK build + stable

    + most configurable solution (using Android.mk/Application.mk) + supports generating split APKs with proper version codes - No C/C++ code editing/debugging within Android Studio
  10. #dfua gradle(-experimental) plugin, built-in NDK support + full code editing/debugging

    within Android Studio - it’s experimental - can’t generate split APKs with proper version codes - support for native dependencies is almost there
  11. #dfua gradle(-experimental) plugin, manual call to NDK build + full

    code editing within Android Studio + usual Android.mk/Application.mk support (with full native dependencies support) - it’s experimental - can’t generate split APKs with proper version codes - can’t debug from Android Studio
  12. #dfua Solutions to use the NDK with gradle/AS gradle(-stable) plugin,

    deprecated Android NDK support gradle(-stable) plugin, manual call to NDK build KJ -> http://ph0b.com/android-studio-gradle-and-ndk-integration/ gradle(-experimental) plugin, WIP-but-already-great Android NDK support J gradle(-experimental) plugin, manual call to NDK build J
  13. #dfua Gradle experimental plugin dependencies { classpath 'com.android.tools.build:gradle-experimental:0.3.0-alpha7' } com.android.model.application

    / com.android.model.library model{} .with{} = distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-all.zip
  14. #dfua Example of build.gradle update for gradle-experimental apply plugin: 'com.android.application'

    android { compileSdkVersion rootProject.ext.compileSdkVersion buildToolsVersion rootProject.ext.buildToolsVersion defaultConfig { applicationId "com.ph0b.example" minSdkVersion 15 targetSdkVersion 23 versionCode 4 versionName "1.0.1" ndk { moduleName "mymodule" ldLibs "log" stl "gnustl_static" cFlags "-std=c++11 -fexceptions" } } signingConfigs { release { storeFile file(STORE_FILE) storePassword STORE_PASSWORD keyAlias KEY_ALIAS keyPassword KEY_PASSWORD } } buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.txt' signingConfig signingConfigs.release } debug { jniDebuggable true } } } apply plugin: 'com.android.model.application' model { android { compileSdkVersion = rootProject.ext.compileSdkVersion buildToolsVersion = rootProject.ext.buildToolsVersion defaultConfig.with { applicationId = "com.ph0b.example" minSdkVersion.apiLevel = 15 targetSdkVersion.apiLevel = 23 versionCode = 4 versionName = "1.0.1" } } android.ndk { moduleName = "mymodule" ldLibs += ['log'] cppFlags += "-std=c++11" cppFlags += "-fexceptions" stl = 'gnustl_static' } android.signingConfigs { create("release") { keyAlias = KEY_ALIAS keyPassword = STORE_PASSWORD storeFile = file(STORE_FILE) storePassword = KEY_PASSWORD } } android.buildTypes { release { // signingConfig = signingConfigs.release // buggy, look for a workaround here: issue 182249 minifyEnabled = true proguardFiles += file('proguard-rules.txt') } } }
  15. #dfua NDK configurability android.ndk { moduleName platformVersion toolchain toolchainVersion cFlags

    cppFlags ldLibs ldFlags abiFilters stl renderscriptNdkMode debuggable } In the model, but not yet in the DSL: cIncludeDirs cppIncludeDirs cDefines cppDefines
  16. #dfua Native dependencies (with sources) android.ndk { moduleName = "TeapotNativeActivity"

    platformVersion = 17 cppFlags += "-I${file("src/main/jni/native_app_glue")}".toString() cppFlags += "-I${file("src/main/jni/cpufeatures")}".toString() cppFlags += "-I${file("src/main/jni/ndk_helper")}".toString() ldLibs += ["android", "EGL", "GLESv2", "dl", "log"] stl = "stlport_static" } build.gradle
  17. #dfua Adding a folder of native sources to be compiled

    android.sources { main.jni { source { srcDirs += ['src/main/XXX'] } } } build.gradle
  18. #dfua android.sources { main.jni { dependencies { project ":ndkLib" buildType

    "debug" linkage "static" } } } build.gradle Other solution (really experimental right now): Native dependencies (with sources)
  19. #dfua Using good old Android.mk/Application.mk import org.apache.tools.ant.taskdefs.condition.Os android.ndk { …

    } android.sources { main.jni { source { srcDirs = ['src/main/none'] } } main.jniLibs { source { srcDirs = ['src/main/libs'] } } } task ndkBuild(type: Exec) { def ndkBuildExt = Os.isFamily(Os.FAMILY_WINDOWS) ? ".cmd" : "" commandLine "ndk-build${ndkBuildExt}", '-C', file('src/main').absolutePath } tasks.withType(JavaCompile) { compileTask -> compileTask.dependsOn ndkBuild } build.gradle
  20. #dfua Native Dependencies android.productFlavors { create ("x86") { ndk.abiFilters +=

    "x86" ndk.ldFlags += "-L${file("src/main/jni/prebuilts/x86")}".toString() } } build.gradle Please don’t do this, as version codes can’t be properly handled.
  21. #dfua Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE :=

    hello-jni LOCAL_SRC_FILES := hello-jni.c include $(BUILD_SHARED_LIBRARY) • Other useful variables: LOCAL_C_INCLUDES := ./headers/ LOCAL_EXPORT_C_INCLUDES := ./headers/ LOCAL_SHARED_LIBRARIES := module_shared LOCAL_STATIC_LIBRARIES := module_static Other predefined macros: BUILD_SHARED_LIBRARY, BUILD_STATIC_LIBRARY, PREBUILT_SHARED_LIBRARY, PREBUILT_STATIC_LIBRARY
  22. #dfua 3 Application.mk APP_PLATFORM := android-15 # <= minSDKVersion APP_CFLAGS

    := -O3 APP_STL := gnustl_shared APP_ABI := all # or all32, all64… APP_OPTIM := release # default NDK_TOOCLHAIN_VERSION := 4.8 # default
  23. #dfua Multiple APKs and version codes handling Google Play* supports

    multiple APKs for the same application. What compatible APK will be chosen for a device entirely depends on the android:versionCode If you have multiple APKs for multiple ABIs, best is to simply prefix your current version code with a digit representing the ABI: 2310 3310 6310 7310 You can have more options for multiple APKs, here is a convention that will work if you’re using all of these: x86 ARMv7 ARM64 X86_64