3. Native Development for Android
Natural/native language of Android development is Java
Android runs Linux kernel at its core
C/C++ development is possible, actually an Android application can be written
entirely in C or C++
Leverages standard Java Native Interface (JNI)
However it will not benefit most apps
4.
5. Benefits of Native Development for Android
• Mostly useful for computation intensive apps where performance becomes
an issue
• May help to port or share code with other platforms, like iOS
• Use external native libraries
• Sometimes allows access to APIs not exposed in Java layer
6. NDK development Cons:
Requires compilation for every CPU architecture and, possibly, a separate APK
for each architecture.
May significantly increase APK size
JNI development is cumbersome for Java developers
7. Native Development Kit or NDK for Android
NDK is a set of tools or toolchain used for for native development for Android
platform.
http://developer.android.com/ndk/index.html
Samples*
https://github.com/googlesamples/android-ndk
8. ABI is Application Binary Interface
Different Android handsets use different CPUs, which in turn support different
instruction sets. Each combination of CPU and instruction sets has its own
Application Binary Interface, or ABI.
armeabi
armeabi-v7a
arm64-v8a
x86
x86_64
mips
mips64
11. NDK setup
NDK setup is very straight-forward:
[Install Android Studio]
Download and unzip NDK into a convenient location or let Android Studio do it
for you
Optionally get the samples from Github, they are not included in the NDK
https://github.com/googlesamples/android-ndk *
* Look for various branches corresponding to build methods
12. Several ways to build native code
• Using ndk-build or cmake and externalNativeBuild { } block in build.gradle
(starting with Android Studio 2.2)
Use if you are porting older or very complex project or familiar with GNU make or cmake
• Using experimental Gradle plugin – new build system
Recommended for new projects, doesn’t require external build tool knowledge
• Use toolchain directly
Use you favorite build tools
14. Experimental plugin - Project structure
Starting from version 1.3 Android Studio supports NDK development with the
relatively new 'com.android.model.application' gradle plugin
.C, .CPP files under jni folder at the same level as java
*Old toolchain based on makefiles and ndk-build is not covered by this training.
15. Project structure
Build settings defined in android.ndk section of the build.gradle file, for
example
model {
...
android.ndk {
moduleName = "native-codec-jni"
cppFlags.add("-UNDEBUG")
// for native multimedia
ldLibs.addAll(["OpenMAXAL", "mediandk"])
// for logging
ldLibs.add("log")
// for native windows
ldLibs.add("android")
stl = "stlport_static"
}
...
}
16. Everything you can configure in android.ndk
android.ndk {
// All configurations that can be changed in android.ndk.
moduleName = "mymodule"
ldLibs.addAll(['log', 'android'])
ldLibs.add("log")
ldFlags.add("-L/custom/lib/path")
...
}
17. Everything you can configure in android.ndk 2
android.ndk {
// All configurations that can be changed in android.ndk.
...
abiFilters.add("x86") // List of target ABIs
CFlags.add("-DCUSTOM_DEFINE")
cppFlags.add("-DCUSTOM_DEFINE")
debuggable = false
renderscriptNdkMode = false
stl = "stlport_static" // choice of c++ runtimes provided
platformVersion = 15
}
● http://tools.android.com/tech-docs/new-build-system/gradle-experimental#TOC-Ndk-Integration
19. Or Split APKs
In native code causes an APK too large. To build separate APK for each
architecture
android {
...
splits {
abi {
enable true
reset()
include 'x86', 'armeabi-v7a', 'mips' // ABIs to include
universalApk true // build “fat” version
}
}
}
20. Split APKs - version code support
Every APK in Play store must have unique versionCode
// map for the version code
project.ext.versionCodes = ['armeabi-v7a':1, 'x86':2, 'mips':3]
applicationVariants.all { variant ->
// assign different version code for each output
variant.outputs.each { output ->
output.versionCodeOverride =
project.ext.versionCodes.get(output.getFilter(OutputFile.ABI)) * 10000
+ variant.versionCode
}
}
* http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
21. C++ runtimes (stl = "stlport_static")
the build system automatically links the standard C libraries, real-time
extensions, and pthread
By default NDK provides a very minimal standard C++ runtime support library
(libstdc++). This minimal support does not include, for example:
○ Standard C++ Library support (except a few trivial headers).
○ C++ exceptions support
○ RTTI support
Available runtimes: GAbi++, STLport, GNU STL, LLVM libc++
Detailed information about various available runtimes and supplied headers can
be found in the docs: developer.android.com/ndk/guides/cpp-support.html
22. Stable NDK libraries (ldLibs.addAll(['log', 'android']))
The Android NDK provides a set of native headers for prebuilt libraries that allow
access various system features without the need to go through JNI.
Library Description Header files
log Android log support log.h
z ZLib compression library zlib.h, zconf.h
dl Dynamic linker library dlfcn.h
GLESv1_CM, GLESv2,
OpenSLES, EGL, GLESv3, 3.1
Open GL ES, EGL, libraries for various versions many
android For writing pure native apps many
OpenMAXAL Android native multimedia handling is based on
Khronos Group OpenMAX AL
OMXAL/OpenMAXAL.h,
OMXAL/OpenMAXAL_Platform.h,
OpenMAXAL_Android.h
jnigraphics Native interface to the pixel buffers of bitmaps bitmap.h
23. Pure Native Activity
android.app.NativeActivity is a glue between Android and and pure native
Activity
No need to subclass it, only properly define in the manifest
Android framework APIs can be accessed through the JNI
Native code should adhere to certain structure defined by NDK in
native_activity.h
Alternatively use helper library defined in android_native_app_glue.h
Implement native function ANativeActivity_onCreate
Implement ANativeActivity->callbacks to manage activity lifecycle
24. Pure native activity manifest
<application android:label="@string/app_name" android:hasCode="false">
<!-- Our activity is the built-in NativeActivity framework class.
This will take care of integrating with our NDK code. -->
<activity android:name="android.app.NativeActivity"
android:label="@string/app_name"
android:configChanges="orientation|keyboardHidden">
<!-- Tell NativeActivity the name of or .so -->
<meta-data android:name="android.app.lib_name"
android:value="native-activity" />
...
</activity>
</application>
● Sample: https://github.com/googlesamples/android-ndk/tree/master/native-activity
25. Debugging JNI code
In the latest releases of Android Studio native debugger is nicely integrated and
can be used out of the box
26.
27. Debugging JNI crashes
Tombstone files are crash dumps with some extra information
Up to 10 last tombstone files saved by the system and replaced cyclically
$ adb shell ls /data/tombstones
$ adb pull /data/tombstones/tombstone_00
28. Examining tombstone files with ndk-stack
Identify crash address in your library
$ ndk-stack -sym <root symbols dir> [-dump <dump file>]
$ ndk-stack -sym .appbuildintermediatessymbols -dump .tombstone_00
29. Finding file location with addr2line
addr2line command that you need to use depends on the ABI of your crashed file.
alias addr2line=
’$NDK/toolchains/x86_64-4.9/prebuilt/windows/bin/i686-linux-android-
addr2line.exe’
Find the crashed line
$ addr2line -f -e <input file> <address>
Alternative way is to use product flavors. However if you have real product flavors this will be cumbersome. Samples still use product flavors method and abiFilters
It is recommended to write Android application in Java and only delegate selected parts to native code. However it is possible to write an app entirely in C/C++. Consider Web Browser or very complex high-performance game
Working directory: C:\Users\kirill\kirill\Projects\tikal\android-ndk-samples\hello-jni
Crashlytics upload symbols
Working directory: C:\Users\kirill\kirill\Projects\tikal\android-ndk-samples\hello-jni
$ ndk-stack -sym .\app\build\intermediates\symbols -dump .\tombstone_00
Working directory: C:\Users\kirill\kirill\Projects\tikal\android-ndk-samples\hello-jni
alias
addr2line -f -e app/build/intermediates/binaries/debug/x86-64/obj/x86_64/libhello-jni.so 07dd
addr2line=’/cygdrive/c/apps/android-ndk-r11c/toolchains/x86_64-4.9/prebuilt/windows/bin/x86_64-linux-android-addr2line.e