← ソースコード説明書

Android ビルドガイド

概要

macOS 上でネイティブエンジンを Android 向けにクロスビルドし、エミュレーターまたは実機で動作確認する手順。SDL2 をソースからビルドし、NDK 経由でコンパイルする。macOS 側のコードは #ifdef __ANDROID__ ガードで分岐しており、既存のビルドには影響しない。

前提条件

ツールバージョンインストール
macOS ビルド動作済み17-build-guide-macos.md
Java JDK17brew install openjdk@17
Android SDKAPI 35sdkmanager
Android NDK25+sdkmanager
Android Build Tools35.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

以下がダウンロードされる:

ライブラリバージョン
SDL22.30.12
SDL2_image2.8.4
SDL2_ttf2.22.0
SDL2_mixer2.8.1
+ vendored depsogg, 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 assembleDebugJAVA_HOME is not setCould 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.cppSDL_WINDOW_FULLSCREEN_DESKTOP、タッチイベント、戻るボタン、logcat 出力
FontManager.cppSDL_RWFromFile で APK assets から読み込み
AssetProvider.cppSDL_RWFromFile + SDL_RWread で JSON 読み込み
FileStorage.cppSDL_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
Ad: stickyBottom (728x90)
kaedevn - ノベルゲームを作れるプラットフォーム