🔥

React Native + ExpoでPush通知を試す

React Native + Expo で Push 通知を試した時のメモ。

参考にしたドキュメント

前提

  • expo-cliはインストール済み。バージョンは4.7.3
  • iOS アプリExpo Goで動作確認。バージョンは2.21.3

expo-cli を更新

なんかexpo-cliが古かったので新しいバージョンに更新。 Expo Go も最新に更新。

$ yarn add -g expo-cli

プロジェクト作成

まずはプロジェクトを作成する。

$ expo i -t blank

起動方法について

Expo の起動はexpo startyarn startどちらでも OK。

動作確認の方法について

Expo 起動でブラウザに管理コンソール的なものが表示されるので、 PC とスマホが同じ Wifi に接続されていることを確認して、QR コードを読み取れば Expo Go アプリ上で作ったアプリが起動する。

ちなみに、Expo Go を開いている時にシェイクするとメニューが表示されるので、そこからアプリの Reload ができる。

ライブラリを追加

$ yarn add expo-constants
$ yarn add expo-notifications

ソースコード

以下のコードを App.js にコピペ。Expo Document の Usage そのままでいいと思う。

import Constants from "expo-constants";
import * as Notifications from "expo-notifications";
import React, { useState, useEffect, useRef } from "react";
import { Text, View, Button, Platform } from "react-native";

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: false,
    shouldSetBadge: false,
  }),
});

export default function App() {
  const [expoPushToken, setExpoPushToken] = useState("");
  const [notification, setNotification] = useState(false);
  const notificationListener = useRef();
  const responseListener = useRef();

  useEffect(() => {
    registerForPushNotificationsAsync().then((token) =>
      setExpoPushToken(token)
    );

    // This listener is fired whenever a notification is received while the app is foregrounded
    notificationListener.current =
      Notifications.addNotificationReceivedListener((notification) => {
        setNotification(notification);
      });

    // This listener is fired whenever a user taps on or interacts with a notification (works when app is foregrounded, backgrounded, or killed)
    responseListener.current =
      Notifications.addNotificationResponseReceivedListener((response) => {
        console.log(response);
      });

    return () => {
      Notifications.removeNotificationSubscription(
        notificationListener.current
      );
      Notifications.removeNotificationSubscription(responseListener.current);
    };
  }, []);

  return (
    <View
      style={{
        flex: 1,
        alignItems: "center",
        justifyContent: "space-around",
      }}
    >
      <Text>Your expo push token: {expoPushToken}</Text>
      <View style={{ alignItems: "center", justifyContent: "center" }}>
        <Text>
          Title: {notification && notification.request.content.title}{" "}
        </Text>
        <Text>Body: {notification && notification.request.content.body}</Text>
        <Text>
          Data:{" "}
          {notification && JSON.stringify(notification.request.content.data)}
        </Text>
      </View>
      <Button
        title="Press to Send Notification"
        onPress={async () => {
          try {
            await sendPushNotification(expoPushToken);
          } catch (error) {
            console.log(error);
          }
        }}
      />
    </View>
  );
}

// Can use this function below, OR use Expo's Push Notification Tool-> https://expo.io/notifications
async function sendPushNotification(expoPushToken) {
  const message = {
    to: expoPushToken,
    sound: "default",
    title: "Original Title",
    body: "And here is the body!",
    data: { someData: "goes here" },
  };

  try {
    await fetch("https://exp.host/--/api/v2/push/send", {
      method: "POST",
      headers: {
        Accept: "application/json",
        "Accept-encoding": "gzip, deflate",
        "Content-Type": "application/json",
      },
      body: JSON.stringify(message),
    });
  } catch (error) {
    console.log(error);
  }
}

async function registerForPushNotificationsAsync() {
  let token;

  try {
    if (Constants.isDevice) {
      const { status: existingStatus } =
        await Notifications.getPermissionsAsync();
      let finalStatus = existingStatus;
      if (existingStatus !== "granted") {
        const { status } = await Notifications.requestPermissionsAsync();
        finalStatus = status;
      }
      if (finalStatus !== "granted") {
        alert("Failed to get push token for push notification!");
        return;
      }
      token = (await Notifications.getExpoPushTokenAsync()).data;
      console.log(token);
    } else {
      alert("Must use physical device for Push Notifications");
    }

    if (Platform.OS === "android") {
      Notifications.setNotificationChannelAsync("default", {
        name: "default",
        importance: Notifications.AndroidImportance.MAX,
        vibrationPattern: [0, 250, 250, 250],
        lightColor: "#FF231F7C",
      });
    }
  } catch (error) {
    console.log(error);
  }

  return token;
}

ハマったこと

以下のエラーが発生して expo push token が取得できなかった。 エラーメッセージ通り、サーバー起動前にexpo loginしたら、無事に Push 通知の確認ができた。

Error encountered while fetching Expo token, expected an OK response, received: 400 (body: ”{“errors”:[{“code”:“VALIDATION_ERROR”,“message”:“The Expo push notification service is supported only for Expo projects. Ensure you are logged in to your Expo developer account on the computer from which you are loading your project.”,“isTransient”:false}]}”).

忘れっぽい自分のためのノートです。調べたことや試したことをストックしていきます。