LoginSignup
12
7

More than 5 years have passed since last update.

GAE/Go+WebPushAPI+FCMでPush通知

Posted at

まとめ

  • Node.js実装をそのままGoにポートした
  • FCM周りはサーバKeyだけ取得すればOK

前提

https://console.cloud.google.com
1. Projectを取得していること
2. GCMのAPIを有効化していること

https://console.firebase.google.com
1. Projectを取得していること

Client

ここを見てその通りに実装します。
注) p256dhとauthはclientかserverのどちらかでsafe URLに置換する必要があります。

概要は以下のような感じです
1. Event Listenerを登録する
2. Server Workerでsubscriptionを取得する
3. GAEにsubscriptionを送信する
4. GAEのデータストアにsubscription情報を保存する

Server

とりあえずPUSH通知だけしたい場合

AuthorizationヘッダにFCMのServer Keyを設定してFCMサーバ(https://fcm.googleapis.com/fcm/send) にPOSTするだけ

Payload付きでPUSH通知したい場合

Payloadを暗号化する必要があります

Node.jsの暗号化実装
https://github.com/GoogleChrome/web-push-encryption

自分はGoで使いたかったのですが見当たらなかったので用意しました
https://github.com/koichiroo/webpushencrypto/blob/master/encrypto.go
paddingが0固定になっているのでその内直します。。

以下使い方です。環境はGAEを想定しています。

使い方
import "github.com/koichiroo/webpushencrypto"

const (
    fcm = "https://fcm.googleapis.com/fcm/send"

    gcm = "https://android.googleapis.com/gcm/send"

    serverKey = "プロジェクトによる"
)

func webpush() error {
    encrypt, err := webpushencrypto.GetEncryptoMessage(key, auth, payload)
    if err != nil {
        return err
    }

    safeSalt := convertSafeURL(base64.URLEncoding.EncodeToString(encrypt.Salt))
    safeKey :=  convertSafeURL(base64.URLEncoding.EncodeToString(encrypt.PublickKey))
    endpoint := strings.Replace(sub.Endpoint, gcm, fcm, -1)
    req, err := http.NewRequest("POST", endpoint, bytes.NewReader(encrypt.Payload))
    if e != nil {
        return
    }
    defer req.Body.Close()
    req.Header.Set("Authorization", strings.Join([]string{"key", serverKey}, "="))
    req.Header.Set("Encryption", fmt.Sprintf("salt=%s", safeSalt))
    req.Header.Set("Crypto-Key", fmt.Sprintf("dh=%s", safeKey))
    req.Header.Set("Content-Encoding", "aesgcm")
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("TTL", "0")
    res, err := urlfetch.Client(ctx).Do(req)
    if err != nil {
         return
    }
    defer res.Body.Close()
}

func convertToSafeURL(s string) string {
    s = strings.Replace(s, "+", "-", -1)
    s = strings.Replace(s, "/", "_", -1)
    s = strings.Replace(s, "=", "", -1)
    return s
}

keyはsubscriptionのp256dh、authはsubscriptionのauthです。
Server KeyはFirebaseのプロジェクトを作成すれば自動的に取得されているものです。
endpointはService WorkerがandroidのURLを取得してくるのでFCM用に置換しています。
payloadは何でもいいですが、今回はMarshal済のJSONを想定しています。

感想

わかってしまえば簡単なのですが、意外とハマりました。
Crypto-Keyヘッダのdh=df=でずっと送信していた。。typoは怖い

12
7
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
12
7