AWS Mobile Blog

Sync store access and simplified credentials provider

by Stefano Buliani | on | Permalink | Comments |  Share

Today we released a new feature for Amazon Cognito that gives developers, utilizing their credentials, full API access to the sync store to read and write user profile data. This feature helps you access and modify user profiles from your backend infrastructure. For example, game developers can use this feature to distribute prizes to players who achieved a certain top score.

New pages in the Amazon Cognito console also allow you to perform the same operations: You can list identities, look at their profile data, and edit it directly from the web interface. We listened to your feedback and have now added the ability to access the starter code, which shows you how to initialize the credentials provider and run your first sync operation, directly through the identity pool dashboard page. If you haven’t yet, the page will ask you to save the association between your identity pool and the IAM roles in your account. You will then be able to open the starter code page at any point. Because the IAM roles are now associated with the identity pool, you don’t need to pass them to the credentials provider constructor anymore. Instead, you can initialize the object only with an identity pool ID.

Android

CognitoCachingCredentialsProvider cognitoProvider = new CognitoCachingCredentialsProvider(     
    myActivity.getContext(), // get the context for the current activity     
    "IDENTITY_POOL_ID", // Identity pool ID
    Regions.US_EAST_1 // Your AWS Region
);

iOS

AWSCognitoCredentialsProvider *credentialsProvider = [AWSCognitoCredentialsProvider     
    credentialsWithRegionType: AWSRegionUSEast1
    identityPoolId:@"IDENTITY_POOL_ID"];

Distributing prizes

For our example, we will take you through how to set a prize, in the form of a flag, in a player’s profile directly in the sync store. This example assumes that you have an API in your backend that the app calls whenever the player completes a level. The sample method is called setPrizes; and expects a Cognito identity ID and the latest score achieved by the player.

Before we define the method itself, we have to set a few constants required for our application to work such as the AWS access credentials, the identity pool and dataset information, and the values we’ll be setting in the player profile. You can retrieve an AWS access key and secret key from the IAM console.

// the score to beat in order to be awarded a prize
private static final int MAX_SCORE = 1000;
// how much health to add each time the player beats the score
private static final int ADDITIONAL_HEALTH_POINTS = 100;

// AWS credentials and identity pool data
private static final String AWS_ACCESS_KEY = "xxx";
private static final String AWS_SECRET_KEY = "xxx+T";
private static final String AWS_IDENTITY_POOL_ID = "us-east-1:xx";

// Cognito dataset and key information
private static final String PRIZE_DATASET_NAME = "prizes";
private static final String PRIZE_RECORD_KEY = "additional_health_points";

We can now define our setPrizes method. This receives two input parameters: first, the Cognito identity ID, and second, the last score achieved by the user. The method first checks if the score is high enough to warrant a prize, and then proceeds to access the sync store and write the required information.

We initialize an AmazonCognitoSyncClient using a set of BasicAWSCredentials that comprise the access key and secret key generated through the IAM console. The first step in the process is to list the records in the player’s dataset using the ListRecordsRequest object. This API call returns a list of Record objects in the dataset as well as a sync session token. We need to save this token and reuse it later on in the function when updating the data.

The method then prepares a new RecordPatch object based on the prize data. If we already have a prize set, then we increment it instead of overwriting it. Once the patch is ready, we create an UpdateRecordsRequest object and use it to send the changes to the server.

The next time the player connects and synchronizes their profile, they will receive the updated data, and your application will react accordingly awarding them the prize. If you have configured your identity pool to support push synchronization, Cognito will send a notification to the device, and the new data you have set in the user profile will be synchronized right away.

private static void setPrizes(String identityId, int lastScore) {
	// if the last score is not greater than the defined max
	// then we return without modifying the profile
	if (lastScore < MAX_SCORE)
		return;
	
	String syncSessionToken = "";
		
	BasicAWSCredentials awsCredentials = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
	AmazonCognitoSyncClient syncClient = new AmazonCognitoSyncClient(awsCredentials);
		
	// first we make a list records to initiate a sync operation.
	ListRecordsRequest recordsRequest = new ListRecordsRequest();
	recordsRequest.setDatasetName(PRIZE_DATASET_NAME);
	recordsRequest.setIdentityId(identityId);
	recordsRequest.setIdentityPoolId(AWS_IDENTITY_POOL_ID);
		
	ListRecordsResult records = syncClient.listRecords(recordsRequest);
	syncSessionToken = records.getSyncSessionToken();
		
	// we can start creating the patch object for the record we want to change/insert
	RecordPatch patch = new RecordPatch();
	patch.setOp(Operation.Replace);
	patch.setKey(PRIZE_RECORD_KEY);
	patch.setValue("" + ADDITIONAL_HEALTH_POINTS); 
	patch.setSyncCount((long) 0);
		
	// now we loop over the records to find if the record already existed and set the parameters we need
	List allRecords = records.getRecords();
	for (Record curRecord : allRecords) {
		// we already had the record. add the additional health points to the current value
		if (curRecord.getKey().equals(PRIZE_RECORD_KEY)) {
			patch.setValue(
				Integer.toString(ADDITIONAL_HEALTH_POINTS + Integer.parseInt(curRecord.getValue()))
			);
			patch.setSyncCount(curRecord.getSyncCount());
		}
	}
		
	ArrayList patches = new ArrayList();
	patches.add(patch);
		
	// now we can send the update records request
	UpdateRecordsRequest updateRequest = new UpdateRecordsRequest();
	updateRequest.setDatasetName(PRIZE_DATASET_NAME);
	updateRequest.setIdentityId(identityId);
	updateRequest.setIdentityPoolId(AWS_IDENTITY_POOL_ID);
	updateRequest.setSyncSessionToken(syncSessionToken);
	updateRequest.setRecordPatches(patches);
		
	UpdateRecordsResult output = syncClient.updateRecords(updateRequest);
	System.out.println(output.toString());
}

You can interact with Amazon Cognito through the AWS Mobile SDK for iOS, Android, and Unity as well as all other AWS SDKs. When using the AWS Mobile SDK for iOS, Android, and Unity, you can take advantage of the high-level abstractions we have built on top of the raw APIs and simply utilize the synchronize() or synchronizeOnConnectivity() method instead of the list and update records. We look forward to your feedback through the Cognito forum and our Twitter account.