前回は管理画面からAWS Lambdaを動かしました。
今回の目標はこの2つです。
・UnityからAWS Lambdaを動かしてみる
・Unityで作ったアプリをiPhoneで実行してAWS Lambdaを動かしてみる
[参考] AWS Mobile SDK for Unityを使ってサーバーレスなアプリを開発する:
http://nil-one.com/blog/article/2016/04/14/AWS_Mobile_SDK_for_Unity/
上記の参考ページにもありますが、"AWS Mobile SDK for Unity"を使います。
AWS Mobile SDK for Unity:
http://docs.aws.amazon.com/mobile/sdkforunity/developerguide/
SDKの対象にAWS Lambdaがありますね。
そして、Amazon Cognito も対象になっている点がポイントです(後述)。
はじめに、AWS Mobile SDK for Unityを上記のURLからダウンロードします。

Unityで新規プロジェクトを作成します。
ここでは、LambdaTest という名前にして、2Dで作成します。

Unityでプロジェクトが作成できたら、先ほど解凍した中から
AWSSDK.Lambda.3.1.4.7.unitypackage
をWクリックしてUnityにすべてインポートします。


UnityのBuildSettings(Ctrl+Shift+B)では、iOSにSwitchPlatformしておきます。

ProjectウィンドウのAssets > Examples > LambdaExampleシーン をWクリックして
サンプルシーンを開きます。

Gameウィンドウにプレビューが表示されるのですが、
カメラが配置されていないために警告(No cameras redering)が出ます。

再生ボタンを押すと実行はされますが、気持ち悪いのでシーンにカメラを追加します。
Hierarchyウィンドウで右クリック > Camera でカメラを追加すると警告は消えます。

カメラが追加された後のHierarcyウィンドウです。

先ほど、再生ボタンを押せば実行されると書きましたが、実行はされますが
ボタンを押しても何も反応しません。
理由は、Lambdaオブジェクトに本来適用されているスクリプトが抜け落ちているからです!

Assets > Examples > LambdaExample(C#ファイル) を先ほどのLambdaオブジェクトに
適用します。
すると、AWS Lambdaを使用するために必要なパラメーターが表示されます。
重要なのは、この3つです。
・Identity Pool Id
・Cognito Identity Region
・Lambda Region

はじめに挙げた「AWS Mobile SDK for Unityを使ってサーバーレスなアプリを開発する」の
ページにもありますが、AWS Mobile SDK for Unity を使用するためには"Cognito"という
サービスを利用する必要があります。
Amazon Cognito:
https://aws.amazon.com/jp/cognito/
このユーザーのサインイン機能を使って、UnityからAWS Lambdaにアクセスするようです。
Unityの作業は一旦ここで止めて、Cognitoサービスを利用してみましょう。
AWSの管理画面のサービスから、Cognitoを選びます。
※管理画面の作業は、すべて"東京リージョン"での作業です!!

"Manage Federated Identities"を選びます。

"Identity pool name"が必須なので、ここではアプリの名前(AllZeroPuzzle)にしてみました。
ユーザー認証は使わないので、"Unauthenticated identities"の
"Enable access to unauthenticated identities"にチェックを入れておきます。
最後に"Create Pool"を押します。

ユーザー認証あり/なし時のロールを作成する画面になります。
特に何もせず"許可"を押します。

次に、Cognitoをどうやってプログラムから設定するかの説明ページが表示されるので、
Platform で Unity を選択します。
"Get AWS Credentials"のサンプルプログラムの中に記載されている
ap-northeast-1:xxxxxxxxxxxxxxxxxx
が Identity Pool ID です。
これを控えておきます。
控えておくものはこの2点です。
・Identity Pool ID
・リージョン名(Identity Pool IDの先頭"ap-northeast-1"のこと)
各リージョン名:
https://docs.aws.amazon.com/ja_jp/ElasticMapReduce/latest/DeveloperGuide/emr-plan-region.html

それでは、Unityに戻って、以下の3つを埋めてみましょう。
・Identity Pool Id
・Cognito Identity Region
・Lambda Region

再生ボタンを押してGameウィンドウの"List Functions"ボタンを押してみましょう。
すると、エラーが出ます。
これは、まだCognitoで作ったロールをLambdaに関連付けていないからです。

再び、AWSの管理画面に戻ります。
サービス > AWS Lambda > Functions
を見ると、前回作った"helloWorld"があるので選択します。

Configuration の"Existing role"が前回のまま(lambda_basic_execution)になっています。
この lambda_basic_execution を先ほどCognitoで作ったロールに置き換えたいのですが
選択肢にありません。
では、どうすればよいのでしょうか。

管理画面のサービス > セキュリティ&アイデンティィ > IAM を選びます。

左メニューの"ロール"を選ぶと、前回作ったロール(lambda_basic_execution)と
今回Cognitoで作ったロール(2つ)があります。
認証なし(Cognito_AllZeroPuzzleUnauth_Role)のロールを選びます。

アクセス許可 > インラインポリシー > ロールポリシーの作成 を押します。

"Policy Generator"の"選択"を押します。

アクセス許可の編集画面になりますので、以下を設定します。
・AWSサービス = AWS Lambda
・アクション = InvokeFunction、ListFunctions ※Unityで使っている関数
・Amazonリソースネーム(ARN) = *(アスタリスク)
設定が終わったら"ステートメントを追加"を押します。


画面下にアクセス許可が表示されると"次のステップ"ボタンが有効になりますので、
押して次に進みます。

ポリシーの確認画面です。
特に何もせずに"ポリシーの適用"を押します。

画面が戻ると、インラインポリシーに先ほど作成したポリシーが追加されました。

次に、前回作った lambda_basic_execution のロールを選びます。

信頼関係を押すと、信頼されたエンティティとしてLambdaがあることが確認できます。
信頼関係の編集を押します。

表示されるポリシードキュメントをコピーしておきます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
ロール画面に戻り、認証しない方(Cognito_AllZeroPuzzleUnauth_Role)を選びます。
信頼関係の画面を見ると、信頼されたエンティティには
cognito-identity.amazonaws.com
だけが記載されています。
ここに、先ほどの"lambda_basic_executionと同じ信頼されたエンティティ"を追加します。
つまり、
ID プロバイダー lambda.amazonaws.com
を追加します。
ここでも、信頼関係の編集を押します。
先ほどの信頼関係の"Statement"の内容を、",(カンマ)"で区切ってから追記します。

すると、信頼されたエンティティに"ID プロバイダー lambda.amazonaws.com"が追加されました。

Lambdaの画面に戻ります。
ExistingRoleに、先ほど選択肢にはなかった"Cognito_AllZeroPuzzleUnauth_Role"が追加されているので
選択します。

画面上の"Save and test"を押してみましょう。
特に問題なく実行されるはずです。
次に、Unityに移り、再生を押してから"List Functions"を押すと、
Lambdaで作った関数 helloWorld が表示されます。

続いて、"Invoke"を押すと、"Function Name:"の入力欄に記載されている関数を呼びます。
記入欄には"helloWorld"とあるので、Lambda上のhelloWorldが呼ばれます。

これで、PCのUnityからAWS Lambdaに接続し、関数を実行することができました。
最後に、iPhoneで動作するようにします。
サンプルに添付してあった
Assets > Examples > readme.md
を開くと、IL2CPP で実行するには
Resources ディレクトリを作り、その中に link.xml を追加する必要があるようです。

link.xmlに記述する内容は
https://github.com/aws/aws-sdk-net/blob/master/Unity.README.md#unity-sdk-fundamentals
に記載されていますが、こちらにも転機しておきます。
※上記には、コメントアウトしていない部分があったため
<linker>
<assembly fullname="UnityEngine">
<type fullname="UnityEngine.Experimental.Networking.UnityWebRequest" preserve="all" />
<type fullname="UnityEngine.Experimental.Networking.UploadHandlerRaw" preserve="all" />
<type fullname="UnityEngine.Experimental.Networking.UploadHandler" preserve="all" />
<type fullname="UnityEngine.Experimental.Networking.DownloadHandler" preserve="all" />
<type fullname="UnityEngine.Experimental.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"/>
</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.SecurityToken" preserve="all"/>
</linker>
readmeでは
<assembly fullname="AWSSDK.Lambda" preserve="all"/>
を追加するように記載がありましたが、追記しなくても動作しました。
Unityでビルドするときは、
"Setting for iOS"で"Bundle Identifier"を自分用に変更しておきましょう。
ここでは、be-styleのアプリということで
com.jpn.bestyle.lambdatest
としておきました。

ビルドする前は、Examples/LambdaExample のシーンが登録されていることを確認しましょう。

UnityでビルドしてできたXcodeのプロジェクトファイルを開きます。
特に何もせずに実行します。
アプリが起動して、"List Functions"と"Invoke"が動作すれば成功です!
iPhoneでの実行時にハマった点がありました。
Credentials is expired、つまりCredentialsが有効期限切れになっているというのです。
事象としては、iPhoneの時計が日本時間なのに、サーバーの時間がアメリカ時間になっていて
その時差によって有効期限切れでAWS Lambdaが使えないというものでした。
解決方法は、iPhoneの時間を"自動設定"にすることでした。
このときにiPhoneの"位置情報"を有効にすることにポイントがありました。
そうしたら、接続先のサーバー(東京リージョン)と端末の時計が合い、Lambdaにアクセスできました。
今回が初めてなので、途中で不要な処理が入っているかもしれません。
それはこれから経験を積んで精査していきたいと思います。
次は、AWS Lambda から DynamoDB にアクセスしてみます。
[Web] AWS Lambda から DynamoDB にアクセスしてアイテムを更新してみた