Article in Code Manual category.

Understanding Android NDK with Kotlin: Part 1 – Concepts

The Android NDK is a set of tools that allow you to use C and C++ code in your Android app. It provides platform libraries to manage…

An Android developer's daily life is full of challenges, from updates in the ecosystem, migration to Kotlin to using Dagger2, RxJava and so on. On my journey to becoming a better developer, I got a chance play with the Android NDK on one of my projects. I was excited to work on it but at the same time worried because of the lack of documentation.

Through this article, I’ll be sharing my experiences with the NDK and how to use it with Kotlin.

What is Android NDK

The Native Development Kit (NDK) is a set of tools that allow you to use C and C++ code in your Android app. It provides platform libraries to manage native activities and access hardware components such as sensors and touch input.

The NDK may not be appropriate for most novice Android programmers who need to use only Java code and framework APIs to develop their apps. However, the NDK can be useful for the following cases:

  • Squeeze extra performance out of a device to achieve low latency or run computationally intensive applications, such as games or physics simulations.
  • Reuse code between your iOS and Android apps.
  • Use libraries like FFMPEG, OpenCV, etc.

Java Native Interface

JNI is the medium of interaction between the Java runtime and native code. It involves more than one language and runtime so some familiarity with C/C++ is recommended.


Getting Started

  • Create a new project
  • Include C++ and Kotlin support
  • Download the latest Android NDK, CMake and LLDB from the SDK manager.

CMake and LLDB

CMake is cross-platform, free and open-source software for managing the build process of software using a compiler-independent method. The build project contains a CMakeLists.txt file in every directory that controls the build process. List of CMake useful functions here.

LLDB is a next generation, high-performance debugger. LLDB currently converts debug information into clang types so that it can leverage the clang compiler infrastructure. It allows LLDB to support the latest C, C++ language features and runtimes in expressions without having to reimplement any of its functionality.

JNI Primitive Types

JNI has its own primitive and reference data types. To work with native code (call native functions written in C/C++, pass arguments, get results, etc.) primitive types are used.

source :

JNI Function Example

android ndk code
Example : To create some function that multiplies two values and returns the result.

To call a native function from Kotlin we’ll have to add:

  • extern “c”
  • JNIEXPORT macro: A macro is a fragment of code which has been given a name. Whenever the name is used, it is replaced by the contents of the macro.
android ndk developers

In this case, JNIEXPORT will be replaced by __attribute__ ((visibility (“default”))).

  • Function name should start with Java and name of the class that contains the appropriate method in Java or Kotlin code.
android ndk developer code

The native function should have at least two arguments: JNIEnv* pEnvand jobject jObj.

The JNIEnv* is a pointer to the pointer to function tables. It provides most of the JNI functions. All your native functions will receive a JNIEnv as the first argument. jobject jObj is the class instance that contains this function in Kotlin code. In my case, it’s an object of Math class.

JNI functions are available through an interface pointer. An interface pointer is a pointer to a pointer. This pointer points to an array of pointers, each of which points to an interface function. Every interface function is at a predefined offset inside the array.see figure below for the illustration.

jni functions

Adding Header File

To add header files we can either use #include<filename> to include standard library header files or #include "filename" to include programmer-defined header files.

To avoid including headers multiple times by mistake, wrapping the header content in #ifndef — #endif can be used, this avoids error during compilation.

android ndk

JNI — Reference Types

source :

To get an instance of Kotlin class we have to use the above-mentioned reference types.

android dev code
Example function with params

Local, Weak and Global References

We can create local, weak and global references with jObject.
JNIEnv *jEnv provides most of the JNI functions respectively for creating references.

jobject NewGlobalRef(JNIEnv *env, jobject obj);,
jweak NewWeakGlobalRef(JNIEnv *env, jobject obj); and
jobject NewLocalRef(JNIEnv *env, jobject ref);

Similarly, we have functions to delete the reference:

void DeleteLocalRef(JNIEnv *env, jobject localRef);,
void DeleteGlobalRef(JNIEnv *env, jobject globalRef); and
void DeleteWeakGlobalRef(JNIEnv *env, jweak obj);. and is the makefile for building the native project. It allows you to group your sources into modules. A module is either a static library, a shared library, or a standalone executable. You can define one or more modules in each file, and you can use the same source file in multiple modules.

android ndk
Example file

The file is really a tiny GNU Makefile fragment that defines several variables for compilation. This makefile describes several variables that will help make the assembly more flexible.

android ndk
Example file

This covered most of the basics required to start using Native SDK in your project.


In this article, we went through the basics of Android NDK. Hop in for the Part 2 where I’ll demonstrate a sample app using the NDK where we will see how to communicate between Kotlin and C++

More Articles By nitish-bhatt

Recent Articles

Previous post SALT May 9, 2018
Next post Google I/O 2018 Focused On Android AI Development May 11, 2018