近期在項目中需要用到AWS SNS服務,因爲面向安卓平臺,當然優先考慮谷歌的GCM(Google已更新爲FCM)搭配,在開發中遇到幾點問題,做一下記錄,順便給同行們參考。
首先註冊/擁有Google賬號,在https://firebase.google.com/ 創建自己的項目,在Application欄添加自己的Android應用,根據提示一步步完成firebase的設置,生成對應的server_key即可,這裏基本不會有任何問題,谷歌的幫助文檔和截圖說明十分詳細。FCM設定完成後在Android App加入FirebaseMessagingService即可通過firebase的Cloud Messaging發送並測試FCM推送效果:
public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { Log.d("FCM", "onMessageReceived:" + remoteMessage.getFrom()); // Check if message contains a data payload. if (remoteMessage.getData().size() > 0) { Log.d("FCM", "Message data payload: " + remoteMessage.getData()); } // Check if message contains a notification payload. if (remoteMessage.getNotification() != null) { Log.d("FCM", "Message Notification Body: " + remoteMessage.getNotification().getBody()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ createNotificationChannels(getApplicationContext()); }else { sendNotification(remoteMessage.getNotification().getBody()); } } } }
測試FCM可用後,開始創建自己的SNS服務,首先登陸AWS Console,在Services下拉菜單搜索SNS,就可以找到Simple Notification Service,然後按照SNS dashboard的Common Action完成create Topic 、Create platform application、Create Subscription、pulish Message 就可以發送Notification了,而爲了綁定先前創建的FCM應用,在Create platform application時需要選擇Push notification platform爲Google Cloud Messaging(GCM),然後輸入在Firebase添加自己Android App時產生的api_key,而同時需要注意的是,若需要安卓設備能夠接收到Notification,需要在點擊application ARN,然後添加對應安卓設備的platform Endpoint,Create platform endpoint時需要輸入兩條數據,第二個user data爲用戶任意輸入內容,第一條的Device Token就是安卓設備從Google服務返回的token,取得Token需要在Android App加入FirebaseInstanceIdService,而爲了方便Endpoint的生成,我們可以將Token自動添加到Endpoint中,並創建與Topic對應的Subscription,使安卓用戶能夠自動實現接收Topic所發出的通知,代碼如下:
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService { public MyFirebaseInstanceIDService() { } @Override public void onTokenRefresh() { //For registration of token String refreshedToken = FirebaseInstanceId.getInstance().getToken(); //To displaying token on logcat Log.d("TOKEN", refreshedToken); //upload token to SNS endpoint sendTokentoSNS(refreshedToken); } private void sendTokentoSNS(String refreshedToken){ String access_id = "********"; String secret_key ="********"; String appArn = "arn:aws:sns:us-west-2:********:app/GCM/xxx_client"; String topicArn = "arn:aws:sns:us-west-2:********:ota-notify"; AWSCredentials credentials = new BasicAWSCredentials(access_id,secret_key); AWSCredentialsProvider provider = new StaticCredentialsProvider(credentials); AmazonSNSClient snsClient = new AmazonSNSClient(provider); snsClient.setRegion(Region.getRegion(Regions.US_WEST_2)); CreatePlatformEndpointRequest createPlatformEndpointRequest = new CreatePlatformEndpointRequest() .withPlatformApplicationArn() .withToken(refreshedToken) .withCustomUserData(Build.DEVICE); CreatePlatformEndpointResult result = snsClient.createPlatformEndpoint(createPlatformEndpointRequest); SubscribeRequest subscribeRequest = new SubscribeRequest().withTopicArn(topicArn) .withProtocol("application") .withEndpoint(result.getEndpointArn()); snsClient.subscribe(subscribeRequest); Log.i("TOKEN","add token to SNS "); } }
以上基本實現了SNS通知接收和發送的框架,不過實際發送GCM通知時,還有一個問題需要解決,就是GCM在SNS裏Message的格式,怎樣發出對應的data和notification分類的消息,經過測試後,我使用了Gson來轉換SNS需要的格式,發送出一條包含data和notification的通知,代碼如下:
String topicArn = "arn:aws:sns:us-west-2:********:ota-notify";
//publish to an SNS topic
String update = “a new update!”;
Gson gson = new Gson();
GCM gcm = new GCM();
data data = new data();
notification notification = new notification();
SNSMessage snsMessage = new SNSMessage();
notification.setTitle("AWS S3");
notification.setSound("default");
notification.setBody("you have "+update);
data.setMessage("image update");
gcm.setNotification(notification);
gcm.setData(data);
snsMessage.setGcm(gson.toJson(gcm,GCM.class));
snsMessage.setDefault("default message");
String jsonstr = gson.toJson(snsMessage,SNSMessage.class);
PublishRequest publishRequest = new PublishRequest()
.withTopicArn(topicArn)
.withSubject("update")
.withMessageStructure("json")
.withMessage(jsonstr);
PublishResult publishResult = snsClient.publish(publishRequest);
//print MessageId of message published to SNS topic
System.out.println("MessageId - " + publishResult.getMessageId());