XamarinでAmazon Pinpointを使う（iOS編）

基本的な知識はあることが前提です。

オフィシャルページを見ながらやって詰まったところを中心に書いています。


# Amazon Pinpointのセットアップ

Mobile HubからセットアップしてたのですがNotificationで詰まりました。

Mobile HubにNotification用の証明書の設定があるのですが、そこの設定だけではPinpointからNotificationが投げれなかったです。

PinpointのSettings画面のChannelsと言う項目からも証明書の設定をする必要があります。
そうしないと、Notificationを投げても届かず、エラーも教えてくれず途方に暮れます。

<img width="981" alt="スクリーンショット 2018-01-31 10.10.23.png" src="https://qiita-image-store.s3.amazonaws.com/0/201603/d85f4b0c-946c-783c-f629-3407529b4483.png">


# SDKの取り込み

PinpointのXamarin SDKは存在しません（２０１８年１月時点）。

必要な機能だけをラップしたiOSライブラリを準備しました。

## Cocoa Touch Static Library の準備

オフィシャルサイトからAWSのSDKをダウンロードしてきて、それをラップするライブラリプロジェクトを作ります。

```objective-c
#import "AWSSDK.h"

@implementation AWSSDK

- (void)Initialize:(NSDictionary *)launchOptions
{
    AWSCognitoCredentialsProvider *cognitoCredentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionAPNortheast1 identityPoolId:@"IdentityPoolIdを設定"];
    AWSServiceConfiguration *pinpointConfig = [[AWSServiceConfiguration
                                                alloc] initWithRegion:AWSRegionUSEast1
                                               credentialsProvider:cognitoCredentialsProvider];
    [[AWSServiceManager defaultServiceManager]
     setDefaultServiceConfiguration:pinpointConfig];
    AWSPinpointConfiguration *configuration = [[AWSPinpointConfiguration
                                                alloc] initWithAppId:@"AppIdを設定" launchOptions:launchOptions];
    _pinpoint = [AWSPinpoint pinpointWithConfiguration:configuration];
}

- (void)Regist:(NSData *)deviceToken
{
    [_pinpoint.notificationManager interceptDidRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}

- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response 
{
    [_pinpoint.notificationManager interceptDidReceiveRemoteNotification:response.notification.request.content.userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result) {}];
}
@end
```

必要な機能だけを呼び出してます。
”XXXを設定”と言う箇所は各人の環境に合わせて変更します。
今回は呼び元から設定する方が良いのでしょうが、このアプリ専用でしか考えてなかったので埋め込んでます。


<img width="223" alt="スクリーンショット 2018-01-31 10.16.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/201603/c75d71a5-96b2-22bb-77a6-c83003d771c5.png">

Frameworkも必要なものだけ設定してます。

##　Xamarinにバインディングプロジェクトの追加

<img width="391" alt="スクリーンショット 2018-01-31 10.23.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/201603/daea5c4e-7693-3e88-4c3a-9a506702776e.png">

プロジェクトの追加からバインディングライブラリを追加し、追加したプロジェクトに、先ほどのXcode側のプロジェクトから出力した .a のファイルをドラッグ＆ドロップします。

<img width="190" alt="スクリーンショット 2018-01-31 10.22.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/201603/c0811bdf-252e-5ba9-a641-a125260de125.png">

そうすると、 .a ファイルが取り込まれ、展開ボタンを押すと　.linkwith.cs と言う拡張子のファイルが見えます。

<img width="197" alt="スクリーンショット 2018-01-31 10.24.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/201603/a5914c5c-a7f2-0247-283d-a99ab22a02ce.png">

.linkwith.csのファイルを編集します。

```C#
using ObjCRuntime;

[assembly: LinkWith(
    "libAWSSDK.a",
    LinkTarget.Arm64,
    SmartLink = true,
    ForceLoad = true,
    Frameworks = "CoreFoundation UserNotifications Foundation SystemConfiguration AWSCore AWSPinpoint",
    LinkerFlags = "-lz -lsqlite3",
    IsCxx = true
)]
```

このように内容を修正しました。
自分の場合は、めんどくさいので Arm64 だけをターゲットにしてます。
また、AWS SDKが依存しているフレームワークも指定してます。（１個１個本当に必要かどうかは検証してません。不要なものもあるかもしれません。）
オフシャルページに SQLite 使ってると書いてたのでリンクの設定も書いて見ました。

注意： ここまでの手順は実機むけです。シミュレーターの場合はシミュレーター向けのライブラリを作って統合する必要があるはずです。

```C#
using System;

using Foundation;
using UserNotifications;

namespace aws.ios
{
    [BaseType(typeof(NSObject))]
    interface AWSSDK
    {
        [Export("Initialize:")]
        void Initialize([NullAllowed] NSDictionary launchOptions);
        [Export("Regist:")]
        void Regist([NullAllowed] NSData token);
        [Export("didReceiveNotificationResponse:")]
        void didReceiveNotificationResponse([NullAllowed] UNNotificationResponse response);
    }
}
```

ApiDefinition.csにも呼び出すメソッドのシグニチャを書きます。

## iOSプロジェクトから呼び出す

```C#
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();

            LoadApplication(new App());

#if !DEBUG
            _aws = new AWSSDK();
            _aws.Initialize(options);

            var settings = UIUserNotificationSettings.GetSettingsForTypes(UIUserNotificationType.Alert | UIUserNotificationType.Badge | UIUserNotificationType.Sound, null);
            app.RegisterUserNotificationSettings(settings);
            app.RegisterForRemoteNotifications();
            UNUserNotificationCenter.Current.Delegate = new UserNotificationCenterDelegate();
#endif
            return base.FinishedLaunching(app, options);
        }
```

こんな感じで呼び出すところを書きます。
自分の場合はDEBUGモードの時はデバイス登録したくなかったので処理をオフにしてます。
DeviceTokenの登録やNotification受信時の処理も他に書く必要があります。


## Pinpointコンソールで結果確認

Segmentを作って見て、デバイスが登録されているか確認