1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Android】Unityアプリをネイティブアプリに組み込んでみる

Last updated at Posted at 2025-12-13

この記事はレコチョク Advent Calendar 2025 の 14日目の記事となります。

はじめに

こんにちは!
Androidアプリ開発エンジニアの杉山です。
つい先日今年1番聞いた楽曲を見ることができたのですが、自分が聴いていた楽曲はCieloさんの「ルート39」でした。よかったら聴いてみてください!!

近年連続で出展させていただいているMaker Faire TokyoにてUnityを使った作品を公開し、たくさんの方々に体験していただきました。(作品やイベントに関しては、プレスリリースをご覧ください。)

過去の作品ではPC向けのUnityアプリを製作していました。ですが自分はAndroidエンジニアなので、Android向けにアプリを作ってみたいなと考えていました。
UnityではAndroid用にアプリをビルドすることも可能となっているので試しにやってみようとしたのですが、そこでふとある考えが浮かびました。

ゲームロジックをUnityで実装しながら、スタート画面などのUIをJetpack Composeで構築するハイブリッドアプローチなら、ComposeのインターフェースとUnityの表現力を両立させることができるのではないか?ゲームに直接関係しないUI部分はJetpack Composeを用いることにより、再コンポーズによるリソースの最適化や実装の簡略化、機能の棲み分けができるのではないか?と思いました。

そこで今回は、UnityをAndroidのネイティブアプリに組み込むためにはどうしたらいいのか、そもそも可能なのかを実際に試してみることにしました。

作成物概要、使用技術

UnityでARフレームワークを使った簡易的な風船割りゲームを作成し、 Androidネイティブアプリからライブラリとして呼び出せるようにします。スタート画面はJetpack Compose、ゲーム画面はUnityといった構成となるアプリの完成を目指します。
使用技術は以下になります。

カテゴリ 技術
開発PC/OS MacBook Pro(Apple M4 Proチップ)/macOS Sequoia(15.2)
ゲームエンジン Unity 6000.2.12f1 (IL2CPP バックエンド)
AR フレームワーク AR Foundation 6.2.1 + ARCore XR Plugin
Android UI Jetpack Compose + Material Design 3
ビルドシステム Gradle 8.13 + Android SDK 36 + NDK 27.2

開発手順

今回行った開発を以下の手順で紹介していきます。

  1. Unity AR 設定
  2. Unity ライブラリエクスポート
  3. Android アプリ構築
  4. 詰まった点

1. Unity AR 設定

まずは組み込むUnity側のアプリをつくりたいので、Unityをインストール後 Universal 3D で新規プロジェクトを作成します。
そして、作成するのはAndroid向けアプリになりますので、File -> Build Profilesで、PlatformをAndroid に切り替えます。

必要なパッケージのインストール

次に、以下に必要なパッケージをまとめてあるのでインストールしてください。
Window -> Package Management -> Package Managerを開いて、Unity Registryのタブの部分で各パッケージを検索するとインストールできます。

パッケージ 用途
AR Foundation AR 基本機能
Google ARCore XR Plugin Android AR サポート

Player Settings の設定

Playerの設定を行います。設定は、Edit -> Project Settings -> Playerからできます。
この部分を設定することで、AR Foundation と ARCore の動作要件に合わせた設定つまり、カメラによる動作負荷の部分の設定ができます。

  • Scripting Backend: IL2CPP
  • Target Architectures: ARM64 チェック(ARMv7 は外す)
  • Minimum API Level: 24 以上(自分の環境では29にしました)
  • Graphics APIs: Vulkan を削除(OpenGL ES 3.0 を保持)
  • Multithreaded Rendering: チェック OFF
  • Managed Stripping Level: Minimal

XR Plugin Management の有効化

Edit -> Project Settings -> XR Plug-in Managementを開きます。「Install XR Plugin Management」を押して、インストールをします。その後、以下の設定を行なってください。
今回はAndroidで実装するため、Google ARCoreを使えるように設定します。

  • Android タブで Google ARCore を ON
  • Initialize XR on Startup: チェック ON

Scene 設定

Hierarchyに以下の対応を行なってください。

  • 「+」をクリック -> XR -> AR Session を追加
  • 「+」をクリック -> XR -> XR Origin を追加
  • Main Camera を削除
  • XR Origin の中にある Camera を MainCamera タグに設定

これで AR Foundation の基本的な設定が完了しました。あとはゲームの内容を実装していくのですが、今回のメインはUnityアプリとネイティブアプリの組み合わせ部分になるため割愛します。(実装には社内AIであるRecoChatを活用しました)

実際にできたゲームが以下になります。カメラを動かすと空間内にある風船を見つけることができ、タップすると割れてスコアが増え、新しい風船が生み出されます。今回はこのアプリをライブラリ化してネイティブアプリで動かせるようにします。

2. Unity ライブラリエクスポート

作成したアプリをライブラリとしてExportしたいのでFile -> Build Profiles -> Platform -> Android に移動し、"Export" チェックボックスを ON にします。

押すと出力先フォルダを選択する必要があるので、フォルダを指定、または作成して出力します。
(例: D:/UnityExport/unityLibrary)

エクスポートが完了すると生成されたフォルダ内に unityLibrary が作成されます

生成される構造

生成されたフォルダ内は画像のようになっています。この中で赤枠で囲まれた部分をライブラリとして利用します。unityLibraryの中に、作成したゲームの内容が入っており、sharedが必要なのはunityLibrary内で参照し利用しているためです。ライブラリ化自体は簡単にUnity側でやってくれることがわかりました。

3. Android アプリ構築

エクスポートできたらAndroidのネイティブアプリの方を準備します。今回はJetpack Composeを使って実装しています。

先ほど説明した通り、unityLibraryとsharedのフォルダをAndroidプロジェクトに移します。
移す場所はプロジェクト直下に移してください。移動させたあとは以下の画像のようになっていればOKです。

※今回はライブラリを組み込むにあたって必要な部分を解説しています。Composeの実装部分などは割愛しているため、不足している部分などはそれぞれの環境で補完していただければと思います。

settings.gradle の設定

unityLibraryの中にあるAARファイルを読み取る必要があるため、dirのパスを通します。

pluginManagement {
    repositories {
        google {
            content {
                includeGroupByRegex("com\\.android.*")
                includeGroupByRegex("com\\.google.*")
                includeGroupByRegex("androidx.*")
            }
        }
        mavenCentral()
        gradlePluginPortal()
    }
}
dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
    repositories {
        google()
        mavenCentral()
        // unityLibraryの中に入っているAARファイルを読み取れるようにする
        flatDir {
            dirs("unityLibrary/libs")  
        }
    }
}

rootProject.name = "YourProductsName"
include(":app")
// 作成したライブラリを読み込めるようにするために追加
include(":unityLibrary")
include(":unityLibrary:xrmanifest.androidlib")

build.gradle (Module: app) の設定

ライブラリをコード内で利用できるようにするために、implementationとして追加します。追加する際はprojectとして追加します。

android {
    compileSdk 36
    defaultConfig {
        minSdk 29
        targetSdk 36
    }

    // その他必要な設定を追加してください(省略)
}

dependencies {
    // Jetpack Composeなどに必要なものを追加(省略)
    
    // ExportしたUnity ライブラリ
    implementation(project(":unityLibrary"))
}

AndroidManifest.xml の設定

ここは今回作成したアプリがARカメラを使うアプリであったので、必要なパーミッションなどを追加しています。

<manifest>
    // ARカメラを利用するので必要なパーミッション,featureを追加
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    
    <uses-feature
        android:name="android.hardware.camera.ar"
        android:required="false" />

    <uses-feature android:name="android.hardware.camera" />

    <application>
        <activity
            android:name=".MainActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

MainActivity の実装

実際に、Unityのゲーム画面を呼び出す部分になります。Activityとして作成されているので、startActivity()intentとして呼び出してあげれば起動させることができます。

class MainActivity : ComponentActivity() {
    companion object {
        const val TAG = "MainActivity"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            ARBubblesTheme {
                AppNavigation(
                    onStartUnityAR = { startUnityAR() },
                    onExit = { finish() }
                )
            }
        }
    }

    private fun startUnityAR() {
        val intent = Intent(this, UnityPlayerGameActivity::class.java)
        startActivity(intent)
    }
}

@Composable
fun AppNavigation(
    onStartUnityAR: () -> Unit,
    onExit: () -> Unit
) {
    val navController = rememberNavController()

    NavHost(
        navController = navController,
        startDestination = "permission"
    ) {
        composable("permission") {
            PermissionScreen(
                onPermissionGranted = {
                    navController.navigate("start") {
                        popUpTo("permission") { inclusive = true }
                    }
                }
            )
        }

        composable("start") {
            StartScreen(
                onARButtonClick = onStartUnityAR,
                onExitClick = onExit
            )
        }
    }
}

出来上がったアプリがこちらになります!
ARカメラのための権限許可からアプリのスタート画面をComposeで作成し、ゲーム自体はUnityで作成したものを呼び出して実行できるようになりました!

4. 詰まった点

Unity側で生成したaarファイルが読み込まれない

ビルドをしようとするとaarファイルが見つからないエラーが…

色々試した結果、導入したフォルダの構成が良くなかったことが原因でした。
UnityのアプリをExportした際に、画像のunityExportを丸ごとネイティブアプリのプロジェクトに移動させていました。
そのため、構造が複雑になってしまい、正しくファイルが読み取れない状態になってしまっていたので、ビルドができない状態になっていました。
最初はパスなどを変えたりして対応していたのですが、そもそも不要なファイルが多かったりしていたことも原因かもしれません…

解決策として必要なフォルダ、ファイルのみを正しい構成で入れ直す。Android アプリ構築を参照することで無事Unityアプリを起動することができました。

まとめ

Unityアプリをライブラリ化し、Androidのネイティブアプリから呼び出せるようにしてみました。
ComposeとUnityで画面の作り分けができるようになることがわかったので、より自由度の高いアプリが作れるようになると思いました!
今後さらに拡張する上で、Unityアプリからスコアなどをネイティブアプリの方に呼び出せるようにしてスコアボードなどを作れたらいいなと考えています。

記事を読んでいただきありがとうございました!
明日の レコチョク Advent Calendar 2025 は15日目「【Swift】クロージャの種類と省略形」です。お楽しみに!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?