モバイル開発におけるC++: Android NDK、Unity、Unreal Engine

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

C++は、手動メモリ管理を備えたマルチパラダイムプログラミング言語であり、手続き型、オブジェクト指向、ジェネリックプログラミングを組み合わせています。モバイル開発では、C++はAndroid NDKを介したライブラリのポーティングや、UnityやUnreal Engineゲームエンジンを介したクロスプラットフォームゲームの作成に使用されます。TIOBE (2026)によると、C++はプロフェッショナル開発者の間でトップ5の最も人気のある言語の一つです。

重要ポイント

  • C++は、Android NDK、Unity、Unreal Engineで使用されるシステムプログラミング言語
  • Android NDKは、C++コードをARMプロセッサ向けのネイティブ.soライブラリにコンパイル可能
  • Unreal Engineは完全にC++上に構築され、Unityは低レベルプラグインにC++を使用
  • JNI (Java Native Interface)は、Android上でJava/KotlinとC++の橋渡し
  • CMakeとNDK Buildは、モバイルプラットフォーム向けC++プロジェクトのビルドシステム

C++とは?

C++は、1985年にビャーネ・ストロヴストルップによってC言語の拡張としてクラスサポートを備えて作成されたプログラミング言語です。C++は、ポインタによる直接メモリアクセス、テンプレートメタプログラミング、多重継承を提供します。C++17およびC++20標準では、コルーチン、コンセプト、レンジが追加されました。

JavaやKotlinとは異なり、C++にはガベージコレクタがありません — 開発者はnew演算子とdelete演算子を使って手動でメモリの割り当てと解放を管理します。これによりパフォーマンスを完全に制御できますが、規律が必要です。JetBrains Developer Survey (2025)によると、C++開発者の42%がゲーム業界でこの言語を使用しています。

C++標準は3年ごとに進化しています: C++11 (ラムダ、auto、unique_ptr)、C++14 (ジェネリックラムダ)、C++17 (if constexpr、filesystem)、C++20 (モジュール、コルーチン、コンセプト)。ClangおよびGCCコンパイラはすべての最新標準をサポートしており、Android NDKはLLVMツールチェーンからClangを使用しています。

C++とJava/Kotlinの違い

C++とJVM言語の主な違いは、手動メモリ管理とマシンコードへの直接コンパイルです。JavaとKotlinは自動ガベージコレクションを備えた仮想マシン上で動作します。C++コードは、ARM、x86、RISC-Vなどの特定のアーキテクチャ向けのネイティブバイナリにコンパイルされます。

基準C++Java / Kotlin
メモリ管理手動 (new/delete、RAII)自動 (ガベージコレクタ)
コンパイルネイティブマシンコードJVM / ART バイトコード
パフォーマンス最大 (ゼロコスト抽象化)高い(GC停止あり)
モバイル開発での使用NDK、ゲーム、ライブラリUIアプリ、ビジネスロジック
ビルドCMake、NDK Build、Gradle + NDKGradle、Maven
クロスプラットフォーム各プラットフォーム向けにコンパイルどこでもJVM / ART

モバイル開発におけるC++: Android NDK

Android NDK (Native Development Kit)は、Androidアプリケーションの一部をCやC++で記述するためのGoogleのツールキットです。NDKには、Clangベースのツールチェーン、Androidシステムヘッダファイル、デバッグおよびプロファイリングライブラリが含まれています。バージョンr27 (2025)はC++20をサポートし、LLVM 18を使用しています。

NDKは、C++コードをARM64、ARM32、x86、x86_64アーキテクチャ向けの動的.soライブラリにコンパイルします。JavaまたはKotlinアプリケーションは、System.loadLibrary()を介してこれらのライブラリをロードし、JNIを介してネイティブ関数を呼び出します。Googleによると、NDKは500万回以上ダウンロードされています。

NDKを使用したプロジェクト構造

典型的なAndroid NDKプロジェクトには、C++ソースファイルを含むapp/src/main/cpp/フォルダ、ビルド用のCMakeLists.txt、ネイティブメソッドを宣言するJavaクラスが含まれます。Gradleは、build.gradleのexternalNativeBuildブロックを介してNDKを接続します。

cpp
// native-lib.cpp — Android用のシンプルなJNIメソッド
#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());
}

このコードは、Java_com_example_app_MainActivity_stringFromJNIという完全な名前でJNI関数を宣言しています — これがJNIの命名規則です。関数は、JNIEnv(実行環境)とjobject(呼び出し元クラスインスタンス)へのポインタを受け取ります。env->NewStringUTFは、C++文字列からJava文字列を作成します。

ABIとターゲットアーキテクチャ

Androidは複数のABI(アプリケーションバイナリインターフェース)をサポートしています: arm64-v8a(64ビットARMデバイス、最新スマートフォンの99%)、armeabi-v7a(32ビットARM、レガシーデバイス)、x86_64(エミュレータ)。NDKは、build.gradleのABIフィルタを介して各アーキテクチャ向けに.soをビルドできます。

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

C++とゲームエンジン: UnityとUnreal Engine

C++はゲームエンジンの主要言語です。Unreal EngineはすべてのゲームコードにC++を使用し、Unityはレンダリングと物理演算にエンジンコアでC++を使用しています。開発者がUnityでC#で記述していても、内部ではC++がグラフィックス、サウンド、物理計算を管理しています。

Unreal Engine: 主要言語としてのC++

Unreal EngineはゼロからC++上に構築されています。ゲームロジックコードは、ブループリント(ビジュアルスクリプティングシステム)との統合のためにUHT(Unreal Header Tool)マクロを使用してC++で記述されます。クラスは、プレフィックス文字U、A、Fを付けて基本型AActor、UObject、UGameInstanceから継承します。

cpp
// Unreal Engineで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;
};

UCLASS()およびUPROPERTY()マクロは、Unreal Engineのリフレクションシステムの一部です。UHT(Unreal Header Tool)は、シリアル化、ブループリント、ネットワークレプリケーションのためにヘッダファイルからC++コードを生成します。MoveSpeedは、UPROPERTY(EditAnywhere)を介してエディタに表示されます。

Unity: プラグインとネイティブSDKでのC++

UnityはゲームロジックにC#を使用しますが、C++はネイティブプラグイン(Android用の.soライブラリ、iOS用の.bundle)で使用されます。Android NDKを介して、広告ネットワークや分析のC++ SDKを統合したり、デスクトップゲームからC++ライブラリをポーティングしたりできます。

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);
    }
}

この例では、C#がP/Invokeを介してC++関数ProcessFrameへの呼び出しをマーシャリングしています。DllImport属性は.soライブラリの名前を指定します。C++関数はリアルタイムでフレームを処理し、結果を返します。このアプローチは、ポストエフェクトやコンピュータビジョンに使用されます。

JNI: JavaとC++の連携

JNI (Java Native Interface)は、JavaまたはKotlinからC/C++コードを呼び出すための標準メカニズムです。Androidでは、JNIがART仮想マシンとネイティブライブラリの間でデータを転送する唯一の方法です。各JNI呼び出しにはオーバーヘッドがあるため、データは一度に1フィールドずつではなく、バッチで転送する必要があります。

JNIEnvはJNI関数テーブルへのポインタです。env->FindClassはJavaクラスをロードし、env->GetMethodIDはメソッド識別子を取得し、env->CallVoidMethodはそれを呼び出します。文字列にはGetStringUTFCharsとReleaseStringUTFCharsを使用します。JNIは、Javaオブジェクトへのグローバル参照とウィーク参照もサポートしています。

cpp
// JNIを介してC++からJavaにバイト配列を渡す
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; // バイトを反転
    }

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

GetByteArrayElementsはJavaバイト配列へのポインタを取得します。ReleaseByteArrayElementsのJNI_COMMITは、メモリを解放せずに変更をJava配列にコピーして戻します。forループ処理は、GC停止なしで最大のC++パフォーマンスでCPU上で実行されます。

JNIにおけるメモリ管理

JNIの主な危険性は、グローバル参照のリークです。すべてのNewGlobalRefはDeleteGlobalRefを介して解放する必要があります。ローカル参照(FindClass、NewStringUTFが返すもの)は、ネイティブ関数から戻るときに自動的に解放されます。集中的な呼び出しには、PushLocalFrame / PopLocalFrameを使用してください。

Android向けC++のCMakeとビルドシステム

CMakeは、Android NDKにおけるC++の主要ビルドツールです。CMakeLists.txtは、ビルドターゲット、ライブラリ、依存関係を記述します。Gradleは、externalNativeBuildを介してCMakeを呼び出し、NDKとツールチェーンへのパスを渡します。代替として、Android.mkとApplication.mkに基づくNDK Buildがあります。

CMake 3.22+は、異なる最適化フラグを持つデバッグ、リリース、プロファイルなど、さまざまな構成のプリセット(CMakePresets.json)をサポートしています。Androidでは、NDKのandroid.toolchain.cmakeツールチェーンが使用され、ビルド中にGradleによって自動的に提供されます。

cmake
# Android NDKプロジェクト用のCMakeLists.txt
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)は.soライブラリを作成します。target_link_librariesは、システムライブラリのandroid(JNI用)とlog(__android_log_print用)をリンクします。静的ライブラリlibjpeg.aはJPEG画像処理用にリンクされます。CXX_STANDARD 20はC++20サポートを有効にします。

vcpkgと依存関係管理

vcpkgは、Android NDKをターゲットプラットフォームとしてサポートするMicrosoftのC++パッケージマネージャです。vcpkgを介して、Android ABI用にコンパイルされたBoost、OpenCV、SQLite、nlohmann-jsonなどのライブラリをインストールできます。Vcpkgは、CMAKE_TOOLCHAIN_FILEを介してCMakeと統合します。

モバイルデバイスにおけるC++のパフォーマンス

C++は、ネイティブARMコードへのコンパイルとガベージコレクタの不在により、モバイルデバイスで最大のパフォーマンスを提供します。Googleのテスト(Android Performance Patterns、2024)によると、計算集約型タスクにおいて、C++のJNIコードは同等のJavaコードより3〜10倍高速に実行されます。

モバイルプラットフォームにおけるC++パフォーマンスの主要因: キャッシュローカリティ(連続メモリレイアウト)、ARM向けNEON SIMD命令、メッセージキューを介した非同期JNI通信。NEONはARMのSIMD拡張であり、1命令で128ビットのデータを処理し、オーディオ、ビデオ、画像処理に不可欠です。

cpp
// NEON組み込み関数によるSIMD配列処理
#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はメモリから128ビットNEONレジスタに4つのfloatをロードします。vmulq_f32は1サイクルですべての4要素を0.5で乗算します。vst1q_f32は結果をストアします。SIMDがない場合、同じループは4回の乗算を逐次的に実行します — NEONはそのような操作で最大4倍の高速化を実現します。

操作C++ (ms)Java/Kotlin (ms)高速化
1920x1080画像処理12453.75x
高速フーリエ変換 (FFT)8344.25x
1MBブロックのAES-256暗号化3186x
ZLIBデータ圧縮5224.4x

モバイルプロジェクトでC++を使用する際のよくある間違い

最初で最も危険な間違いはメモリリークです。すべてのnewにはdeleteが、すべてのnew[]にはdelete[]が必要です。RAMが限られているモバイルデバイスでは、リークが発生するとOOM(メモリ不足)とアプリクラッシュにつながります。スマートポインタ(std::unique_ptr、std::shared_ptr、std::weak_ptr)を介してRAIIを使用してください。

2つ目の間違いはABI互換性の無視です。armeabi-v7a用にコンパイルされたライブラリは、ARM64デバイスではロードされません。build.gradleで常にabiFiltersを指定し、x86_64エミュレータだけでなく実際のデバイスでテストしてください。自動ABIフィルタリングにはAndroid App Bundleを使用してください。

3つ目のよくある間違いは頻繁なJNI呼び出しです。JavaとC++間の各遷移には約50〜100 nsかかります。JNIを介して10000要素の配列を1つずつ処理すると、オーバーヘッドが有用な作業を上回ります。配列全体を一度に渡してC++側で処理してください。

スレッドの問題も頻繁な間違いです。C++はstd::threadを起動できますが、JNIにアクセスできるのはJavaによって作成されたスレッドからのみです。C++スレッドからJavaメソッドを呼び出すには、JNIを介してAttachCurrentThread / DetachCurrentThreadを使用してください。

cpp
// C++スレッドからJavaを正しく呼び出す
JavaVM *g_vm; // 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();
    }
}

よくある質問

Android NDKとは何ですか?また、なぜC++が必要なのですか?

Android NDK (Native Development Kit)は、アプリケーションの一部をCまたはC++で記述するためのツールキットです。パフォーマンスが重要なタスク、C/C++ライブラリのAndroidへのポーティング、UnityやUnreal Engine用のクロスプラットフォームコードの実装に使用されます。

UnityのどのゲームがC++で書かれていますか?

Unityでは、ゲームロジックコードはC#で記述されますが、C++はAndroid NDKと組み合わせてプラグイン、ハードウェアアクセラレーション、カスタムC++ライブラリのポーティング、広告や分析用のネイティブSDKの統合に使用されます。

Android向けC++のCMakeLists.txtを設定するには?

CMakeLists.txtは、ソースファイル、ライブラリ、コンパイルフラグを記述します。最小構成には、.soをビルドするためのadd_libraryと、Android logやその他のシステムライブラリをリンクするためのtarget_link_librariesが含まれます。

AndroidでC++にJNIは必須ですか?

JNI (Java Native Interface)は、AndroidアプリのJava/KotlinコードとC++ライブラリの間の層です。C++がJavaから呼び出される場合、JNIは必須です。NDKを介して完全にC++コードを記述することもできますが、エントリポイントは通常、ネイティブ関数を呼び出すJava Activityです。

モバイル開発でKotlinの代わりにC++が正当化されるのはいつですか?

C++は、ゲーム、リアルタイムオーディオ/ビデオ処理、コンピュータビジョン、暗号化、物理シミュレーション、他のプラットフォームからのライブラリのポーティングに適しています。通常のUIアプリケーションには、Kotlinの方が効率的でシンプルです。

まとめ

  • C++は手動メモリ管理を備えたマルチパラダイム言語で、高性能コードのためにAndroid NDK、Unity、Unreal Engineで使用される
  • Android NDKは、LLVMのClangツールチェーンを使用してARMアーキテクチャ向けにC++を.soライブラリにコンパイルする
  • Unreal EngineはUHTリフレクションシステムを備えて完全にC++上に構築され、Unityはレンダリングおよび物理コアにC++を使用する
  • JNIは、Java___の命名規則でAndroid上のJava/KotlinとC++の間の必須の橋渡し
  • CMakeはNDKにおけるC++の主要ビルドシステムで、C++20とGradle統合をサポート
  • NEON SIMDは128ビットベクトル命令によりARMプロセッサでのデータ処理を最大4倍高速化
  • よくある間違い: メモリリーク、abiFiltersの誤ったABI、頻繁なJNI呼び出し、AttachCurrentThreadなしのスレッド使用

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

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

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

こちらもお読みください