NDK Android:ネイティブ開発キットとC++のためのJNIの概要

著者: IT Sectr 公開日: 2026-02-09 読了時間: 10 分

NDK(ネイティブ開発キット)は、Android向けにアプリケーションの一部をCおよびC++で記述するためのツールキットです。通常のAndroid SDKとは異なり、NDKはコードをネイティブライブラリ(.so)にコンパイルし、仮想マシンレイヤーを介さずにプロセッサーで直接動作します。Google NDK Guides、2026によると、NDKは高性能コンピューティング、ゲーム、オーディオ処理、既存のC/C++プロジェクトの再利用に使用されています。JNI(Javaネイティブインターフェース)はネイティブコードをKotlinやJavaと連携させます。

重要ポイント

  • NDK — C/C++コードをAndroid向けネイティブライブラリにコンパイルするツールキット。
  • JNI — Java/Kotlin仮想マシンとネイティブコード間の相互作用インターフェース。
  • CMake — NDKプロジェクトの主要ビルドシステム、CMakeLists.txtで設定可能。
  • ABI — ターゲットプロセッサーアーキテクチャ(arm64-v8a、armeabi-v7a、x86_64)。
  • NDKはほとんどのAndroidアプリケーションに不要で、高いパフォーマンスが要求されるタスクでのみ使用。

NDKとは

NDK(ネイティブ開発キット)は、CおよびC++コードをAndroid向けの実行可能ライブラリにクロスコンパイルするためのツールセットです。NDKにはClangコンパイラ、libc++標準ライブラリ、Android APIヘッダーファイル、ビルドユーティリティが含まれます。開発者はCまたはC++でネイティブコードを作成し、.soファイル(共有オブジェクト)にコンパイルして、JNIを介してアプリケーションに接続します。

NDKはAndroid SDKを置き換えるものではなく、補完します。すべてのUI、ライフサイクル、システムサービスはKotlinまたはJavaで動作します。ネイティブコードは特定のタスクを解決します:数学的計算、暗号化、コーデック、ゲームの物理演算。GoogleはSDKが必要なパフォーマンスやハードウェア機能へのアクセスを提供しない場合にのみNDKの使用を推奨しています。

NDKの歴史は2009年(NDK r1)に始まります。この間、ツールキットは実験的なスクリプト集から、CMake、LLDBデバッグ、プロファイリングをサポートする成熟したシステムへと進化しました。2026年現在の最新バージョンはNDK r27で、Clang 19、C++20の完全サポート、libc++を唯一の標準ライブラリとしています。

NDKの主要機能

NDKはネイティブAPIを介してAndroidの低レベル機能へのアクセスを開発者に提供します。主なユースケースは次のとおりです:3Dグラフィック向けOpenGL ESとVulkanの操作、Oboeを介したオーディオ処理、BoringSSLによる暗号化操作、ARM向けNEON最適化。これらのAPIはすべてC/C++から利用可能で、コンパイルにNDKが必要です。

さらに、NDKを使用すると、既存のC/C++ライブラリをKotlinで書き直すことなく再利用できます。これは、長い歴史を持つC++プロジェクト(ゲームエンジン(Unity、Unreal Engine)、コンピュータビジョンライブラリ(OpenCV)、暗号化パッケージ(OpenSSL))に特に関連性が高く、NDKによって開発期間を数年短縮できます。

コンポーネント目的
ClangC++20対応C/C++コンパイラ
libc++標準C++ライブラリ(NDK r27で唯一)
CMakeネイティブライブラリのビルドシステム
LLDBAndroid Studioでのネイティブコードデバッガ
ndk-buildレガシービルドシステム(CMakeに置き換え)

NDK vs SDK:ネイティブコードが必要なケース

NDKと純粋なSDKの選択はタスクに依存します。Android SDKは90%のシナリオ(ネットワーキング、ファイル、通知、カメラ)向けにJava/Kotlin APIを提供します。NDKは、これらのAPIが必要なパフォーマンスや機能を提供しない場合に使用されます。たとえば、SDKを介したリアルタイムオーディオ処理は可能ですが50~200msのレイテンシがあり、Oboeを介したネイティブライブラリではレイテンシが5~15msに低減します。

APKサイズも別の要因です。NDKを追加すると、各ABIアーキテクチャに個別の.soライブラリが必要になるため、アプリケーションサイズが増加します。ただし、Android App Bundle(AAB)を使用すると問題が軽減されます:Google Playはユーザーのアーキテクチャに合ったライブラリのみを配信します。典型的なネイティブプロジェクトでは、デバイスあたりのインストールサイズに1〜10MB追加されます。

SDKとNDKの比較(基準別)

基準SDK(Kotlin/Java)NDK(C/C++)
パフォーマンス中程度(JIT/AOTコンパイル)高い(マシンコード)
オーディオレイテンシ50~200msOboe経由で5~15ms
3DグラフィックCanvas/OpenGL Kotlin API経由Vulkan/OpenGL直接
開発の複雑さ低い高い(メモリ管理、JNI)
コードの移植性AndroidのみLinux、Windows、macOS、iOS
APKサイズ最小+1~10MB/ライブラリ

NDKアーキテクチャ:ツールとライブラリ

NDKはSDK Managerを介してAndroid SDKとは別にインストールされます。NDKディレクトリ内には、ツールチェーン(コンパイラ)、プラットフォームライブラリ、ヘッダーファイル、ユーティリティがあります。NDKツールチェーンには、すべてのターゲットABI(arm64-v8a、armeabi-v7a、x86_64、x86)向けのクロスコンパイル用Clangが含まれています。コンパイラはCMakeまたはndk-buildのフラグに基づいて自動的に必要なアーキテクチャを選択します。

ネイティブコード用のAndroid APIは、sysroot/usr/includeディレクトリのヘッダーファイルで提供されます。そこにはネイティブコードで利用可能なすべてのAPIの宣言があります:native_activity.h(Activityライフサイクル)、input.h(入力イベント)、sensor.h(センサー)。これらのヘッダーをインクルードすると、JNIレイヤーなしでハードウェア機能にアクセスできます。

NDKディレクトリ構成

text
ndk/
  toolchains/
    llvm/prebuilt/windows-x86_64/
      bin/        // Clang, ld, llvm-profdata
      sysroot/    // Android APIヘッダーファイル
  platforms/
    android-26/  // API 26用 libc、libm、libdl
    android-34/
  sources/
    cxx-stl/     // libc++ヘッダー
  build/
    cmake/       // CMakeツールチェーンファイル

ネイティブAndroid API

NDKを介して以下のネイティブAPIグループが利用可能です:Native App Glue(CからのActivityライフサイクル管理)、OpenGL ES 3.2およびVulkan 1.3(グラフィック)、Oboe(低レイテンシオーディオ)、Neural Networks API(オンデバイス機械学習)。各APIにはNDKの一部としてヘッダーファイルと静的/動的ライブラリがあります。

ネイティブAPIの操作にJNIは不要です。関数はC/C++コードから直接呼び出されます。ただし、KotlinのUIとの対話には依然としてJNIが必要です。このハイブリッドアーキテクチャはゲームエンジンで一般的です:C++によるグラフィックと物理演算(Vulkan経由)、KotlinによるメニューとUI(Jetpack Compose経由)。

JNI:KotlinがC++を呼び出す仕組み

JNI(Javaネイティブインターフェース)は、Java/Kotlin仮想マシンからネイティブコードを呼び出す標準メカニズムです。開発者はKotlinでexternalキーワードを使用して外部関数を宣言し、System.loadLibraryを介して.soライブラリをロードします。C++側では、関数はJNI命名規則を使用して宣言され、パッケージ名とクラス名がエンコードされます。

Kotlinでのネイティブ関数の宣言

kotlin
class NativeBridge {
    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }

    external fun stringFromJNI(): String
    external fun fibonacci(n: Int): Long
    external fun processBuffer(data: ByteArray): ByteArray
}

// コードでの使用
val bridge = NativeBridge()
println(bridge.stringFromJNI())  // "Hello from C++"

C++でのJNI関数の実装

cpp
#include <jni.h>
#include <string>

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

extern "C" JNIEXPORT jlong JNICALL
Java_com_example_app_NativeBridge_fibonacci(
    JNIEnv* env, jobject /* this */, jint n) {
    if (n <= 1) return n;
    jlong a = 0, b = 1;
    for (int i = 2; i <= n; i++) {
        jlong temp = a + b;
        a = b;
        b = temp;
    }
    return b;
}

NDK向けCMakeLists.txtの設定

CMakeはNDKの主要ビルドシステムであり、従来のndk-buildに代わるものです。CMakeLists.txtファイルはソースファイル、ライブラリ、コンパイルフラグを記述します。Android Studioは、build.gradleでexternalNativeBuildが設定されている場合、プロジェクトビルド時に自動的にCMakeを呼び出します。CMakeは各ターゲットABIのメイクファイルを生成し、ネイティブコードを並行してコンパイルします。

ネイティブライブラリのCMakeLists.txt例

cmake
cmake_minimum_required(VERSION 3.22.1)
project("nativelib")

# ヘッダーファイルのインクルード
include_directories(src/main/cpp/include)

# ネイティブライブラリの作成
add_library(
    native-lib
    SHARED
    src/main/cpp/native-lib.cpp
    src/main/cpp/math_utils.cpp
    src/main/cpp/audio_processor.cpp
)

# Androidシステムライブラリのリンク
target_link_libraries(
    native-lib
    android
    log
    OpenSLES
    # libc++は自動的にリンク
)

# 最適化フラグ
target_compile_options(native-lib PRIVATE -O3 -Wall -Wextra)

NDK向けbuild.gradleの設定

groovy
android {
    defaultConfig {
        ndk {
            // ビルドのターゲットABI
            abiFilters "arm64-v8a", "armeabi-v7a", "x86_64"
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
            version "3.22.1"
        }
    }
    buildTypes {
        release {
            externalNativeBuild {
                cmake {
                    arguments "-DCMAKE_BUILD_TYPE=Release"
                }
            }
        }
    }
}

ABIとマルチプラットフォームビルド

ABI(アプリケーションバイナリインターフェース)は、デバイスのプロセッサとの互換性を決定するマシンコード形式です。各ARMまたはx86アーキテクチャには独自のABIがあります。NDKは指定された各ABIに対してネイティブコードを個別にコンパイルします。2026年現在の最も一般的なABI:arm64-v8a(最新デバイスの99%)、armeabi-v7a(古い32ビットデバイス)、x86_64(エミュレータとChromebook)。

build.gradleでabiFiltersを指定すると、必要なアーキテクチャのみにビルドが制限され、コンパイル時間が短縮されます。Google Playでは、ライブラリがサポートするすべてのABIを含めることを推奨します。これによりすべてのデバイスで動作が保証されます。Google Play Consoleでは、App Bundleを介してABI固有のAPK配信を設定できます。

ネイティブコードでのデバイスABIの判定

cpp
#include <jni.h>
#include <android/api-level.h>

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_app_NativeBridge_getABIInfo(
    JNIEnv* env, jobject /* this */) {

    #if defined(__arm__)
        #if defined(__ARM_ARCH_7A__)
            return env->NewStringUTF("armeabi-v7a");
        #endif
    #elif defined(__aarch64__)
        return env->NewStringUTF("arm64-v8a");
    #elif defined(__x86_64__)
        return env->NewStringUTF("x86_64");
    #elif defined(__i386__)
        return env->NewStringUTF("x86");
    #endif

    return env->NewStringUTF("unknown");
}
ABIアーキテクチャビット数デバイス
arm64-v8aARMv8-A64ビットほぼすべての最新スマートフォン
armeabi-v7aARMv7-A32ビット古いデバイス(2020年以前)
x86_64x86-6464ビットエミュレータ、Chromebook
x86x86 IA-3232ビットレガシーエミュレータ

C++ネイティブコードの例

実用的な例として、浮動小数点数を扱う数学ライブラリを考えてみましょう。C++のネイティブコードは、ARM NEON命令への直接アクセスと実行時の配列境界チェックが不要なため、Kotlinよりも効率的に計算を実行します。この例は、NDKの典型的な使用パターンである、重い計算をネイティブレイヤーにオフロードする方法を示しています。

ネイティブコードでの数学的操作

cpp
#include <jni.h>
#include <cmath>
#include <vector>

extern "C" JNIEXPORT jfloatArray JNICALL
Java_com_example_app_NativeBridge_normalizeArray(
    JNIEnv* env, jobject, jfloatArray input) {

    jsize len = env->GetArrayLength(input);
    jfloat* elements = env->GetFloatArrayElements(input, nullptr);

    // 平均と標準偏差の計算
    float sum = 0.0f, sumSq = 0.0f;
    for (jsize i = 0; i < len; i++) {
        sum += elements[i];
        sumSq += elements[i] * elements[i];
    }
    float mean = sum / len;
    float stddev = std::sqrt(sumSq / len - mean * mean);

    // 正規化:(x - mean) / stddev
    jfloat* result = new jfloat[len];
    for (jsize i = 0; i < len; i++) {
        result[i] = (elements[i] - mean) / stddev;
    }

    env->ReleaseFloatArrayElements(input, elements, JNI_ABORT);
    jfloatArray output = env->NewFloatArray(len);
    env->SetFloatArrayRegion(output, 0, len, result);
    delete[] result;
    return output;
}

ネイティブコードからのロギング

ネイティブコードをデバッグするには、android/log.hライブラリの__android_log_printマクロを使用します。メッセージはJava/KotlinログとともにLogcatに表示されます。ログレベル(ANDROID_LOG_DEBUG、ANDROID_LOG_ERROR)を使用してメッセージをフィルタリングできます。

cpp
#include <android/log.h>
#define LOG_TAG "NativeLib"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)

extern "C" JNIEXPORT void JNICALL
Java_com_example_app_NativeBridge_processData(
    JNIEnv* env, jobject, jint count) {

    LOGD("Processing %d items", count);

    for (int i = 0; i < count; i++) {
        // 重い処理
        LOGD("Item %d processed", i);
    }

    LOGD("Processing complete");
}

よくある質問

Android開発にNDKは必須ですか?

いいえ。ほとんどのアプリケーションではKotlin SDKで十分です。NDKが必要なのは、リアルタイムオーディオ/ビデオ処理、3Dグラフィック、暗号化、既存のC/C++プロジェクトの再利用など、高性能が要求されるタスクです。

NDKはどのコンパイラを使用しますか?

NDKはLLVMツールチェーンのClangを使用します。NDK r23以降、GCCは完全に削除されました。ClangはすべてのAndroid ABI(arm64-v8a、armeabi-v7a、x86_64、x86)向けにクロスコンパイルします。

NDKの文脈でのABIとは?

ABI(アプリケーションバイナリインターフェース)はプロセッサとの互換性を決定するマシンコード形式です。NDKは各ABIごとに個別に.soライブラリをビルドします。arm64-v8aは最新のAndroidデバイスの主要ABIです。

NDKを介してC++コードをデバッグできますか?

はい。Android StudioはLLDB(ネイティブコードデバッガ)をサポートしています。C++ファイルにブレークポイントを設定し、変数やコールスタックを表示できます。NDKとLLDBプラグインが必要です。

NDKはAPKサイズにどのように影響しますか?

各ネイティブライブラリはAPKに100KB~数MB追加します。各ABIには個別の.soライブラリが必要です。Android App Bundleはユーザーに適切なアーキテクチャのみを配信し、インストールサイズを削減します。

まとめ

  • NDK — Clangコンパイラを使用してC/C++コードをAndroid向けネイティブライブラリにクロスコンパイルするためのツールセット。
  • JNI — externalキーワードと関数命名規則を介してKotlin/Javaをネイティブコードと接続するインターフェース。
  • CMake — NDKの主要ビルドシステム。CMakeLists.txtとGradleのexternalNativeBuildで設定。
  • ABIはプロセッサアーキテクチャ(arm64-v8a、armeabi-v7a、x86_64)を定義します。各ABIに個別のライブラリビルドが必要。
  • NDKは高いパフォーマンスが必要なタスク(ゲーム、オーディオ、グラフィック、暗号化、オンデバイス機械学習)にのみ使用してください。
  • Google PlayはApp Bundleを介したABI分割をサポート:ユーザーは自分のデバイスアーキテクチャ用のライブラリのみを受け取ります。
  • ネイティブライブラリはAPKサイズを大幅に増加させますが、重要な操作に対して最大のパフォーマンスと低レイテンシを提供します。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください