Unity as a Libraryを使ってみよう　~AndroidとUnityだってチームを組める~

# はじめに
こんにちは！
東海メンターのだすです。
この記事は[Life is Tech ! Tokai Advent Calendar 2022](https://qiita.com/advent-calendar/2022/life-is-tech-tokai)の1日目の記事です。

**Android(iOS)とUnityだって工夫すれば一緒にチームを組んで作品を作ることができるよ！
みんなで楽しくものづくりしようぜ！**
ということが言いたくて、その間をつなげられるUnity as a Libraryの紹介をするよという内容です。

# きっかけ
ハッカソンに参加した時、チームのメンバーがAndroid、Unityなど手持ちの技術がバラバラでした。
こういう時は学習コストなどを考えると技術選定は難しいですよね。

その時使ったのがUnity as a Libraryで、UnityをAndroidのネイティブアプリ上で動かすというものでした。

# Unity as a Library(UaaL)とは
> [Unity as a Library（UaaL）](https://unity.com/ja/features/unity-as-a-library)はUnityをネイティブアプリのライブラリとして利用する技術で、アプリで作ったViewとUnityで作ったViewを共存させられます。

AndroidやiOSのネイティブアプリに組み込むことができ、[Mirrativ](https://www.mirrativ.com)や[Reality](https://reality.app/)のアプリに使われているそうです。

# 開発環境　
- AndroidStudio 2021.3.1
- Unity 2021.3.6f1
# Unityの実装
まずは簡単なUnityのプロジェクトを作ります。
今回は適当にSphereをたくさん降らせました。

これをエクスポートしてAndroidで読み込める状態にしていきます。
![スクリーンショット 2022-12-04 17.48.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/7da9ee86-bb35-0f43-e3b8-9866031a295d.png)

## Unityからエクスポート
### Build Settings
`File → Build Settings`を開いて、`Platform`を`Android`にします。
`Export Project`にはチェックを入れておきます。
![スクリーンショット 2022-12-04 2.56.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/09f3d7bf-b971-3630-6519-71b6821c1d67.png)

### Player Settings
`Build Settings`の左下のボタンより`Player Settings`を開きます。
`Configuration → Scripting Backend`を`IL2CPP`にします。
次に`Target Architectures → ARM64`にチェックを入れます。
![スクリーンショット 2022-12-04 2.58.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/a7439599-f442-a02c-6dec-5eca6a071fbc.png)
`Build → Custom Main Manifest`にチェックを入れて、`AndroidManifest.xml`をカスタマイズできるようにします。
![スクリーンショット 2022-12-04 3.02.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/15d0f741-391a-af3c-c912-b5a76e739f5c.png)
#### AndroidManifest.xml(Unity)
UnityのプロジェクトのアセットにAndroidManifest.xmlファイルが追加されるので編集します。
`<intent-filter>~</intent-filter>`を削除しておきます。
このタグが付いているActivityが立ち上げ時に実行されるので必要だったら編集してください。
![スクリーンショット 2022-12-04 3.19.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/6e8ca3f0-badc-084d-6fde-f445c9468402.png)

### エクスポート
設定が終わったらプロジェクトを`Build Settings → Export`よりエクスポートします。

![スクリーンショット 2022-12-04 18.30.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/bcbc2105-e0b0-d3c2-95b8-0b9060dfc8af.png)

`Build`フォルダがない場合はフォルダを作成して、ここにエクスポートしましょう。
（自分が気が付くのに時間がかかったポイント）
`unityLibrary`というディレクトリが出力されていれば正常です。
![スクリーンショット 2022-12-04 3.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/e783ea06-b1da-f3c0-4c48-41e0dba61918.png)



これでUnity側は完了です！

# Androidの実装
Android側の実装をしていきます。
今回はシンプルに1画面の上半分にUnityを表示させてみます。
下半分はAndroidらしくネイティブのUIを配置しておきます。

**完成図**
<img width=30% src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/e9f448c9-7a02-8d6e-5b62-8da65cfae943.jpeg" alt="85511.jpg">

## Unityのインポート
Androidプロジェクトのディレクトリ内に先ほどエクスポートした`unityLibrary`をコピーして配置します。
![スクリーンショット 2022-12-04 22.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323458/82c89456-8c4c-552e-02df-d9daa676f75a.png)


## 設定
ここからプロジェクト内でUnityLibraryを扱えるように設定をしていきます。
まずは、unityLIbraryにあるプロジェクトを読み込むために`settings.gradle`に以下を加えます。
```settings.gradle
include ':unityLibrary'
```
依存関係を記述するために`build.gradle(Module:app)`に以下を追加します。
```gradle:build.gradle(Module:app)
dependencies {
    ...
    implementation project(':unityLibrary')
    implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])
}
```
Unity2020以降で発生するようになったエラーに対して以下を追加します。
```gradle:gradle.propereties
unityStreamingAssets=.unity3d
```
NDKが必要になるので以下を`local.properties`に追加します。
今回はUnity Hubで読み込んだNDKを参照しています。
```gradle:local.properties
ndk.dir=/Applications/Unity/Hub/Editor/2021.3.8f1/PlaybackEngines/AndroidPlayer/NDK
```
以下がUnityから参照されているらしく`String.xml`に追加しないとクラッシュしました。
```strings.xml
<string name=”game_view_content_description”>Game view</string>
```

以上で設定は完了です。
ビルドが通るか確認してください。

## アプリの実装
次はUnityをレイアウトに追加していきます。
今回は1画面の構成なので`activity_main.xml`と`MainActivity.kt`を編集します。
```activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:id="@+id/unity"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHeight_percent="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <LinearLayout
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:gravity="center"
        android:orientation="vertical"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/unity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello World!" />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:text="Button" />

    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
```

```MainActivity.kt
package com.norihiro.uaalsample

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.ViewGroup
import android.view.WindowManager.LayoutParams.SCREEN_ORIENTATION_CHANGED
import androidx.constraintlayout.widget.ConstraintLayout
import com.unity3d.player.UnityPlayer
import com.unity3d.player.UnityPlayerActivity


class MainActivity : UnityPlayerActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        window.clearFlags(SCREEN_ORIENTATION_CHANGED)
        findViewById<ConstraintLayout>(R.id.unity)?.addView(
            mUnityPlayer, ViewGroup.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT
            )
        )
    }
}
```

# 動作確認
以上で実装は終わりです。
実行してみましょう！

https://twitter.com/DasunaDev/status/1599421390767415296

# 終わりに
Unityは容量が大きくAndroidアプリとしてはビルドに時間がかかったりとデメリットもあります。
その分リッチな3D表現ができるのは場合によっては十分なメリットだと思います。

周りにいろんなエンジニアがいると思うんですけど、どうしてもプラットフォームごとにコミュニティが分かれて交流が持てないということもあると思います。
でもこうして一緒にアプリを作ることができるともっと楽しくものづくりができると思うので、よかったらUaaLを試してみてください。

いつかこの記事の続編として、Android、Unity間のデータ通信についても取り上げたいです。

# 参考記事
今回の記事は以下の記事を参考にさせていただきました。
ありがとうございました。

https://qiita.com/cha84rakanal/items/4a1e4b242ec40e3e8121

https://qiita.com/Yuuki_S/items/5e54a9de6327e03dbe6a

https://medium.com/swlh/unity-as-a-library-bring-unity-features-to-your-android-app-9936bea9b775

https://tech.mirrativ.stream/entry/2021/08/24/191503

https://forum.unity.com/threads/using-unity-as-a-library-in-native-ios-android-apps.685195/

https://forum.unity.com/threads/integration-unity-as-a-library-in-native-android-app.685240/