NDK(ネイティブ開発キット)は、Android向けにアプリケーションの一部をCおよびC++で記述するためのツールキットです。通常のAndroid SDKとは異なり、NDKはコードをネイティブライブラリ(.so)にコンパイルし、仮想マシンレイヤーを介さずにプロセッサーで直接動作します。Google NDK Guides、2026によると、NDKは高性能コンピューティング、ゲーム、オーディオ処理、既存のC/C++プロジェクトの再利用に使用されています。JNI(Javaネイティブインターフェース)はネイティブコードをKotlinやJavaと連携させます。
重要ポイント
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はネイティブ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によって開発期間を数年短縮できます。
| コンポーネント | 目的 |
|---|---|
| Clang | C++20対応C/C++コンパイラ |
| libc++ | 標準C++ライブラリ(NDK r27で唯一) |
| CMake | ネイティブライブラリのビルドシステム |
| LLDB | Android Studioでのネイティブコードデバッガ |
| ndk-build | レガシービルドシステム(CMakeに置き換え) |
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(Kotlin/Java) | NDK(C/C++) |
|---|---|---|
| パフォーマンス | 中程度(JIT/AOTコンパイル) | 高い(マシンコード) |
| オーディオレイテンシ | 50~200ms | Oboe経由で5~15ms |
| 3Dグラフィック | Canvas/OpenGL Kotlin API経由 | Vulkan/OpenGL直接 |
| 開発の複雑さ | 低い | 高い(メモリ管理、JNI) |
| コードの移植性 | Androidのみ | Linux、Windows、macOS、iOS |
| APKサイズ | 最小 | +1~10MB/ライブラリ |
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/
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ツールチェーンファイル
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(Javaネイティブインターフェース)は、Java/Kotlin仮想マシンからネイティブコードを呼び出す標準メカニズムです。開発者はKotlinでexternalキーワードを使用して外部関数を宣言し、System.loadLibraryを介して.soライブラリをロードします。C++側では、関数はJNI命名規則を使用して宣言され、パッケージ名とクラス名がエンコードされます。
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++"
#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;
}
CMakeはNDKの主要ビルドシステムであり、従来のndk-buildに代わるものです。CMakeLists.txtファイルはソースファイル、ライブラリ、コンパイルフラグを記述します。Android Studioは、build.gradleでexternalNativeBuildが設定されている場合、プロジェクトビルド時に自動的にCMakeを呼び出します。CMakeは各ターゲットABIのメイクファイルを生成し、ネイティブコードを並行してコンパイルします。
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)
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(アプリケーションバイナリインターフェース)は、デバイスのプロセッサとの互換性を決定するマシンコード形式です。各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配信を設定できます。
#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-v8a | ARMv8-A | 64ビット | ほぼすべての最新スマートフォン |
| armeabi-v7a | ARMv7-A | 32ビット | 古いデバイス(2020年以前) |
| x86_64 | x86-64 | 64ビット | エミュレータ、Chromebook |
| x86 | x86 IA-32 | 32ビット | レガシーエミュレータ |
実用的な例として、浮動小数点数を扱う数学ライブラリを考えてみましょう。C++のネイティブコードは、ARM NEON命令への直接アクセスと実行時の配列境界チェックが不要なため、Kotlinよりも効率的に計算を実行します。この例は、NDKの典型的な使用パターンである、重い計算をネイティブレイヤーにオフロードする方法を示しています。
#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)を使用してメッセージをフィルタリングできます。
#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");
}
よくある質問
いいえ。ほとんどのアプリケーションではKotlin SDKで十分です。NDKが必要なのは、リアルタイムオーディオ/ビデオ処理、3Dグラフィック、暗号化、既存のC/C++プロジェクトの再利用など、高性能が要求されるタスクです。
NDKはLLVMツールチェーンのClangを使用します。NDK r23以降、GCCは完全に削除されました。ClangはすべてのAndroid ABI(arm64-v8a、armeabi-v7a、x86_64、x86)向けにクロスコンパイルします。
ABI(アプリケーションバイナリインターフェース)はプロセッサとの互換性を決定するマシンコード形式です。NDKは各ABIごとに個別に.soライブラリをビルドします。arm64-v8aは最新のAndroidデバイスの主要ABIです。
はい。Android StudioはLLDB(ネイティブコードデバッガ)をサポートしています。C++ファイルにブレークポイントを設定し、変数やコールスタックを表示できます。NDKとLLDBプラグインが必要です。
各ネイティブライブラリはAPKに100KB~数MB追加します。各ABIには個別の.soライブラリが必要です。Android App Bundleはユーザーに適切なアーキテクチャのみを配信し、インストールサイズを削減します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。