mastering the ndk with android studio 2.0 and the gradle-experimental plugin

44
Mastering the NDK with Android Studio 2.0+ and the gradle-experimental plugin Xavier Hallade Application Engineer @ Intel

Upload: xavier-hallade

Post on 16-Apr-2017

20.340 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Mastering the NDKwith Android Studio 2.0+ and the gradle-experimental plugin

Xavier Hallade

Application Engineer @ Intel

Page 2: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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

Page 3: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

The Android NDKLet’s briefly reexamine what it is and how it works

Page 4: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

The Android NDK

Page 5: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Checking .so files

https://play.google.com/store/apps/details?id=co

m.xh.nativelibsmonitor.app

Page 6: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Java Native Interface (JNI)

Java side

System.loadLibrary()

native keyword

C/C++ side - .so files

#include <jni.h>

– Java primitive types, objects, methods

– JNIEnv*, JavaVM*

Page 7: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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 usingJNIEnv->RegisterNatives()

Mapping C/C++ implementations to Java methods

Page 8: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

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) – the historical tool

Build ARM64 libs

Build x86_64 libs

Build mips64 libs

Build ARMv7a libs

Build ARMv5 libs

Build x86 libs

Build mips libs

Page 9: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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.

Page 10: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Android Studio and the NDKWhere are we now?

Page 11: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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: first availability, with a lot of limitations

• Since April 7th (yesterday night!): first stable version of the experimental

plugin available, and everything is awesome !!

Page 12: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

AS NDK Code editingDemo

Page 13: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

13

Page 14: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Page 15: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

AS NDK DebuggingDemo

Page 16: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Page 17: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

How to get This?

Page 18: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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, experimental but stable since yesterday

• mixing gradle-stable and –experimental plugins

Page 19: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

gradle(-stable) plugin, deprecated Android NDK support

- bad APP_PLATFORM handling

- it’s deprecated!

Page 20: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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

~ C/C++ code editing inside Android Studio

- No C/C++ code debugging inside Android Studio

Page 21: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

gradle(-experimental) plugin, built-in NDK support

+ full code editing/debugging within Android Studio

+ good support for native dependencies since 0.6.0-alpha1

- it’s experimental and the documentation barely exists yet

- can’t generate split APKs with proper version codes

- Many incompatible plugins.

Page 22: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Mixing gradle-stable and gradle-experimental plugins

+ full code editing/debugging support within Android Studio

+ good support for native dependencies since 0.6.0

+ can generate split APKs with proper version codes

+ all the plugins are supported

- it’s experimental and the documentation barely exists yet

Page 23: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Using the right versions

Android Studio 1.5 2.0 2.1-preview5

gradle 2.8 2.10 2.10

gradle plugin 1.5.0 2.0.0 2.1.0-alpha5

gradle-experimental plugin 0.4.0 0.6.0 0.7.0-alpha5

Page 24: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Migrating to gradle-experimental

Page 25: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Gradle experimental plugin

dependencies {

classpath 'com.android.tools.build:gradle-experimental:0.6.0'

}

com.android.model. application / library / native

model{}

.with{}

distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip

.add() / .addAll() / .removeAll()

Page 26: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Example of build.gradle update to gradle-experimentalapply 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.addAll(['log'])

cppFlags.add("-std=c++11“)

cppFlags.add("-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 = $("android.signingConfigs.release“)

minifyEnabled true

proguardFiles.add(file('proguard-rules.txt'))

}

}

}

Page 27: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

NDK configurabilityandroid.ndk {

moduleNameplatformVersiontoolchain toolchainVersioncFlagscppFlagsldLibsldFlagsabiFiltersstlrenderscriptNdkModedebuggable

}

android.abis { // 0.7.0+

create("ABI") { //ABI can be any of x86, x86_64,

armeabi-v7a, arm64-v8a…

cppFlagsldLibsldFlags

}}

Page 28: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Android Studio configuration

Page 29: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Gradle configuration examples

Page 30: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

android.ndk {

moduleName = "TeapotNativeActivity"

platformVersion = 17

cppFlags.add("-I${file("src/main/jni/native_app_glue")}".toString())

cppFlags.add("-I${file("src/main/jni/cpufeatures")}".toString())

cppFlags.add("-I${file("src/main/jni/ndk_helper")}".toString())

ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log"])

stl = "stlport_static"

}

build.gradle

Native dependencies (with sources)

Page 31: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

android.sources {

main{

jni {

source {

srcDir 'src/main/XXX'//folder

srcDir 'src/main/YYY'//other folder

exclude "**/not_this_one.c" //single file

}

}

}

}

build.gradle

Adding/Removing native sources to be compiled

Page 32: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

repositories { libs(PrebuiltLibraries) { myexternallib {

headers.srcDir "src/main/jni/prebuilts/include"

binaries.withType(SharedLibraryBinary) {

sharedLibraryFile =

file("src/main/jni/prebuilts/${targetPlatform.getName()}/libmyexternallib.so")

}

}}}

android.ndk {

moduleName = "TeapotNativeActivity"

platformVersion = 17

ldLibs.addAll(["android", "EGL", "GLESv2", "dl", "log"])

stl = "stlport_static"

}

android.sources { main { jni { dependencies {

library "myexternallib" linkage "dynamic" //dynamic is default / can be static too

}}}}

build.gradle

Native dependencies (prebuilts)

Page 33: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

apply plugin: 'com.android.model.application'

model {

def versionCodeBase = 11;

def versionCodePrefixes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5,

'mips64': 6, 'x86': 8, 'x86_64': 9];

//...

android.productFlavors {

create ("armv7") {

ndk.abiFilters.add("armeabi-v7a")

versionCode = versionCodePrefixes.get("armeabi-v7a", 0) * 1000000 + versionCodeBase

}

create ("x86") {

ndk.abiFilters.add("x86")

versionCode = versionCodePrefixes.get("x86", 0) * 1000000 + versionCodeBase

}

}

}

build.gradle

Multiple APKs (gradle-experimental)

Page 34: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

//project’s build.gradle:

buildscript {

dependencies {

classpath 'com.android.tools.build:gradle-experimental:0.6.0'

classpath 'com.android.tools.build:gradle:2.0.0'

}

}

//to keep debugging working, set this in the build.gradle that uses the stable plugin:

android{

buildTypes.debug.jniDebuggable true

}

/!\ use the latest versions for both plugins, don’t mix older ones.

build.gradle

Mixing gradle stable and -experimental plugins

Page 35: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Mixing gradle stable and -experimental plugins…and keep debugging working in AS:

Page 36: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

splits {

abi {

enable true

reset()

include 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'

universalApk true

}

}

// map for the version code

project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3,

'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]

applicationVariants.all { variant ->

// assign different version code for each output

variant.outputs.each { output ->

output.versionCodeOverride =

project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI),

0) * 1000000 + defaultConfig.versionCode

}

}

build.gradle

Multiple APKs (APK Splits – gradle-stable)

Page 37: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Q&A@ph0b – ph0b.com – +XavierHallade

Page 38: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

Resources

http://ph0b.com/new-android-studio-ndk-support/

https://github.com/googlesamples/android-ndk

Watch for this issue to be resolved for fixing editing on Windows versions of AS: http://b.android.com/195483

Page 39: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

Additional slides

Page 40: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

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:

x86ARMv7 ARM64 X86_64

Page 41: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT

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_sharedLOCAL_STATIC_LIBRARIES := module_static

Other predefined macros:

BUILD_SHARED_LIBRARY, BUILD_STATIC_LIBRARY,PREBUILT_SHARED_LIBRARY, PREBUILT_STATIC_LIBRARY

Page 42: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

#droidconIT 43

Application.mk

APP_PLATFORM := android-15 # <= minSDKVersion

APP_CFLAGS := -O3

APP_STL := c++_shared

APP_ABI := all # or all32, all64…

APP_OPTIM := release # default

NDK_TOOCLHAIN_VERSION := 4.8 # default

Page 43: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin
Page 44: Mastering the NDK with Android Studio 2.0 and the gradle-experimental plugin

import org.apache.tools.ant.taskdefs.condition.Os

android.sources {

main {

jni {

source {

srcDirs = ['src/main/none']

}

}

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

Using Android.mk/Application.mk from Gradle