みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Expoでつくったアプリにサーバからプッシュ通知を送ってバッジをつける 📛

前回つくった、Expoアプリにプッシュ通知を送るローカルサーバ。

blog.kimizuka.org

すんなりうまくいったので、これをそのままHerokuやら、Lambdaやら、Cloud Functionsやらにデプロイすれば、問題なくプッシュ通知を遅れると思い込んでいましたが、冷静に考えると、Expoにログインしないと400が返ってくるため、このままでは動かないことは火を見るよりも明らかでした。

どうしたものかと、Expoにログインする方法を調べてみたところ、expo-server-sdk たるものを使うのがセオリーのようです。

docs.expo.dev


ソースコード

const { Expo } = require('expo-server-sdk');

let expo = new Expo({
  accessToken: process.env.EXPO_ACCESS_TOKEN
});

const tokens = [
  'ExponentPushToken[XXXXXX]',
  'ExponentPushToken[XXXXXX]'
];

const messages = [];

tokens.forEach((token) => {
  messages.push({
    to: token,
    sound: 'default',
    title: '本気で Push! Push!',
    badge: 0 | Math.random() * 9 + 1,
    body: 'We can say!',
    data: {
      timestamp: Date.now()
    }
  })
});

const chunks = expo.chunkPushNotifications(messages);
const tickets = [];

for (let chunk of chunks) {
  try {
    let ticketChunk = await expo.sendPushNotificationsAsync(chunk);

    tickets.push(...ticketChunk);
  } catch (error) {
    console.error(error);
  }
}

const receiptIds = [];

for (let ticket of tickets) {
  if (ticket.id) {
    receiptIds.push(ticket.id);
  }
}

const receiptIdChunks = expo.chunkPushNotificationReceiptIds(receiptIds);

for (let chunk of receiptIdChunks) {
  try {
    let receipts = await expo.getPushNotificationReceiptsAsync(chunk);

    for (let receiptId in receipts) {
      let { status, message, details } = receipts[receiptId];

      if (status === 'ok') {
        continue;
      } else if (status === 'error') {
        if (details && details.error) {
          console.error(message);
        }
      }
    }
  } catch (error) {
    console.error(error);
  }
}

ローカルサーバ用のコード をまるまる移植するとしたらこんな感じです。

あとはこれをHerokuやら、Lambdaやらにデプロイすれば動くはずですが、実際に運用する際はtokensをデータベースから取得するはずなので、とりあえず、Cloud FunctionsにでデプロイしてCloud Firestoreからトークンを取得する方向で実装を試みようと思います。