View a markdown version of this page

实施推送同步 - Amazon Cognito

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

实施推送同步

注意

如果您是 Amazon Cognito Sync 的新用户,请使用 AWS AppSync。与 Amazon Cognito Sync 一样, AWS AppSync 它是一项用于跨设备同步应用程序数据的服务。

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

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

注意

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

您必须首先设置用于推送同步的账户,并在 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 角色。在 AWS IAM 控制台中,单击 Create role (创建角色) 以创建或修改与您身份池关联的角色。

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

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

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

JSON
{ "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:已更新的数据集的名称。这是为了公开OrCreateDataset 征集而提供的。

  • 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:远程数据集的同步计数。您可以使用此方法来确保本地数据集已过期,并且传入同步是新的。