Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―サーバー(Amazon SNS:プッシュ通知を配信:HMS Part 2)
Amazon SNSのトピックに送られたプッシュ配信内容をプッシュサーバーに転送するLambdaのサンプル
index.js
const Util = require("./util.js");
const PushUtil = require("./pushUtil.js");
exports.handler = function (event, context, callback) {
const util = new Util();
const pushUtil = new PushUtil();
let pushData = null;
try {
// プッシュデータを取得
const dataString = util.getData(event);
// ログ出力
console.info("data = " + dataString);
// プッシュデータのJSONオブジェクトを生成
pushData = JSON.parse(dataString);
} catch (exception) {
util.returnErrorResponse(callback, 400, exception);
}
// プッシュデータの有効性を検証
if (!pushData) {
// プッシュデータのJSONオブジェクトが作れない
util.returnErrorResponse(callback, 400, "No data");
} else if (!pushData.hasOwnProperty("title")) {
// タイトルがない
util.returnErrorResponse(callback, 400, "No title");
} else if (!pushData.hasOwnProperty("body")) {
// 本文がない
util.returnErrorResponse(callback, 400, "No body");
} else if (!pushData.hasOwnProperty("token") || !Array.isArray(pushData.token) || pushData.token.length < 1) {
// 送信先がない
util.returnErrorResponse(callback, 400, "No push target");
} else {
// プッシュサーバーにアクセスするためのプッシュトークンを認証サーバーから取得する
const getAccessTokenPromise = pushUtil.createGetAccessTokenPromise();
getAccessTokenPromise.then((result) => {
// ログ出力
console.info("https://oauth-login.cloud.huawei.com/oauth2/v3/token = " + result);
let accessTokenJson = null;
try {
accessTokenJson = JSON.parse(result);
} catch (exception) {
util.returnErrorResponse(callback, 500, exception);
}
// レスポンスを検証する
if (!accessTokenJson) {
// レスポンスがない
util.returnErrorResponse(callback, 500, "No access token response");
} else if (!accessTokenJson.hasOwnProperty("access_token")) {
// アクセストークンがない
util.returnErrorResponse(callback, 500, "No access token");
} else if (!accessTokenJson.hasOwnProperty("token_type")) {
// アクセストークンの種類が不明
util.returnErrorResponse(callback, 500, "Unknown access token type");
} else if (accessTokenJson.token_type != "Bearer") {
// アクセストークンの種類が違う
util.returnErrorResponse(callback, 500, "Incorrect access token type");
} else {
// アクセストークン
const accessToken = accessTokenJson.access_token;
// タイトル
const pushTitle = pushData.title;
// 本文
const pushBody = pushData.body;
// 送信対象
const pushToken = pushData.token;
// プッシュ通知を送る
const pushNotificationPromise = pushUtil.createPushNotificationPromise(accessToken, pushTitle, pushBody, pushToken);
pushNotificationPromise.then((result) => {
// ログ出力
console.info("https://push-api.cloud.huawei.com/v2/736430079244623135/messages:send = " + result);
let pushNotificationJson = null;
try {
pushNotificationJson = JSON.parse(result);
} catch (exception) {
util.returnErrorResponse(callback, 500, exception);
}
// レスポンスを検証する
if (!pushNotificationJson) {
// レスポンスがない
util.returnErrorResponse(callback, 500, "No push notification response");
} else if (!pushNotificationJson.hasOwnProperty("code")) {
// 送信結果がない
util.returnErrorResponse(callback, 500, "No push notification result");
} else if (pushNotificationJson.result != "80000000" && pushNotificationJson.result != "80100000") {
// アクセストークンの種類が不明
util.returnErrorResponse(callback, 500, "Push failed");
} else {
util.returnResponse(callback, 200, result);
}
}).catch((error) => {
util.returnErrorResponse(callback, 500, error);
});
}
}).catch((error) => {
util.returnErrorResponse(callback, 500, error);
});
}
}
pushUtil.js
const Util = require("./util.js");
const CLIENT_ID = "AppGallery ConnectのMy AppsのApp informationのApp ID";
const CLIENT_SECRET = "AppGallery ConnectのMy AppsのApp informationのApp secret";
module.exports = class MenuContent {
constructor() {
this.util = new Util();
}
createGetAccessTokenPromise() {
const hostname = "oauth-login.cloud.huawei.com";
const path = "/oauth2/v3/token";
const method = "POST";
const headers = {};
const data = {
grant_type: "client_credentials",
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET
};
return this.util.createRequestPromise_x_www_form_urlencoded(hostname, path, method, headers, data);
}
createPushNotificationPromise(accessToken, title, body, token) {
const hostname = "push-api.cloud.huawei.com";
const path = "/v2/736430079244623135/messages:send";
const method = "POST";
const headers = {
Authorization: "Bearer " + accessToken
};
const data = {
validate_only: false,
message: {
notification: {
title: title,
body: body
},
android: {
notification: {
title: title,
body: body,
click_action: {
"type": 1,
"intent": "#Intent;compo=com.rvr/.Activity;S.W=U;end"
}
}
},
token: token
}
};
return this.util.createRequestPromise_json(hostname, path, method, headers, data);
}
}
util.js
const https = require('https');
const querystring = require('querystring');
module.exports = class Util {
constructor() {}
getData(event) {
if (event
&& event.hasOwnProperty("Records")
&& Array.isArray(event.Records)
&& event.Records.length > 0
&& event.Records[0].hasOwnProperty("Sns")
&& event.Records[0].Sns.hasOwnProperty("Message")
) {
return event.Records[0].Sns.Message;
}
return null;
}
createRequestPromise_json(hostname, path, method, headers, data) {
return new Promise((resolve, reject) => {
try {
const stringData = JSON.stringify(data);
headers["Content-Type"] = "application/json";
const options = {
hostname: hostname,
path: path,
method: method,
rejectUnauthorized: false,
headers: headers
};
const request = https.request(options, (response) => {
let data = '';
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', () => {
resolve(data);
});
}).on("error", (error) => {
reject(error);
});
request.write(stringData);
request.end();
} catch (exception) {
reject(exception);
}
});
}
createRequestPromise_x_www_form_urlencoded(hostname, path, method, headers, data) {
return new Promise((resolve, reject) => {
try {
const postData = querystring.stringify(data);
headers["Content-Type"] = "application/x-www-form-urlencoded";
headers["Content-Length"] = postData.length;
const options = {
hostname: hostname,
path: path,
method: method,
headers: headers
};
const request = https.request(options, (response) => {
let data = '';
response.on('data', (chunk) => {
data += chunk;
});
response.on('end', () => {
resolve(data);
});
}).on("error", (error) => {
reject(error);
});
request.write(postData);
request.end();
} catch (exception) {
reject(exception);
}
});
}
returnResponse(callback, statusCode, body) {
if (callback && callback instanceof Function) {
const response = {
'statusCode': statusCode,
'headers': {
'Content-type': 'application/json'
},
'body': JSON.stringify(body)
}
callback(null, response);
}
}
returnErrorResponse(callback, statusCode, error) {
const body = {
error: error
};
this.returnResponse(callback, statusCode, body);
}
}
GitHub
参考
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法
1―概要
2―クライアント(Android-GMS)
3―クライアント(Android-HMS)
4―クライアント(iOS-APNS)
5―サーバー(Amazon SNS:プッシュトークンの保存)
6―サーバー(Amazon SNS:プッシュトークンの管理:HMS)
7―サーバー(Amazon SNS:プッシュトークンの保存:HMS)
8―サーバー(Amazon SNS:プッシュ通知を配信)
9―サーバー(Amazon SNS:プッシュ通知を配信:HMS)
10―サーバー(Amazon SNS:プッシュ通知を配信:複数のデバイスに同時配信)