Android ビルドガイド
概要
macOS 上でネイティブエンジンを Android 向けにクロスビルドし、エミュレーターまたは実機で動作確認する手順。SDL2 をソースからビルドし、NDK 経由でコンパイルする。macOS 側のコードは #ifdef __ANDROID__ ガードで分岐しており、既存のビルドには影響しない。
前提条件
| ツール | バージョン | インストール |
|---|---|---|
| macOS ビルド | 動作済み | 17-build-guide-macos.md |
| Java JDK | 17 | brew install openjdk@17 |
| Android SDK | API 35 | sdkmanager |
| Android NDK | 25+ | sdkmanager |
| Android Build Tools | 35.0.0+ | sdkmanager |
Step 1: Java のセットアップ
brew install openjdk@17
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
.zshrcに追加しておくと毎回設定する必要がない。
Step 2: Android SDK / NDK のセットアップ
# Android コマンドラインツール
brew install --cask android-commandlinetools
export ANDROID_HOME=$HOME/Library/Android/sdk
# 必要なコンポーネントをインストール
JAVA_HOME=/opt/homebrew/opt/openjdk@17 \
sdkmanager --sdk_root=$ANDROID_HOME \
"platform-tools" \
"platforms;android-35" \
"build-tools;35.0.0" \
"ndk;28.0.13004108" \
"cmake;3.22.1"
インストール確認
ls $ANDROID_HOME/ndk/ # NDK バージョンが表示される
ls $ANDROID_HOME/platforms/ # android-35 が存在する
Step 3: SDL2 ソースのダウンロード
Android ビルドでは SDL2 をソースからビルドする(Homebrew の .dylib は macOS 専用)。
# リポジトリルートから実行
bash scripts/download-sdl2-sources.sh
以下がダウンロードされる:
| ライブラリ | バージョン |
|---|---|
| SDL2 | 2.30.12 |
| SDL2_image | 2.8.4 |
| SDL2_ttf | 2.22.0 |
| SDL2_mixer | 2.8.1 |
| + vendored deps | ogg, vorbis, freetype, harfbuzz 等 |
配置先: packages/native-engine/external/
Step 4: APK ビルド
cd packages/native-engine/android
export JAVA_HOME="/opt/homebrew/opt/openjdk@17"
export ANDROID_HOME="$HOME/Library/Android/sdk"
# ビルド(初回は Gradle ダウンロード + 依存解決で数分かかる)
./gradlew assembleDebug
出力: app/build/outputs/apk/debug/app-debug.apk
Step 5: エミュレーターのセットアップ
システムイメージのインストール
JAVA_HOME=/opt/homebrew/opt/openjdk@17 \
sdkmanager --sdk_root=$ANDROID_HOME \
"system-images;android-35-ext15;google_apis;arm64-v8a" \
"emulator"
AVD(仮想デバイス)の作成
avdmanager create avd -n kaedevn_test -k "system-images;android-35-ext15;google_apis;arm64-v8a" -d pixel_6
avdmanagerがうまく動かない場合は Android Studio の Device Manager から作成するか、~/.android/avd/に手動で config.ini を配置する(詳細は後述のハマりポイント参照)。
エミュレーターの起動
$ANDROID_HOME/emulator/emulator -avd kaedevn_test -gpu host &
# ブート完了を待つ
adb wait-for-device
adb shell getprop sys.boot_completed # "1" が返れば OK
Step 6: インストールと実行
# APK インストール
adb install -r app/build/outputs/apk/debug/app-debug.apk
# 起動
adb shell am start -n com.kaedevn.native_engine/.KaedevnActivity
# ログ確認
adb logcat -s "kaedevn:*" "SDL:*"
正常に動作すると、背景・立ち絵・日本語テキストがエミュレーター上に表示される。
ハマりポイント
1. 'SDL2/SDL_image.h' file not found(最もよくハマる)
症状: JNI CMake ビルド中にヘッダが見つからない。
原因: macOS では #include <SDL2/SDL_image.h> と書くが、SDL2 ソースビルドではヘッダが SDL2/ サブディレクトリに配置されない。Homebrew とソースビルドでヘッダの配置が異なる。
解決: JNI の CMakeLists.txt に「互換 include ディレクトリ」を作成する仕組みが入っている。SDL2 コアと satellite ライブラリのヘッダを sdl2-compat-include/SDL2/ にコピーし、そこを include パスに追加する。
set(SDL2_COMPAT_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/sdl2-compat-include/SDL2")
file(MAKE_DIRECTORY "${SDL2_COMPAT_INCLUDE_DIR}")
file(COPY ${SDL2_CORE_HEADERS} ${SDL2_IMAGE_HEADERS} ... DESTINATION "${SDL2_COMPAT_INCLUDE_DIR}")
target_include_directories(main PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/sdl2-compat-include")
これがないと macOS とのコード共有が壊れる。
2. No cmake project for ogg found in external/ogg
症状: Gradle ビルド中に SDL2_mixer の vendored 依存が見つからない。
原因: scripts/download-sdl2-sources.sh を実行していないか、途中で失敗した。satellite ライブラリ(SDL2_mixer 等)は内部に vendored 依存(ogg, vorbis, freetype 等)を持っており、それらの追加ダウンロードが必要。
解決:
# リポジトリルートから再実行
bash scripts/download-sdl2-sources.sh
スクリプトが satellite ライブラリの external/download.sh も自動実行する。
3. fabsf / fmodf 未定義エラー
症状: NDK ビルド中に undefined reference to 'fabsf'。
原因: macOS では <math.h> が暗黙的にリンクされるが、Android NDK では明示的に #include <math.h> が必要。
解決: 数学関数を使うソースファイルに #include <math.h> を追加。
4. エミュレーターが QEMU クラッシュする
症状: エミュレーター起動直後にクラッシュ、または画面が真っ黒。
原因: Apple Silicon macOS で -gpu swiftshader_indirect(ソフトウェアレンダリング)を使うと不安定。
解決:
# 必ず -gpu host を指定
$ANDROID_HOME/emulator/emulator -avd kaedevn_test -gpu host &
5. avdmanager で AVD が作成できない
症状: avdmanager create avd がエラーを返す、または作成した AVD が一覧に表示されない。
原因: sdkmanager の状態不整合。SDK パスやイメージの指定が環境によって微妙に異なる。
解決: 手動で ~/.android/avd/ に config を作成する:
mkdir -p ~/.android/avd/kaedevn_test.avd
cat > ~/.android/avd/kaedevn_test.ini << EOF
avd.ini.encoding=UTF-8
path=$HOME/.android/avd/kaedevn_test.avd
path.rel=avd/kaedevn_test.avd
target=android-35
EOF
cat > ~/.android/avd/kaedevn_test.avd/config.ini << EOF
AvdId = kaedevn_test
abi.type = arm64-v8a
hw.cpu.arch = arm64
hw.cpu.ncore = 4
hw.ramSize = 2048
hw.lcd.width = 1080
hw.lcd.height = 2400
hw.lcd.density = 411
hw.gpu.enabled = yes
hw.gpu.mode = auto
hw.keyboard = yes
image.sysdir.1 = system-images/android-35-ext15/google_apis/arm64-v8a/
tag.id = google_apis
EOF
6. Gradle で Java が見つからない
症状: ./gradlew assembleDebug で JAVA_HOME is not set や Could not determine java version。
原因: macOS のデフォルト /usr/bin/java は JDK ではない。Gradle 8.x は JDK 17 を要求する。
解決:
export JAVA_HOME="/opt/homebrew/opt/openjdk@17"
7. resource mipmap/ic_launcher not found
症状: Gradle ビルドでリソースエラー。
原因: app/src/main/res/mipmap-*/ic_launcher.png が不足。
解決: 適当な PNG アイコンを配置するか、SDL2 テンプレートからコピー:
# 48x48 の PNG を各ディレクトリに配置
mkdir -p app/src/main/res/mipmap-hdpi
cp /path/to/icon.png app/src/main/res/mipmap-hdpi/ic_launcher.png
8. std::filesystem が使えない
症状: NDK ビルドで std::filesystem::create_directories が未定義。
原因: Android NDK の古いバージョンでは <filesystem> のサポートが不完全。
解決: FileStorage.cpp では #ifdef __ANDROID__ で mkdir (POSIX) を使用し、std::filesystem を回避している。新しいコードを追加する場合も同様に分岐すること。
アーキテクチャ補足
.ksc スクリプト
|
v
Interpreter (step 駆動)
|
v
IEngineAPI (純粋仮想クラス)
|
+-- SDL2Engine (macOS / Android / Switch) <- 同一コード
+-- WebEngine (PixiJS / ブラウザ)
SDL2Engine のコードは macOS / Android で完全に共通。プラットフォーム差異は main.cpp と各マネージャの #ifdef __ANDROID__ のみ。
Android 固有の対応箇所
| ファイル | 対応内容 |
|---|---|
main.cpp | SDL_WINDOW_FULLSCREEN_DESKTOP、タッチイベント、戻るボタン、logcat 出力 |
FontManager.cpp | SDL_RWFromFile で APK assets から読み込み |
AssetProvider.cpp | SDL_RWFromFile + SDL_RWread で JSON 読み込み |
FileStorage.cpp | SDL_AndroidGetInternalStoragePath() + mkdir |
Shader.cpp | 全メソッドをスタブ化(SDL_Renderer ベースで OpenGL 不使用) |
クイックリファレンス
# === 環境変数(.zshrc に追加推奨) ===
export JAVA_HOME=/opt/homebrew/opt/openjdk@17
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$PATH
# === SDL2 ソース取得 ===
bash scripts/download-sdl2-sources.sh
# === APK ビルド ===
cd packages/native-engine/android && ./gradlew assembleDebug
# === エミュレーター ===
emulator -avd kaedevn_test -gpu host &
adb wait-for-device
# === インストール & 実行 ===
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.kaedevn.native_engine/.KaedevnActivity
adb logcat -s "kaedevn:*" "SDL:*"
# === クリーンビルド ===
cd packages/native-engine/android && ./gradlew clean && ./gradlew assembleDebug