推送同步 - Amazon Cognito
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

推送同步

如果您是 Amazon Cognito Sync 的新用户,请使用 Amazon AppSync。像 Amazon Cognito Sync 一样,Amazon AppSync 是一种在设备之间同步应用程序数据的服务。

它允许同步用户数据,如应用程序首选项或游戏状态。它还通过允许多个用户实时同步和协作处理共享的数据,来扩展这些功能。

Amazon Cognito 会自动跟踪身份和设备之间的关联。使用推送同步功能,您可以确保在身份数据发生更改后向给定身份的每个实例发送通知。推送同步可以确保,无论特定身份的同步存储数据何时发生更改,与该身份关联的所有设备都会收到一个静音推送通知,通知它们所发生的更改。

注意

推送同步不支持 JavaScript、Unity 或 Xamarin。

您必须首先设置用于推送同步的账户,并在 Amazon Cognito 控制台中启用推送同步,然后才可使用推送同步。

创建 Amazon Simple Notification Service(Amazon SNS)应用程序

为支持的平台创建并配置 Amazon SNS 应用程序,如 SNS 开发人员指南中所述。

在 Amazon Cognito 控制台中启用推送同步

您可以通过 Amazon Cognito 控制台启用推送同步。从控制台主页

  1. 单击您需要启用推送同步的身份池的名称。此时将显示身份池的 Dashboard(控制面板)页。

  2. Dashboard(控制面板)页的右上角,单击 Manage Identity Pools(管理身份池)。此时将显示 Federated Identities(联合身份)页。

  3. 向下滚动并单击 Push synchronization(推送同步)以将其展开。

  4. Service role(服务角色)下拉菜单中,选择授予 Cognito 发送 SNS 通知的权限的 IAM 角色。在 Amazon IAM 控制台中,单击 Create role (创建角色) 以创建或修改与您身份池关联的角色。

  5. 选择一个平台应用程序,然后单击 Save Changes(保存更改)。

  6. 为应用程序授予 SNS 访问权限

在 Amazon Identity and Access Management 控制台中,将您的 IAM 角色配置为具有完整 Amazon SNS 访问权限,或创建一个具有完整 Amazon SNS 访问权限的新角色。以下示例角色信任策略授予 Amazon Cognito Sync 有限代入 IAM 角色的能力。Amazon Cognito Sync 只能在代表 aws:SourceArn 条件中的身份池和 aws:SourceAccount 条件中的账户时才能代入该角色。

{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "cognito-sync.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "AWS:SourceAccount": "123456789012" }, "ArnLike": { "AWS:SourceArn": "arn:aws:cognito-identity:us-east-1:123456789012:identitypool/us-east-1:177a950c-2c08-43f0-9983-28727EXAMPLE" } } } ] }

要了解有关 IAM 角色的更多信息,请参阅角色(委托和联合)

在您的应用程序中使用推送同步:Android

您的应用程序需要导入 Google Play 服务。您可以通过 Android SDK Manager 下载最新版本的 Google Play 开发工具包。按照 Android 有关 Android 实施的文档注册您的应用程序并接收来自 GCM 的注册 ID。收到注册 ID 之后,您需要向 Amazon Cognito 注册设备,如以下代码段所示:

String registrationId = "MY_GCM_REGISTRATION_ID"; try { client.registerDevice("GCM", registrationId); } catch (RegistrationFailedException rfe) { Log.e(TAG, "Failed to register device for silent sync", rfe); } catch (AmazonClientException ace) { Log.e(TAG, "An unknown error caused registration for silent sync to fail", ace); }

现在,您可以订阅设备以接收来自特定数据集的更新:

Dataset trackedDataset = client.openOrCreateDataset("myDataset"); if (client.isDeviceRegistered()) { try { trackedDataset.subscribe(); } catch (SubscribeFailedException sfe) { Log.e(TAG, "Failed to subscribe to datasets", sfe); } catch (AmazonClientException ace) { Log.e(TAG, "An unknown error caused the subscription to fail", ace); } }

要停止接收来自数据集的推送通知,只需调用 unsubscribe 方法即可。要订阅 CognitoSyncManager 对象中的所有数据集(或特定子集),请使用 subscribeAll()

if (client.isDeviceRegistered()) { try { client.subscribeAll(); } catch (SubscribeFailedException sfe) { Log.e(TAG, "Failed to subscribe to datasets", sfe); } catch (AmazonClientException ace) { Log.e(TAG, "An unknown error caused the subscription to fail", ace); } }

实施 Android BroadcastReceiver 对象时,您可以检查已修改数据集的最新版本,并决定您的应用程序是否需要再次同步。

@Override public void onReceive(Context context, Intent intent) { PushSyncUpdate update = client.getPushSyncUpdate(intent); // The update has the source (cognito-sync here), identityId of the // user, identityPoolId in question, the non-local sync count of the // data set and the name of the dataset. All are accessible through // relevant getters. String source = update.getSource(); String identityPoolId = update.getIdentityPoolId(); String identityId = update.getIdentityId(); String datasetName = update.getDatasetName; long syncCount = update.getSyncCount; Dataset dataset = client.openOrCreateDataset(datasetName); // need to access last sync count. If sync count is less or equal to // last sync count of the dataset, no sync is required. long lastSyncCount = dataset.getLastSyncCount(); if (lastSyncCount < syncCount) { dataset.synchronize(new SyncCallback() { // ... }); } }

推送通知负载中提供以下键:

  • source:cognito-sync。这可以作为通知之间的区分因素。

  • identityPoolId:身份池 ID。这可用于验证或获取其他信息,但从接收方的角度来看,这并不是不可或缺的。

  • identityId:池中的身份 ID。

  • datasetName:已更新的数据集的名称。这可用于 openOrCreateDataset 调用。

  • syncCount:远程数据集的同步计数。您可以使用此方法来确保本地数据集已过期,并且传入同步是新的。

在您的应用程序中使用推送同步:iOS – Objective-C

要获取应用程序的设备令牌,请参阅 Apple 有关注册远程通知的文档。收到来自 APN 的作为 NSData 对象的设备令牌之后,您需要立即使用同步客户端的 registerDevice: 方法向 Amazon Cognito 注册,如下所示:

AWSCognito *syncClient = [AWSCognito defaultCognito]; [[syncClient registerDevice: devToken] continueWithBlock:^id(AWSTask *task) { if(task.error){ NSLog(@"Unable to registerDevice: %@", task.error); } else { NSLog(@"Successfully registered device with id: %@", task.result); } return nil; } ];

在调试模式下,设备将向 APN 沙盒注册;在发布模式下,设备将向 APN 注册。要接收来自特定数据集的更新,请使用 subscribe 方法:

[[[syncClient openOrCreateDataset:@"MyDataset"] subscribe] continueWithBlock:^id(AWSTask *task) { if(task.error){ NSLog(@"Unable to subscribe to dataset: %@", task.error); } else { NSLog(@"Successfully subscribed to dataset: %@", task.result); } return nil; } ];

要停止接收来自数据集的推送通知,只需调用 unsubscribe 方法即可。

[[[syncClient openOrCreateDataset:@”MyDataset”] unsubscribe] continueWithBlock:^id(AWSTask *task) { if(task.error){ NSLog(@"Unable to unsubscribe from dataset: %@", task.error); } else { NSLog(@"Successfully unsubscribed from dataset: %@", task.result); } return nil; } ];

要订阅 AWSCognito 对象中的所有数据集,请调用 subscribeAll

[[syncClient subscribeAll] continueWithBlock:^id(AWSTask *task) { if(task.error){ NSLog(@"Unable to subscribe to all datasets: %@", task.error); } else { NSLog(@"Successfully subscribed to all datasets: %@", task.result); } return nil; } ];

在调用 subscribeAll 之前,请确保在每个数据集上至少同步一次,以便数据集存在于服务器上。

要对推送通知做出反应,您需要在应用程序委托上实施 didReceiveRemoteNotification 方法:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { [[NSNotificationCenter defaultCenter] postNotificationName:@"CognitoPushNotification" object:userInfo]; }

如果您使用通知处理程序发布通知,则可以在您拥有数据集句柄的应用程序中的其他位置响应通知。如果您按照如下方式订阅通知...

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceivePushSync:) name: :@"CognitoPushNotification" object:nil];

...则可以按照如下所示处理通知:

- (void)didReceivePushSync:(NSNotification*)notification { NSDictionary * data = [(NSDictionary *)[notification 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(AWSTask *task) { if(!task.error){ NSLog(@"Successfully synced dataset"); } return nil; }]; } }

推送通知负载中提供以下键:

  • source:cognito-sync。这可以作为通知之间的区分因素。

  • identityPoolId:身份池 ID。这可用于验证或获取其他信息,但从接收方的角度来看,这并不是不可或缺的。

  • identityId:池中的身份 ID。

  • datasetName:已更新的数据集的名称。这可用于 openOrCreateDataset 调用。

  • syncCount:远程数据集的同步计数。您可以使用此方法来确保本地数据集已过期,并且传入同步是新的。

在您的应用程序中使用推送同步:iOS – Swift

要获取应用程序的设备令牌,请参阅 Apple 有关注册远程通知的文档。收到来自 APN 的作为 NSData 对象的设备令牌之后,您需要立即使用同步客户端的 registerDevice: 方法向 Amazon Cognito 注册,如下所示:

let syncClient = AWSCognito.default() syncClient.registerDevice(devToken).continueWith(block: { (task: AWSTask!) -> AnyObject! in if (task.error != nil) { print("Unable to register device: " + task.error.localizedDescription) } else { print("Successfully registered device with id: \(task.result)") } return task })

在调试模式下,设备将向 APN 沙盒注册;在发布模式下,设备将向 APN 注册。要接收来自特定数据集的更新,请使用 subscribe 方法:

syncClient.openOrCreateDataset("MyDataset").subscribe().continueWith(block: { (task: AWSTask!) -> AnyObject! in if (task.error != nil) { print("Unable to subscribe to dataset: " + task.error.localizedDescription) } else { print("Successfully subscribed to dataset: \(task.result)") } return task })

要停止接收来自数据集的推送通知,请调用 unsubscribe 方法:

syncClient.openOrCreateDataset("MyDataset").unsubscribe().continueWith(block: { (task: AWSTask!) -> AnyObject! in if (task.error != nil) { print("Unable to unsubscribe to dataset: " + task.error.localizedDescription) } else { print("Successfully unsubscribed to dataset: \(task.result)") } return task })

要订阅 AWSCognito 对象中的所有数据集,请调用 subscribeAll

syncClient.openOrCreateDataset("MyDataset").subscribeAll().continueWith(block: { (task: AWSTask!) -> AnyObject! in if (task.error != nil) { print("Unable to subscribe to all datasets: " + task.error.localizedDescription) } else { print("Successfully subscribed to all datasets: \(task.result)") } return task })

在调用 subscribeAll 之前,请确保在每个数据集上至少同步一次,以便数据集存在于服务器上。

要对推送通知做出反应,您需要在应用程序委托上实施 didReceiveRemoteNotification 方法:

func application(application: UIApplication, didReceiveRemoteNotification userInfo: [NSObject : AnyObject], fetchCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { NSNotificationCenter.defaultCenter().postNotificationName("CognitoPushNotification", object: userInfo) })

如果您使用通知处理程序发布通知,则可以在您拥有数据集句柄的应用程序中的其他位置响应通知。如果您按照如下方式订阅通知...

NSNotificationCenter.defaultCenter().addObserver(observer:self, selector:"didReceivePushSync:", name:"CognitoPushNotification", object:nil)

...则可以按照如下所示处理通知:

func didReceivePushSync(notification: NSNotification) { if let data = (notification.object as! [String: AnyObject])["data"] as? [String: AnyObject] { let identityId = data["identityId"] as! String let datasetName = data["datasetName"] as! String if self.dataset.name == datasetName && self.identityId == identityId { dataset.synchronize().continueWithBlock {(task) -> AnyObject! in if task.error == nil { print("Successfully synced dataset") } return nil } } } }

推送通知负载中提供以下键:

  • source:cognito-sync。这可以作为通知之间的区分因素。

  • identityPoolId:身份池 ID。这可用于验证或获取其他信息,但从接收方的角度来看,这并不是不可或缺的。

  • identityId:池中的身份 ID。

  • datasetName:已更新的数据集的名称。这可用于 openOrCreateDataset 调用。

  • syncCount:远程数据集的同步计数。您可以使用此方法来确保本地数据集已过期,并且传入同步是新的。