0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法10―サーバー(Amazon SNS:プッシュ通知を配信:HMS Part 2)

Last updated at Posted at 2021-05-07

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:プッシュ通知を配信:複数のデバイスに同時配信)

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?