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 start
、yarn 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}]}”).