C++ in mobile development: Android NDK, Unity and Unreal Engine

Author: IT Sectr Published: 2026-02-10 Reading time: 11 min

C++ is a multi-paradigm programming language with manual memory management, combining procedural, object-oriented and generic programming. In mobile development, C++ is used through Android NDK for porting libraries and through Unity and Unreal Engine game engines for creating cross-platform games. According to TIOBE (2026), C++ is among the top 5 most popular languages among professional developers.

Key Takeaways

  • C++ is a systems programming language used in Android NDK, Unity and Unreal Engine
  • Android NDK allows compiling C++ code into native .so libraries for ARM processors
  • Unreal Engine is entirely built on C++, while Unity uses C++ for low-level plugins
  • JNI (Java Native Interface) is the bridge between Java/Kotlin and C++ on Android
  • CMake and NDK Build are build systems for C++ projects targeting mobile platforms

What is C++?

C++ is a programming language created by Bjarne Stroustrup in 1985 as an extension of the C language with class support. C++ provides direct memory access through pointers, template metaprogramming and multiple inheritance. The C++17 and C++20 standards added coroutines, concepts and ranges.

Unlike Java and Kotlin, C++ does not have a garbage collector — the developer manually manages memory allocation and deallocation through new and delete operators. This gives full control over performance but requires discipline. According to the JetBrains Developer Survey (2025), 42% of C++ developers use the language in the gaming industry.

C++ standards evolve every three years: C++11 (lambdas, auto, unique_ptr), C++14 (generic lambdas), C++17 (if constexpr, filesystem), C++20 (modules, coroutines, concepts). The Clang and GCC compilers support all current standards, and Android NDK uses Clang from the LLVM toolchain.

Differences between C++ and Java/Kotlin

The main difference between C++ and JVM languages is manual memory management and direct compilation to machine code. Java and Kotlin run on a virtual machine with automatic garbage collection. C++ code compiles into a native binary for a specific architecture — ARM, x86 or RISC-V.

CriterionC++Java / Kotlin
Memory managementManual (new/delete, RAII)Automatic (Garbage Collector)
CompilationNative machine codeJVM / ART bytecode
PerformanceMaximum (zero-cost abstractions)High with GC pauses
Usage in mobile developmentNDK, games, librariesUI apps, business logic
BuildCMake, NDK Build, Gradle + NDKGradle, Maven
Cross-platformCompile for each platformJVM / ART everywhere

C++ in mobile development: Android NDK

Android NDK (Native Development Kit) is a Google toolkit for writing parts of Android applications in C and C++. The NDK includes a Clang-based toolchain, Android system header files, and debugging and profiling libraries. Version r27 (2025) supports C++20 and uses LLVM 18.

The NDK compiles C++ code into dynamic .so libraries for ARM64, ARM32, x86 and x86_64 architectures. A Java or Kotlin application loads these libraries via System.loadLibrary() and calls native functions through JNI. According to Google, the NDK has been downloaded over 5 million times.

NDK project structure

A typical Android NDK project contains the app/src/main/cpp/ folder with C++ source files, CMakeLists.txt for building, and a Java class declaring native methods. Gradle connects the NDK through the externalNativeBuild block in build.gradle.

cpp
// native-lib.cpp — simple JNI method for Android
#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_MainActivity_stringFromJNI(
    JNIEnv *env,
    jobject /*thiz*/) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

The code declares a JNI function with the full name Java_com_example_app_MainActivity_stringFromJNI — this is the JNI naming convention. The function takes a pointer to JNIEnv (the execution environment) and jobject (the calling class instance). env->NewStringUTF creates a Java string from a C++ string.

ABI and target architectures

Android supports several ABI (Application Binary Interface): arm64-v8a (64-bit ARM devices, 99% of modern smartphones), armeabi-v7a (32-bit ARM, legacy devices), x86_64 (emulators). The NDK allows building .so for each architecture through ABI filters in build.gradle.

gradle
android {
    defaultConfig {
        ndk {
            abiFilters "arm64-v8a", "armeabi-v7a"
        }
    }
    externalNativeBuild {
        cmake {
            path "src/main/cpp/CMakeLists.txt"
            version "3.22.1"
        }
    }
}

C++ and game engines: Unity and Unreal Engine

C++ is the primary language of game engines. Unreal Engine uses C++ for all game code, while Unity uses C++ in its engine core for rendering and physics. Even if a developer writes in C# in Unity, under the hood C++ manages graphics, sound and physics calculations.

Unreal Engine: C++ as the main language

Unreal Engine is built on C++ from the ground up. Game logic code is written in C++ using UHT (Unreal Header Tool) macros for integration with Blueprints — a visual scripting system. Classes inherit from base types AActor, UObject, UGameInstance with prefix letters U, A, F.

cpp
// Character class in Unreal Engine using C++
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "MyCharacter.generated.h"

UCLASS()
class AMyCharacter : public ACharacter
{
    GENERATED_BODY()

public:
    AMyCharacter();

    virtual void BeginPlay() override;
    virtual void Tick(float DeltaTime) override;

    UPROPERTY(EditAnywhere, Category = "Movement")
    float MoveSpeed = 600.0f;

protected:
    void SetupPlayerInputComponent(UInputComponent *PlayerInputComponent) override;
};

The UCLASS() and UPROPERTY() macros are part of the Unreal Engine reflection system. UHT (Unreal Header Tool) generates C++ code from header files for serialization, blueprints and network replication. MoveSpeed is displayed in the editor via UPROPERTY(EditAnywhere).

Unity: C++ in plugins and Native SDK

Unity uses C# for game logic, but C++ is used in Native Plugins — .so libraries for Android and .bundle for iOS. Through Android NDK, you can integrate C++ SDKs for ad networks, analytics or port a C++ library from desktop games.

csharp
using System.Runtime.InteropServices;
using UnityEngine;

public class NativeBridge : MonoBehaviour
{
    const string LIB_NAME = "native_plugin";

    [DllImport(LIB_NAME, CallingConvention = CallingConvention.Cdecl)]
    private static extern int ProcessFrame(
        int width, int height,
        IntPtr pixelData
    );

    void Update()
    {
        int result = ProcessFrame(Screen.width, Screen.height, IntPtr.Zero);
        Debug.Log("Frame processed: " + result);
    }
}

In this example, C# marshals a call to the C++ ProcessFrame function via P/Invoke. The DllImport attribute specifies the .so library name. The C++ function processes the frame in real time and returns the result. This approach is used for post-effects and computer vision.

JNI: Java and C++ interaction

JNI (Java Native Interface) is the standard mechanism for calling C/C++ code from Java or Kotlin. In Android, JNI is the only way to transfer data between the ART virtual machine and a native library. Each JNI call has overhead, so data should be transferred in batches rather than one field at a time.

JNIEnv is a pointer to the JNI function table. env->FindClass loads a Java class, env->GetMethodID gets a method identifier, env->CallVoidMethod invokes it. For strings, use GetStringUTFChars and ReleaseStringUTFChars. JNI also supports global and weak references to Java objects.

cpp
// Passing byte array from C++ to Java via JNI
extern "C" JNIEXPORT void JNICALL
Java_com_example_app_ImageProcessor_processArray(
    JNIEnv *env, jobject /*thiz*/,
    jbyteArray input, jint length) {

    jbyte *buffer = env->GetByteArrayElements(input, nullptr);
    jsize size = env->GetArrayLength(input);

    for (jsize i = 0; i < size; ++i) {
        buffer[i] = buffer[i] ^ 0xFF; // invert bytes
    }

    env->ReleaseByteArrayElements(input, buffer, JNI_COMMIT);
}

GetByteArrayElements obtains a pointer to a Java byte array. JNI_COMMIT in ReleaseByteArrayElements copies changes back to the Java array without freeing memory. The for loop processing runs on the CPU with maximum C++ performance and no GC pauses.

Memory management in JNI

The main danger of JNI is global reference leaks. Every NewGlobalRef must be freed via DeleteGlobalRef. Local references (returned by FindClass, NewStringUTF) are automatically released when returning from the native function. For intensive calls, use PushLocalFrame / PopLocalFrame.

CMake and build systems for C++ on Android

CMake is the primary build tool for C++ in Android NDK. CMakeLists.txt describes build targets, libraries and dependencies. Gradle invokes CMake through externalNativeBuild, passing paths to the NDK and toolchain. An alternative is NDK Build based on Android.mk and Application.mk.

CMake 3.22+ supports presets (CMakePresets.json) for different configurations: debug, release, profile with different optimization flags. For Android, the android.toolchain.cmake toolchain from the NDK is used, automatically supplied by Gradle during build.

cmake
# CMakeLists.txt for Android NDK project
cmake_minimum_required(VERSION 3.22)
project("native-lib")

add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
    src/main/cpp/image_utils.cpp
)

target_include_directories(
    native-lib PRIVATE
    src/main/cpp/include
)

target_link_libraries(
    native-lib
    android
    log
    ${CMAKE_SOURCE_DIR}/libs/libjpeg.a
)

set_target_properties(
    native-lib PROPERTIES
    CXX_STANDARD 20
    CXX_STANDARD_REQUIRED ON
)

add_library(SHARED) creates a .so library. target_link_libraries links system libraries android (for JNI) and log (for __android_log_print). The static library libjpeg.a is linked for JPEG image handling. CXX_STANDARD 20 enables C++20 support.

vcpkg and dependency management

vcpkg is a C++ package manager from Microsoft that supports Android NDK as a target platform. Through vcpkg, you can install Boost, OpenCV, SQLite, nlohmann-json and other libraries compiled for Android ABI. Vcpkg integrates with CMake via CMAKE_TOOLCHAIN_FILE.

C++ performance on mobile devices

C++ delivers maximum performance on mobile devices thanks to compilation into native ARM code and the absence of a garbage collector. According to Google tests (Android Performance Patterns, 2024), JNI code in C++ runs 3–10 times faster than equivalent Java code for computationally intensive tasks.

Key factors of C++ performance on mobile platforms: cache locality (contiguous memory layout), NEON SIMD instructions for ARM, asynchronous JNI communication through message queues. NEON is ARM's SIMD extension, processing 128 bits of data in a single instruction, indispensable for audio, video and image processing.

cpp
// SIMD array processing via NEON intrinsics
#include <arm_neon.h>

void process_audio_neon(float *data, size_t n) {
    for (size_t i = 0; i < n; i += 4) {
        float32x4_t vec = vld1q_f32(&data[i]);
        float32x4_t result = vmulq_f32(vec, vdupq_n_f32(0.5f));
        vst1q_f32(&data[i], result);
    }
}

vld1q_f32 loads 4 floats from memory into a 128-bit NEON register. vmulq_f32 multiplies all 4 elements by 0.5 in one cycle. vst1q_f32 stores the result back. Without SIMD, the same loop would perform 4 multiplications sequentially — NEON delivers up to 4x speedup for such operations.

OperationC++ (ms)Java/Kotlin (ms)Speedup
1920x1080 image processing12453.75x
Fast Fourier Transform (FFT)8344.25x
AES-256 encryption of 1MB block3186x
ZLIB data compression5224.4x

Common mistakes when using C++ in mobile projects

The first and most dangerous mistake is memory leaks. Every new must have a matching delete, every new[] must have a matching delete[]. On mobile devices with limited RAM, any leak leads to OOM (Out Of Memory) and app crashes. Use RAII through smart pointers: std::unique_ptr, std::shared_ptr, std::weak_ptr.

The second mistake is ignoring ABI compatibility. A library compiled for armeabi-v7a will not load on an ARM64 device. Always specify abiFilters in build.gradle and test on real devices, not just the x86_64 emulator. Use Android App Bundle for automatic ABI filtering.

The third common mistake is frequent JNI calls. Each transition between Java and C++ costs about 50–100 ns. If you process an array of 10000 elements one by one through JNI, the overhead exceeds the useful work. Pass entire arrays at once and process them on the C++ side.

Threading issues are another frequent mistake. C++ can spawn std::thread, but JNI can only be accessed from threads created by Java. To call Java methods from a C++ thread, use AttachCurrentThread / DetachCurrentThread through JNI.

cpp
// Correctly calling Java from a C++ thread
JavaVM *g_vm; // global pointer obtained at JNI_OnLoad

void background_task() {
    JNIEnv *env;
    jint res = g_vm->AttachCurrentThread(&env, nullptr);
    if (res == JNI_OK) {
        jclass clazz = env->FindClass("com/example/App");
        jmethodID mid = env->GetStaticMethodID(clazz, "onProgress", "(I)V");
        env->CallStaticVoidMethod(clazz, mid, 100);
        g_vm->DetachCurrentThread();
    }
}

Frequently Asked Questions

What is Android NDK and why do we need C++ in it?

Android NDK (Native Development Kit) is a toolkit for writing parts of applications in C or C++. It is used for performance-critical tasks, porting C/C++ libraries to Android, and implementing cross-platform code for Unity and Unreal Engine.

Which Unity games are written in C++?

In Unity, game logic code is written in C#, but C++ is used together with Android NDK for plugins, hardware acceleration, porting custom C++ libraries, and integrating native SDKs for advertising and analytics.

How to configure CMakeLists.txt for C++ on Android?

CMakeLists.txt describes source files, libraries and compilation flags. The minimal configuration includes add_library for building .so and target_link_libraries for linking Android log and other system libraries.

Is JNI in C++ mandatory for Android?

JNI (Java Native Interface) is the layer between Java/Kotlin code of an Android app and the C++ library. If C++ is called from Java, JNI is mandatory. You can write C++ code entirely through NDK, but the entry point is usually a Java Activity that calls native functions.

When is C++ justified instead of Kotlin in mobile development?

C++ is justified for games, real-time audio/video processing, computer vision, cryptography, physics simulations and porting libraries from other platforms. For a regular UI application, Kotlin is more efficient and simpler.

Summary

  • C++ is a multi-paradigm language with manual memory management, used in Android NDK, Unity and Unreal Engine for high-performance code
  • Android NDK compiles C++ into .so libraries for ARM architectures using the Clang toolchain from LLVM
  • Unreal Engine is entirely built on C++ with the UHT reflection system, Unity uses C++ in its rendering and physics core
  • JNI is the mandatory bridge between Java/Kotlin and C++ on Android with the Java___ naming convention
  • CMake is the primary build system for C++ in NDK, supporting C++20 and Gradle integration
  • NEON SIMD provides up to 4x speedup for data processing on ARM processors through 128-bit vector instructions
  • Common mistakes: memory leaks, incorrect ABI in abiFilters, frequent JNI calls and threading without AttachCurrentThread

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also