A Guide to Building Android Libraries with NDK from Scratch

Introduction

Building Android libraries with the NDK (Native Development Kit) can greatly enhance the performance and capabilities of your Android apps, especially when dealing with computationally intensive tasks or utilizing native code. Here’s a step-by-step guide to get you started:

Prerequisites

Before diving into building Android libraries with NDK, ensure you have the following:

  • Android Studio installed
  • Android NDK installed and configured in your project

Step 1: Set Up Your Android Project

  1. Open Android Studio and create a new Android project or open an existing one.

Empty Activity JNI_App

  1. Make sure you have the necessary SDKs and build tools installed for your project.

Step 2: Create Your JNI Folder Structure

Inside your Android project, create a new folder to hold your JNI code. Conventionally, this folder is named jni or src/main/jni.

Alternatively, you have the option to manually navigate to your project directory and create the jni directory yourself.

In my situation, my Android Studio projects are located at /home/kali/AndroidStudioProjects/, and specifically, this JNI_App project is at /home/kali/AndroidStudioProjects/JNI_App/.

$ cd /home/kali/AndroidStudioProjects/JNI_App/
$ cd app/src/main/
$ mkdir jni
$ ls
AndroidManifest.xml  java  jni  res

Within the jni folder, create a C source file (e.g., native-lib.c). This file will contain the native C code you want to call from your Java/Kotlin code.

To do this follow the following steps:

  • Next, in the jni directory, right-click and choose New -> CMakeLists.txt. Also, select New -> C/C++ Source File -> {Name -> native-lib & Type -> C}.

Add_CMakeLists.txt

Add_Cpp

Step 3: Write a native method in Java

In your Java class (usually referred to as a “bridge” class), define the native method. This will act as a bridge between your Java code and the native C/C++ code.

Right Click on com.example.jni_app -> New -> Java Class -> HelloJNI Class

Java_Class_Add

It will look like :

package com.example.jni_app;

public class HelloJNI {
}

Add the following content to it:

package com.example.jni_app;

public class HelloJNI {

    static {
        System.loadLibrary("native-lib");
    }
    public native String printStr();

}

We will use the library libnative-lib.so. This is naming convention that lib and .so should be dropped from library name and include it in System.loadLibrary()

Step 3: Generate the header file

Run the following command in your project’s directory to generate the header file for your native methods.

We have HelloJNI.java located at /app/src/main/java/com/example/jni_app

$ javac -h . HelloJNI.java
$ ls
com_example_jni_app_HelloJNI.h  HelloJNI.java
HelloJNI.class                  MainActivity.java

This command will generate a com_example_jni_app_HelloJNI.h file.

Step 4: Write the native implementation

Open native-lib.c inside the jni directory and implement the native method.

#include <jni.h>
#include "com_example_jni_app_HelloJNI.h"

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_jni_app_HelloJNI_printStr(JNIEnv* env, jobject jobj) {
    return (*env)->NewStringUTF(env, "Hello from native code!");
}

Step 5: Create the Android.mk file

Create an Android.mk file inside the jni directory to define the build rules for the native code.

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := native-lib
LOCAL_SRC_FILES := native-lib.c

include $(BUILD_SHARED_LIBRARY)

Step 6: Build the native library

Open a terminal and navigate to your project’s root directory. Run the following command to build the native library.

$ ndk-build

Step 8: Use the native method in Java

Step 9: Run your App