Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/android/ndk/llms.txt

Use this file to discover all available pages before exploring further.

Quick start guide

This tutorial guides you through creating your first Android application with native C++ code. You’ll build a simple “Hello from C++” app that demonstrates how Java/Kotlin code interacts with native code through JNI (Java Native Interface).

Prerequisites

Before starting, ensure you have:
  • Android Studio installed with NDK and CMake
  • Basic knowledge of Android app development
  • Basic C++ knowledge (helpful but not required)
If you haven’t installed the NDK yet, see the installation guide.

Create your first native app

1

Create a new project with native support

Open Android Studio and create a new project:
  1. Click File > New > New Project
  2. Select Native C++ template
  3. Click Next
  4. Configure your project:
    • Name: HelloNDK
    • Package name: com.example.hellondk
    • Language: Kotlin (or Java)
    • Minimum SDK: API 21 or higher
  5. Click Next
  6. Choose C++ Standard: C++14 or higher
  7. Click Finish
Android Studio creates a project with native code support pre-configured.
2

Explore the project structure

Your project now contains both Java/Kotlin and C++ code:
app/
├── src/
│   ├── main/
│   │   ├── java/          # Java/Kotlin code
│   │   ├── cpp/           # C++ native code
│   │   │   ├── native-lib.cpp
│   │   │   └── CMakeLists.txt
│   │   └── AndroidManifest.xml
└── build.gradle
Key files:
  • native-lib.cpp: Your C++ source code
  • CMakeLists.txt: CMake build configuration
  • MainActivity.kt/java: Loads and calls native code
3

Examine the native code

Open app/src/main/cpp/native-lib.cpp. You’ll see a JNI function:
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_hellondk_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
This function:
  • Is called from Java/Kotlin code
  • Returns a string created in C++
  • Uses JNI to convert C++ string to Java string
The function name follows JNI naming convention: Java_<package>_<class>_<method>
4

Examine the CMake configuration

Open app/src/main/cpp/CMakeLists.txt:
cmake_minimum_required(VERSION 3.18.1)

project("hellondk")

add_library(
    native-lib
    SHARED
    native-lib.cpp
)

find_library(
    log-lib
    log
)

target_link_libraries(
    native-lib
    ${log-lib}
)
This configuration:
  • Creates a shared library named native-lib
  • Compiles native-lib.cpp
  • Links the Android log library
5

Examine the Kotlin/Java code

Open MainActivity.kt (or MainActivity.java):
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        // Load the native library
        System.loadLibrary("native-lib")
        
        // Call the native method
        val textView: TextView = findViewById(R.id.sample_text)
        textView.text = stringFromJNI()
    }
    
    // Declare the native method
    external fun stringFromJNI(): String
}
The code:
  • Loads the native library with System.loadLibrary()
  • Declares the native method with external (Kotlin) or native (Java)
  • Calls the C++ function like any other method
6

Build and run the app

  1. Connect an Android device or start an emulator
  2. Click Run (green play button) or press Shift+F10
  3. Wait for the build to complete
  4. The app displays “Hello from C++” on the screen
The first build may take longer as CMake compiles the native code for multiple architectures (armeabi-v7a, arm64-v8a, x86, x86_64).

Customize your native code

Now let’s modify the native code to perform a simple calculation.
1

Add a new native function

In native-lib.cpp, add a new function that adds two numbers:
extern "C" JNIEXPORT jint JNICALL
Java_com_example_hellondk_MainActivity_addNumbers(
        JNIEnv* env,
        jobject /* this */,
        jint a,
        jint b) {
    return a + b;
}
This function:
  • Takes two integers as parameters
  • Returns their sum
  • Uses jint (JNI integer type)
2

Declare the method in Kotlin/Java

In MainActivity.kt, add the method declaration:
external fun addNumbers(a: Int, b: Int): Int
3

Call the native function

Update onCreate to call the new function:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    
    val textView: TextView = findViewById(R.id.sample_text)
    val greeting = stringFromJNI()
    val sum = addNumbers(15, 27)
    textView.text = "$greeting\nSum: $sum"
}
4

Build and run again

Run the app again. You should now see:
Hello from C++
Sum: 42

Add logging from native code

Logging is essential for debugging native code. Let’s add Android logging support.
1

Include the log header

In native-lib.cpp, add the Android log header:
#include <jni.h>
#include <string>
#include <android/log.h>

#define TAG "NativeLib"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
2

Add logging to your function

Update the addNumbers function:
extern "C" JNIEXPORT jint JNICALL
Java_com_example_hellondk_MainActivity_addNumbers(
        JNIEnv* env,
        jobject /* this */,
        jint a,
        jint b) {
    LOGI("Adding %d + %d", a, b);
    jint result = a + b;
    LOGI("Result: %d", result);
    return result;
}
3

View logs

Run the app and check Logcat in Android Studio:
  1. Open Logcat tab at the bottom
  2. Filter by “NativeLib”
  3. You’ll see the log messages from C++:
I/NativeLib: Adding 15 + 27
I/NativeLib: Result: 42

Understanding JNI types

When working with JNI, you need to understand type mappings between Java and C++:
Java TypeJNI TypeC++ Type
booleanjbooleanuint8_t
bytejbyteint8_t
charjcharuint16_t
shortjshortint16_t
intjintint32_t
longjlongint64_t
floatjfloatfloat
doublejdoubledouble
Objectjobject-
Stringjstring-
Always use JNI types in your native function signatures. Using regular C++ types will cause runtime errors.

Build system configuration

The build.gradle file contains NDK configuration:
android {
    defaultConfig {
        // Specify which ABIs to build
        ndk {
            abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
        }
    }
    
    // Link CMake build script
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.18.1"
        }
    }
}
Building for fewer ABIs reduces APK size but limits device compatibility. Most production apps target armeabi-v7a and arm64-v8a.

Debugging native code

Android Studio provides full debugging support for native code:
1

Set breakpoints

Open native-lib.cpp and click in the left gutter to set a breakpoint.
2

Debug the app

Click Debug (bug icon) instead of Run. The debugger will pause at your breakpoint.
3

Inspect variables

Use the Variables pane to inspect values, step through code, and evaluate expressions.

Common issues and solutions

UnsatisfiedLinkError

If you see UnsatisfiedLinkError: No implementation found:
  • Verify the native function name matches the JNI naming convention
  • Ensure System.loadLibrary() is called before the native method
  • Check that CMakeLists.txt includes your .cpp file

Build errors

If the native build fails:
  • Check Build tab for CMake error messages
  • Ensure NDK and CMake are installed via SDK Manager
  • Verify CMake version in CMakeLists.txt matches installed version

Missing symbols

If you get linker errors about missing symbols:
  • Add required libraries to target_link_libraries in CMakeLists.txt
  • For Android APIs, use find_library() to locate system libraries

Next steps

Congratulations! You’ve built your first native Android application. Here’s what to explore next:

Build systems

Learn advanced CMake and ndk-build configurations

JNI guide

Deep dive into Java Native Interface programming

Performance

Optimize your native code for maximum performance

Debugging

Master native debugging and crash analysis

Additional resources