I have been trying to use AWS SDKs for Push Notifications. But I am getting errors. Tried to find a solution, but can't find much support for this.
iOS & Web push notifications are working fine
What all is already setup & done:
Android side:
AWS SDK dependencies:
implementation 'com.amazonaws:aws-android-sdk-core:2.16.8'
implementation 'com.amazonaws:aws-android-sdk-cognito:2.6.23'
implementation 'com.amazonaws:aws-android-sdk-s3:2.15.1'
implementation 'com.amazonaws:aws-android-sdk-ddb:2.2.0'
implementation ('com.amazonaws:aws-android-sdk-mobile-client:2.16.8') { transitive = true; }
minSdkVersion 21
targetSdkVersion 29
Inside onCreate:
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"My Pool Id here", // Identity pool ID
Regions.US_EAST_1 // Region
);
CognitoSyncManager client = new CognitoSyncManager(
LoginActivateActivity.this,
Regions.US_EAST_1,
credentialsProvider);
String registrationId = "MY_FCM_DEVICE_TOKEN"; **Instead of GCM ID, I am passing my unique FCM device token here. I searched, & it seems that wherever GCM is required, it is being replaced by FCM.**
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("My Topic here");
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);
}
}
Error I am getting on client.registerDevice("GCM", registrationId);
Caused by: com.amazonaws.services.cognitosync.model.InvalidConfigurationException: Identity pool isn't set up for SNS (Service: AmazonCognitoSync; Status Code: 400; Error Code: InvalidConfigurationException; Request ID: a858aaa2-**************************)
Note:
I tried using Amplify libraries, but even that didn't work. Also, at iOS & Web end they are using AWS SDK. So I am also bound to use the same. This is not even a device specific error.
All I need to do is setup my project to get push notifications. But I am stuck at the initial step. Not able to create an endpoint for Android device.
I actually found the solution to the issue, thanks to a friend who shared this link:
https://aws.amazon.com/premiumsupport/knowledge-center/create-android-push-messaging-sns/
This Youtube video also helped a lot:
https://www.youtube.com/watch?v=9QSO3ghSUNk&list=WL&index=3
Edited code
private void registerWithSNS() {
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"Your Identity Pool ID",
Regions.US_EAST_1 // Region
);
client = new AmazonSNSClient(credentialsProvider);
String endpointArn = retrieveEndpointArn();
String token = "Your FCM Registration ID generated for the device";
boolean updateNeeded = false;
boolean createNeeded = (null == endpointArn || "".equalsIgnoreCase(endpointArn));
if (createNeeded) {
// No platform endpoint ARN is stored; need to call createEndpoint.
endpointArn = createEndpoint(token);
createNeeded = false;
}
System.out.println("Retrieving platform endpoint data...");
// Look up the platform endpoint and make sure the data in it is current, even if
// it was just created.
try {
GetEndpointAttributesRequest geaReq =
new GetEndpointAttributesRequest()
.withEndpointArn(endpointArn);
GetEndpointAttributesResult geaRes =
client.getEndpointAttributes(geaReq);
updateNeeded = !geaRes.getAttributes().get("Token").equals(token)
|| !geaRes.getAttributes().get("Enabled").equalsIgnoreCase("true");
} catch (NotFoundException nfe) {
// We had a stored ARN, but the platform endpoint associated with it
// disappeared. Recreate it.
createNeeded = true;
} catch (AmazonClientException e) {
createNeeded = true;
}
if (createNeeded) {
createEndpoint(token);
}
System.out.println("updateNeeded = " + updateNeeded);
if (updateNeeded) {
// The platform endpoint is out of sync with the current data;
// update the token and enable it.
System.out.println("Updating platform endpoint " + endpointArn);
Map attribs = new HashMap();
attribs.put("Token", token);
attribs.put("Enabled", "true");
SetEndpointAttributesRequest saeReq =
new SetEndpointAttributesRequest()
.withEndpointArn(endpointArn)
.withAttributes(attribs);
client.setEndpointAttributes(saeReq);
}
}
/**
* @return never null
* */
private String createEndpoint(String token) {
String endpointArn = null;
try {
System.out.println("Creating platform endpoint with token " + token);
CreatePlatformEndpointRequest cpeReq =
new CreatePlatformEndpointRequest()
.withPlatformApplicationArn("Your Platform ARN. This you get from AWS Console. Unique for all devices for a platform.")
.withToken(token);
CreatePlatformEndpointResult cpeRes = client
.createPlatformEndpoint(cpeReq);
endpointArn = cpeRes.getEndpointArn();
} catch (InvalidParameterException ipe) {
String message = ipe.getErrorMessage();
System.out.println("Exception message: " + message);
Pattern p = Pattern
.compile(".*Endpoint (arn:aws:sns[^ ]+) already exists " +
"with the same [Tt]oken.*");
Matcher m = p.matcher(message);
if (m.matches()) {
// The platform endpoint already exists for this token, but with
// additional custom data that
// createEndpoint doesn't want to overwrite. Just use the
// existing platform endpoint.
endpointArn = m.group(1);
} else {
// Rethrow the exception, the input is actually bad.
throw ipe;
}
}
storeEndpointArn(endpointArn);
return endpointArn;
}
/**
* @return the ARN the app was registered under previously, or null if no
* platform endpoint ARN is stored.
*/
private String retrieveEndpointArn() {
// Retrieve the platform endpoint ARN from permanent storage,
// or return null if null is stored.
return endpointArn;
}
/**
* Stores the platform endpoint ARN in permanent storage for lookup next time.
* */
private void storeEndpointArn(String endpointArn) {
// Write the platform endpoint ARN to permanent storage.
UserSession.getSession(LoginActivateActivity.this).setARN(endpointArn); //Your platform endpoint ARN. This is unique for each device, but changes when
}
Once an endpoint is created for the device, you need to store the endpointArn & FCM registration ID to your DB on server-side. Rest of the code will be your FCM implementation code for receiving notifications.
Hope this helps someone