Amazon Cognito の新機能「Push synchronization」ほか

2014.11.07

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Amazon Cognito の新機能

本日、Amazon Cognito (以下 Cognito) に大きく3つのアップデートがありました!

  • Push synchronization
  • JavaScript sync SDK
  • EU West 1 region のサポート

ということで、この3つのアップデートを順番にご紹介したいと思います。

Push synchronization

Cognito Sync は複数端末でのデータ同期を主眼に置いたサービスですが、クラウドストアの変更を Push 通知で受け取ることができるようになりました。これまではクライアント側から任意のタイミングでデータ同期を実行する必要がありましたが、Push synchronization を使うとデータが変更されたタイミングでプッシュ通知を受けることができるため、非常にシームレスなデータ同期が実現できます。

なお Push synchronization は Amazon SNS を利用しています。いよいよ AWS のモバイルサービスが連係してきましたね!

事前準備

  1. Cognito Identity Pool を用意する (詳しくはこちら)
  2. SNS Console で新しい SNS アプリを作成する (詳しくはこちら)
  3. SNS アプリ作成時にで任意のプラットフォームを設定する
  4. Cognito console の Edit Identity Pool で作成した SNS アプリを設定する

ちなみに Edit Identity Pool で SNS アプリを設定する画面は以下のようになります。

sns

実装 (iOS)

続きまして実装です。今回は iOS で試してみたいと思います。なお、2014年11月07日時点での AWS iOS SDK の最新バージョンは 2.0.12、AWS Cognito Sync SDK の最新バージョンは 1.0.6 ですので、既存のプロジェクトに導入したい場合はアップデートしてから実装してください。

デバイストークンの登録

プッシュ通知を使うので、もちろんプラットフォーム毎にデバイストークンを取得する必要があります。通常の Remote Notification の要求処理を送り、受け取ったデバイストークンを AWSCognito インスタンスの registerDevice メソッドで登録します。

AppDelegate.m

#import <AWSiOSSDKv2/AWSCore.h>
#import <AWSCognitoSync/Cognito.h>

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Remote Notification の認証
    UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert;
    UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
    [application registerUserNotificationSettings:settings];
}

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // Cognito credentials provider の作成
    AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider
        credentialsWithRegionType:AWSRegionUSEast1
	                accountId:@"1234567890",       
	           identityPoolId:@"us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX",      
	            unauthRoleArn:@"arn:aws:iam::XXXXXXXXXX:role/YourRoleName",   
	              authRoleArn:@"arn:aws:iam::XXXXXXXXXX:role/YourRoleName"
    ];
    
    // Cognito sync client の初期化
    AWSCognito *syncClient = [AWSCognito defaultCognito];

    // デバイストークンの登録
    [[syncClient registerDevice: deviceToken] continueWithBlock:^id(BFTask *task) {
      if (task.error) {
          NSLog(@"デバイス登録失敗 : %@", task.error);
      } else {
          NSLog(@"デバイス登録成功 : %@", task.result);
      }
      return nil;
    }];
}

データの更新を Subscribe する

次に、Dataset の変更を Subscribe するようにします。Dataset インスタンスを取得後、subscribe メソッドをコールすることで Subscribe を開始します。全ての Dataset を Subscribe したい場合は AWSCognito インスタンスの subscribeAll メソッドを呼ぶようにしましょう。

// 特定の Dataset の Subscribe
[[[syncClient openOrCreateDataset:@"MyDataset"] subscribe] continueWithBlock:^id(BFTask *task) {
    if (task.error) {
        NSLog(@"Subscribe失敗 : %@", task.error);
    } else {
        NSLog(@"Subscribe成功 : %@", task.result);        
    }
    return nil;
}];
 
// 全ての Dataset の Subscribe
[[syncClient subscribeAll] continueWithBlock:^id(BFTask *task) {
    if (task.error) {
        NSLog(@"Subscribe失敗 : %@", task.error);
    } else {
        NSLog(@"Subscribe成功 : %@", task.result);        
    }
    return nil;
}];

通知の受信

ここまでできたら、あとはクラウドストア側の Dataset が更新されたタイミングで didReceiveRemoteNotification が呼び出されます。そのタイミングで対象の Dataset を同期すれば完了です。

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSDictionary *data = [(NSDictionary *)[userInfo object] objectForKey:@"data"];
    NSString *identityId = [data objectForKey:@"identityId"];
    NSString *datasetName = [data objectForKey:@"datasetName"];
    if ([self.dataset.name isEqualToString:datasetName] && [self.identityId isEqualToString:identityId]){
        [[self.dataset synchronize] continueWithBlock:^id(BFTask *task) {
            if (task.error) {
                NSLog(@"Dataset 同期失敗 : %@", task.error);
            } else {
                NSLog(@"Dataset 同期成功 : %@", task.result);
            }
            return nil;
        }];
    }
}

Android の実装コードのサンプルはこちらをご参照ください。

JavaScript sync SDK

Cognito Sync が JavaScript で利用できるようになりました。localStorage を利用してローカルキャッシュを作成し、ユーザーデータを同期してくれます。

Cognito Sync を利用するには、まずこちらから AWS SDK と JavaScript sync SDK をダウンロードし、次のように aws-sdk-2.0.19.min.jsamazon-cognito.js をインポートします。

<script src="js/aws-sdk-2.0.19.min.js" type="text/javascript"></script>
<script src="js/amazon-cognito.js" type="text/javascript"></script>

あとは iOS や Android の場合と同様に、Cognito Identity から Credential を取得し、Dataset に書き込みます。synchronize メソッドを呼ぶとローカルの変更がクラウドストアにプッシュされます。

// Sync Client
var cognitoSyncClient = null;
 
// AWS SDK と Cognito Credentials provider の初期設定
AWS.config.region = 'us-east-1';
var cognitoParams = {
    AccountId: 'AWS_ACCOUNT_ID',
    IdentityPoolId: 'YOUR_IDENITY_POOL_ID',
    RoleArn: 'arn:aws:iam::123123123:UNAUTHENTICATED_ROLE_ARN'
};
 
// AWS credentials の取得
AWS.config.credentials = new AWS.CognitoIdentityCredentials(cognitoParams);
AWS.config.credentials.get(function() {
    // CognitoSyncManager の初期化
    cognitoSyncClient = new CognitoSyncManager();
});

// Dataset を開く
cognitoSyncClient.openOrCreateDataset("MyDataset", function(err, dataset) {
    
    // Key から値を取得
    dataset.get("MyKey", function(err, value) {
    	// 取得した値を表示するなど
    	console.log(value);
    });
 
    // Key/Value 形式でセット(オブジェクトの場合は JSON.stringify で文字列化してからセットすること)
    dataset.put("MyKey", "HogeHoge", function(err, record) {
        
        //セット後にデータ同期
        if ( !err ) {
            dataset.synchronize({
                onSuccess: function(dataset, newRecords) {
                    // 同期成功
                    console.log("data saved to the cloud and newRecords received");
                },
                onFailure: function(err) {
                    // 何らかのエラーが発生
                    console.log("Error while synchronizing data to the cloud: " + err);
                },
                onConflict: function(dataset, conflicts, callback) {
                    // コンフリクト発生
                    var resolved = [];
                    for (var i=0; i < conflicts.length; i++) {
                        // 以下のいずれかを実行する
                        
                        // クラウドストア側を残す場合
                        resolved.push(conflicts[i].resolveWithRemoteRecord());
                        // ローカルストア側を残す場合
                        resolved.push(conflicts[i].resolveWithLocalRecord());
                        // 何らかのカスタムロジックを実行する場合
                        var newValue = conflicts[i].getRemoteRecord().getValue() + conflicts[i].getLocalRecord().getValue();
                        
                        // コンフリクト解消後のデータをセット
                        resolved.push(conflicts[i].resovleWithValue(newValue);
                    }
                    // コンフリクトの解消
                    dataset.resolve(resolved, function(err) {
                        if ( !err ) 
                            callback(true);
                    });
                },
 
                onDatasetDeleted: function(dataset, datasetName, callback) {
                    // 削除済み
                    // true を返すとローカル側も削除
                    return callback(true);
                },
 
                onDatasetMerged: function(dataset, datasetNames, callback) {
                    // マージ済み
                    // false を返すとマージ
                    return callback(false);
 
                }
            });
        }
    });
}

現在は Developer Preview として公開されています。フィードバックは GitHub Issue で受け付けていますので、要望などある場合はこちらに送りましょう。

EU West 1 リージョンのサポート

これまで Cognito は US East 1 リージョン (バージニア北部リージョン) のみでしか利用できませんでしたが、EU West 1 リージョン (アイルランドリージョン) が新たにサポートされました。

cognito01

Identity Pool はリージョン別に作成されるので、その Identity Pool のユーザーデータは指定したリージョンのみに保存されます。

まとめ

ということで、今回は Cognito Sync を中心としたアップデートでした。今後の Cognito さんにもご期待ください!