AWS SDK for .NETを使うUnityアプリをiOS/Android向けにビルドする
以下の記事で作成したUnityアプリをiOS/Android向けにビルドします。
- UnityでCognito UserPoolsを使ってサインアップ・サインインを実現する
- UnityでCognito UserPoolsから得たトークンでリクエストし、API Gatewayでsubを受け取る
ゲームビューで動作確認
Unityエディタの再生ボタンを押して、正常に動作するか確認します。
このとき、実行環境によってはTlsExceptionが以下のようなエラーがでるようです。(スタックトレースは見やすいように加工しています)
Amazon.Runtime.AmazonServiceException: A WebException with status TrustFailure was thrown. ---> System.Net.WebException: Error: TrustFailure (The authentication or decryption has failed.) ---> System.IO.IOException: The authentication or decryption has failed. ---> Mono.Security.Protocol.Tls.TlsException: Invalid certificate received from server. Error code: 0xffffffff800b010a
これは、Unity Scripting RuntimeのMonoに標準でルート証明書がインストールされていないために発生します。後のiOS/Androidでも同様の問題が発生するのですが、まずはUnityエディタに限定して対応します。以下のURLでも報告されている通り、mozroots
というツールを使って証明書を取得することで解決します。
Windowsでは以下のようにコマンドを実行します。この時、Unity付属のmonoを使うことを忘れないでください。
mozroots.exe --imort --sync
Macの場合は、新しいもの(10.13.4で確認)では発生しませんでした。
Android向けにビルドする
ビルド環境のセットアップ
公式ドキュメントはこちらです。
このドキュメントを参考にしつつ、以下の作業を行いました。
- Android Studioのインストールと、HelloWorldアプリを作成して実行(追加コンポーネントが後からダウンロードされるため)
- Android NDKのダウンロードとインストール
- UnityのFile > Build Settings...でPlatformをAndroidに変更して、SDK/JDK/NDKのパスを設定
- その際にUnityのAndroid moduleインストールを案内されるので実施
- デバッグモードにしたAndroid端末を接続してBuild and Run
執筆時点では過去バージョンのNDKを使わなければエラーが発生します。
- windows: https://dl.google.com/android/repository/android-ndk-r13b-darwin-x86_64.zip
- mac: https://dl.google.com/android/repository/android-ndk-r13b-darwin-x86_64.zip
参考URL: UnityからAndroid実機ビルド手順(2017.08版) - Qiita
TLSの問題について
執筆時点で、Androidでビルドすると、AWS SDKを呼び出す箇所でゲームビューの時と同じTlsExceptionが発生します。
以下のStackOverflowについている回答が参考になるかと思いましたが、回答のコメントで指摘されている通り、Bad SSLでテストしてもtureが返されるため、検証できていないようです。
Mono https webrequest fails with The authentication or decryption has failed"- StackOverflow
Androidビルドではmozrootsを使えないので、代替案を探しているところです。ご存知の方はコメントをお願いします。
iOS向けにビルドする
ビルド環境のセットアップ
ドキュメントはこちらです。
Androidとは違い、developer.apple.comでの作業が発生します。
気をつける点としては、Player Settingsの Automatic Signing Team ID
は任意オプションとなっていますが、ここにTeamIDを入力しない場合は、Unityのビルドで生成されるXCode ProjectにTeam ID設定が入らず、ビルドエラーになります。
iPhoneを繋ぎっぱなしにしてビルドしながら開発するスタイルの場合は、設定することをお勧めします。
link.xmlについて
この記事の本題です。
ビルドしたiOSアプリでAWS SDKの処理を呼ぶと、以下のスタックトレースを出してアプリが停止します。例によって、スタックトレースは抜粋です。
MissingMethodException: Default constructor not found for type Amazon.Util.Internal.PlatformServices.NetworkReachability at System.RuntimeType.CreateInstanceMono (System.Boolean nonPublic) [0x00000] in <00000000000000000000000000000000>:0 at System.RuntimeType.CreateInstanceSlow (System.Boolean publicOnly, System.Boolean skipCheckThis, System.Boolean fillCache, System.Threading.StackCrawlMark& stackMark) [0x00000] in <00000000000000000000000000000000>:0
このエラーは、Unityが行なっている最適化に起因します。
AppStoreでリリースするアプリをビルドするためには、Unity Scripting BackendとしてIL2CPPを使用しなければなりません。以下、ドキュメントからの引用です。
IL2CPP は iOS ARM 64ビットのデプロイをサポートするスクリプトバックエンドなので、新しいアプリのリリースで Apple の App Store を利用するためには必須です。
AWS SDK for .NETのUnity向けReadmeによると、IL2CPPの strip bytecode
がUnityビルド時に常に有効になっているので、AWS SDKがリフレクションしているメソッドが削減されるため、ランタイムエラーが発生するそうです。
したがって、AWS SDKのReadmeとUnityのIL2CPPドキュメントに従って、必要なライブラリを link.xml
に記載して、Assetsディレクトリ直下に配置する必要があります。link.xmlに書いたライブラリは、最適化時の削減対象になりません。
ランタイムエラーのスタックトレースを見ながら、少しずつ編集したものが以下のlink.xmlです。
<linker> <assembly fullname="UnityEngine"> <type fullname="UnityEngine.Networking.UnityWebRequest" preserve="all" /> <type fullname="UnityEngine.Networking.UploadHandlerRaw" preserve="all" /> <type fullname="UnityEngine.Networking.UploadHandler" preserve="all" /> <type fullname="UnityEngine.Networking.DownloadHandler" preserve="all" /> <type fullname="UnityEngine.Networking.DownloadHandlerBuffer" preserve="all" /> </assembly> <assembly fullname="mscorlib"> <namespace fullname="System.Security.Cryptography" preserve="all"/> </assembly> <assembly fullname="System"> <namespace fullname="System.Security.Cryptography" preserve="all"/> <namespace fullname="System.ComponentModel" preserve="all" /> </assembly> <assembly fullname="System.Configuration"> <namespace fullname="System.Configuration" preserve="all" /> </assembly> <assembly fullname="AWSSDK.Core" preserve="all"> <namespace fullname="Amazon.Util.Internal.PlatformServices" preserve="all"/> </assembly> <assembly fullname="AWSSDK.CognitoIdentity" preserve="all"/> <assembly fullname="AWSSDK.CognitoIdentityProvider" preserve="all"/> <assembly fullname="AWSSDK.SecurityToken" preserve="all"/> <assembly fullname="AWSSDK.Extensions.CognitoAuthentication" preserve="all"/> </linker>
この問題とは別にTlsExceptionも発生するため、Android同様の課題があります。
まとめ
UnityアプリをiOS/Android向けにビルドする際の注意点を書きました。
サーバーレス環境ではクライアントが直接AWS SDKを実行する機会が増えるので、このような問題に対処できるナレッジを蓄積して行きましょう。