FlutterUnityWidgetを使ってUaaL(Flutter)を試す

この記事では、FlutterUnityWidgetを使ってUaaL(Flutter)をビルドするまでの手順をまとめています。
今回は、iOSでのビルドについてまとめています。

:::note warn
UaaLはUnityドキュメントに明記ある通り、多少難易度の高い実装方法となります。
また、Xcodeでアプリをビルドする為の詳細な手順（iOS端末を開発者モードにする手順など）については省略をしています。
:::

![スクリーンショット 2023-04-29 12.21.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/ff723742-b1f4-41db-7572-3bb7bf900b3e.png)




## UaaLとは

UaaL (Unity as a Library)は、UnityプロジェクトをLibraryとして扱えるようにすることができるプラグインです。これにより、UnityプロジェクトをFlutterプロジェクトに統合できます。

[https://unity.com/ja/features/unity-as-a-library](https://unity.com/ja/features/unity-as-a-library)

## Flutterとは
Flutterは、Googleが開発しているオープンソースのモバイルアプリケーション開発フレームワークです。Flutterの最大の特徴は、高速な開発スピードと美しいUIの作成が可能であることです。Flutterは、Dartというオブジェクト指向のプログラミング言語を使用しています。Dartは、JavaScriptと似た構文を持ち、TypeScriptのような静的型付けの機能も備えています。

https://docs.flutter.dev/

## FlutterUnityWidgetとは
flutter_unity_widgetは、FlutterとUnityを統合するためのプラグインです。具体的には、UaaL (Unity as a Library)を利用して、UnityプロジェクトをFlutterアプリ内で実行できます。これにより、Flutterで作成したUIとUnityで作成したゲームやAR/VRコンテンツを組み合わせたアプリを開発できます。

[https://github.com/juicycleff/flutter-unity-view-widget](https://github.com/juicycleff/flutter-unity-view-widget)


## 開発環境

```
macOS: 13.3.1 
Flutter: Channel stable, 3.7.11
Dart: version 2.19.6
Java: OpenJDK Runtime Environment (build 17.0.6+0-17.0.6b802.4-9586694)
Xcode: 14.2
CocoaPods: version 1.11.3
Android Studio: version 2022.2
VS Code version 1.77.3
```


## Flutterの開発環境セットアップ

詳細な手順は[公式サイト](https://docs.flutter.dev/get-started/install)に記載があるので割愛しますが、基本的に`flutter doctor`ですべての項目に✅チェックがつくことでセットアップは完了します。


1. [公式サイト](https://docs.flutter.dev/get-started/install)からFlutter SDKをダウンロードしてインストールします。
2. `flutter/bin`のpathを通す。
3. インストール後、`flutter doctor` コマンドを実行して、Flutterの動作環境を確認します。必要なパッケージやライブラリがインストールされているか確認しましょう。
    
:::note info
Xcodeのインストールはバージョン管理を行えるように、`xcodes`からインストールすることをオススメします。

[xcodes](https://github.com/XcodesOrg/xcodes)
:::

```bash
% flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 3.7.11, on macOS 13.3.1 22E261 darwin-arm64, locale ja-JP)
[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2022.2)
[✓] VS Code (version 1.77.3)
[✓] Connected device (3 available)
[✓] HTTP Host Availability

• No issues found!
```
    

## 🔨サンプルをビルドする
### リポジトリのclone

flutter_unity_widgetのリポジトリをclone

```jsx
git clone https://github.com/juicycleff/flutter-unity-view-widget.git
```

### UnityProjectをビルド
1. Unity Hubから以下のディレクトリにあるUnityProjectを開きます
`flutter-unity-view-widget-master/example/unity/DemoApp`


![スクリーンショット 2023-04-28 23.12.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/8a4fa062-705b-4bec-d7f0-625524472928.png)


2. Flutterのメニューから `Export IOS (Debug)`を選択してUnityプロジェクトのビルドを行います

![スクリーンショット 2023-04-28 23.13.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/3a6c87ff-bf2c-e45b-c0a3-eb2201f775f6.png)

:::note info
Unityプロジェクトの成果物 -> `flutter-unity-view-widget-master/example/ios/UnityLibrary`
:::


### flutter パッケージのインストール

ターミナルで`flutter-unity-view-widget-master/example` に移動後、同じディレクトリで `flutter pub get` を実行します。

<details><summary>実行ログ</summary>

```jsx
% flutter pub get      
Running "flutter pub get" in example...
Resolving dependencies... (2.8s)
+ async 2.10.0 (2.11.0 available)
+ boolean_selector 2.1.1
+ characters 1.2.1 (1.3.0 available)
+ clock 1.1.1
+ collection 1.17.0 (1.17.1 available)
+ cupertino_icons 1.0.5
+ fake_async 1.3.1
+ flutter 0.0.0 from sdk flutter
+ flutter_plugin_android_lifecycle 2.0.13
+ flutter_test 0.0.0 from sdk flutter
+ flutter_unity_widget 2022.2.0 from path ..
+ flutter_web_plugins 0.0.0 from sdk flutter
+ js 0.6.5 (0.6.7 available)
+ matcher 0.12.13 (0.12.15 available)
+ material_color_utilities 0.2.0 (0.3.0 available)
+ meta 1.8.0 (1.9.1 available)
+ path 1.8.2 (1.8.3 available)
+ plugin_platform_interface 2.1.4
+ pointer_interceptor 0.9.3+4
+ sky_engine 0.0.99 from sdk flutter
+ source_span 1.9.1 (1.10.0 available)
+ stack_trace 1.11.0
+ stream_channel 2.1.1
+ stream_transform 2.1.0
+ string_scanner 1.2.0
+ term_glyph 1.2.1
+ test_api 0.4.16 (0.5.2 available)
+ vector_math 2.1.4
+ webview_flutter 4.2.0
+ webview_flutter_android 3.6.2
+ webview_flutter_platform_interface 2.3.0
+ webview_flutter_web 0.2.2+1
+ webview_flutter_wkwebview 3.4.0
Changed 33 dependencies!
```

</details>


### UnityAppControllerの修正

Editorで以下のファイルを開き以下に記載するissue通りに変更を加えてください。
- UnityAppController.mm
- UnityAppController.h

[この](https://github.com/juicycleff/flutter-unity-view-widget/issues/486#issuecomment-1451511927)issue通りに変更する

https://github.com/juicycleff/flutter-unity-view-widget/issues/486#issuecomment-1451511927

![スクリーンショット 2023-04-29 1.37.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/355cd5de-d4cb-e11d-4ce3-13f452d559b9.png)


### Podfileのインストール

1. Editorで`flutter-unity-view-widget-master/example/ios/Podfile`を開き以下の項目を変更します

    2行目を変更
    ```jsx
    - # platform :ios, '11.0' //変更前
    + platform :ios, '12.0' //変更後
    ```

    ![スクリーンショット 2023-04-28 23.03.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/85dc2dda-cf8e-e219-3280-abbc126fa7c7.png)



2. ターミナルで`flutter-unity-view-widget-master/example/ios`に移動して `pod install`を実行します

    <details><summary>実行ログ</summary>
    
    ```jsx
    % pod install
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring json-1.8.6 because its extensions are not built. Try: gem pristine json --version 1.8.6
    Ignoring unf_ext-0.0.8.2 because its extensions are not built. Try: gem pristine unf_ext --version 0.0.8.2
    Analyzing dependencies
    Downloading dependencies
    Generating Pods project
    Integrating client project
    Pod installation complete! There are 3 dependencies from the Podfile and 3 total pods installed.
    
    [!] CocoaPods did not set the base configuration of your project because your project already has a custom config set. In order for CocoaPods integration to work at all, please either set the base configurations of the target `Runner` to `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` or include the `Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig` in your build configuration (`Flutter/Release.xcconfig`).
    ```
</details> 


### Xcodeでプロジェクトのワークスペースを開き一部項目の変更をする

`flutter-unity-view-widget-master/example/ios/Runner.xcworkspace`をXcodeで開きます。

:::note warn
`Runner.xcodeproj`ではなく、`Runner.xcworkspace`を開く
:::

1. minimum deploymentを11→12に変更
`Unity-iPhone` `Runner`ともに、MinimumDeploymentsを12.0以降に変更する
    ![スクリーンショット 2023-04-29 1.29.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/d6aa4d37-7dfc-243b-b5d9-d92b88129ff9.png)
    
    :::note warn
    `flutter_unity_widget`の最低動作環境がiOS 12.0以上の為


2. `Unity-iPhone/Data`フォルダーのTarget Membershipを変更する
    ![スクリーンショット 2023-04-29 1.31.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/4ff5d389-bf9b-5a64-e286-61e940b91f57.png)

3. Build Configurationの変更
    `⌘` + `shift` + `,` のショートカットキーでメニューを開き以下の項目を変更する
    - Build Configurationを`Release`に変更
    - `Debug executable`のチェックを外す
    ![スクリーンショット 2023-04-28 23.29.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/64c339a6-507a-c56f-5ad4-c8a78d596622.png)



### `flutter run`を実行

iOS端末をmacに接続して`flutter run`を実行します。

```jsx
% flutter run
Launching lib/main.dart on KouheiのiPhone in debug mode...
Warning: Missing build name (CFBundleShortVersionString).
Warning: Missing build number (CFBundleVersion).
Action Required: You must set a build name and number in the pubspec.yaml file version
field before submitting to the App Store.
Automatically signing iOS for device deployment using specified development team in Xcode
project: ******
Running pod install...                                             787ms
Running Xcode build...                                                  
 └─Compiling, linking and signing...                         6.1s
Xcode build done.                                           40.9s
Installing and launching...                                        25.9s
Connecting to the VM Service is taking longer than expected...
Built from '2021.3/staging' branch, Version '2021.3.16f1 (4016570cf34f)', Build type 'Development', Scripting Backend 'il2cpp'
MemoryManager: Using 'Default' Allocator.
[UnityMemory] Configuration Parameters - Can be set up in boot.config
    "memorysetup-bucket-allocator-granularity=16"
    "memorysetup-bucket-allocator-bucket-count=8"
    "memorysetup-bucket-allocator-block-size=4194304"
    "memorysetup-bucket-allocator-block-count=1"
    "memorysetup-main-allocator-block-size=16777216"
    "memorysetup-thread-allocator-block-size=16777216"
    "memorysetup-gfx-main-allocator-block-size=16777216"
    "memorysetup-gfx-thread-allocator-block-size=16777216"
    "memorysetup-cache-allocator-block-size=4194304"
    "memorysetup-typetree-allocator-block-size=2097152"
    "memorysetup-profiler-bucket-allocator-granularity=16"
    "memorysetup-profiler-bucket-allocator-bucket-count=8"
    "memorysetup-profiler-bucket-allocator-block-size=4194304"
    "memorysetup-profiler-bucket-allocator-block-count=1"
    "memorysetup-profiler-allocator-block-size=16777216"
    "memorysetup-profiler-editor-allocator-block-size=1048576"
    "memorysetup-temp-allocator-size-main=4194304"
    "memorysetup-job-temp-allocator-block-size=2097152"
    "memorysetup-job-temp-allocator-block-size-background=1048576"
    "memorysetup-job-temp-allocator-reduction-small-platforms=262144"
    "memorysetup-temp-allocator-size-background-worker=32768"
    "memorysetup-temp-allocator-size-job-worker=262144"
    "memorysetup-temp-allocator-size-preload-manager=262144"
    "memorysetup-temp-allocator-size-nav-mesh-worker=65536"
    "memorysetup-temp-allocator-size-audio-worker=65536"
    "memorysetup-temp-allocator-size-cloud-worker=32768"
    "memorysetup-temp-allocator-size-gfx=262144"
-> applicationDidFinishLaunching()
Found 3 interfaces on host : 0) 10.129.211.16 1) 169.254.37.193 2) 172.20.10.1
Multi-casting "[IP] 10.129.***.*** [Port] ****** [Flags] 2 [Guid] ****** [EditorId] ****** [Version] 1048832 [Id] iPhonePlayer(8,KouheinoiPhone):**** [Debug] 1 [PackageName] iPhonePlayer [ProjectName] flutterunitywidgets" to [225.0.***.***:****]...
Starting managed debugger on port 56000
```

//TODO: 動画のサイズ変える

![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/968526/54c79645-9fc7-8462-f0f7-913221023c72.gif)


何かエラーが発生した場合は、`Runner.xcworkspace` を開いてXcodeから手動でビルドするとエラー解消を行いやすいです。



## 終わりに

UaaLは初期の学習コストが高いですが、一度乗り切ってしまうとUnityの可能性が大きく広がります！
とくに、Flutterは多くのライブラリとパッケージが用意されており、UIの実装に必要な機能やデザイン要素を簡単に追加できます。

https://fluttergems.dev/

UnityのUIをFlutterに置き換える選択肢、なかなかありなのはないでしょうか？


何か解決できないエラーが発生したら本記事のコメントか、[Twitter](https://twitter.com/K0uhe1D)までどうぞ🙌


## 参考サイト

https://unity.com/ja/features/unity-as-a-library

https://pub.dev/packages/flutter_unity_widget

https://github.com/juicycleff/flutter-unity-view-widget/tree/master

https://docs.flutter.dev/get-started/install

https://github.com/juicycleff/flutter-unity-view-widget/issues/486#issuecomment-1451511927