二つの通知のタイプがあります:
- ローカル通知:デバイスで設定されている
- 外部通知:サーバーから来る
ローカル通知のユースケース:
- 事前に設定することができる通知
- リマインダー、締め切り等
- 決済が完了した通知
外部通知のユースケース:
- チャットメッセージが届く時
- お知らせメッセージ
➤ このチュートリアルでは、ローカル通知も外部通知も送っていきます。手順は次のとおりです:
1. Expoプッシュトークンを取得する
2. アプリで通知の受け取りを設定する
3. テスト通知を送る
準備
Expoプロジェクトを作成しましょう。Visual Studio CodeなどのIDEでexpo init expo-push-notifications
を実行します。ターミナルで「blank template」を選びます。
必要なパッケージをインストールします: expo install expo-notifications expo-device
を実行し、そうしたらcd expo-push-notifications
、 npm start
を実行します。 Expo開発環境の設定についてもっと知りたいなら、この記事をお読みください。
トークンの取得
App.jsxのコードをすべてを削除し、以下のコードに置き換えます。
import { Button, Platform, Text, View } from "react-native";
import * as Notifications from "expo-notifications";
import * as Device from "expo-device";
import { useEffect, useState, useRef } from "react";
export default function App() {
//プッシュトークンのバリュー
const [expoPushToken, setExpoPushToken] = useState("");
//プッシュ通知に登録する
const registerForPushNofications = async () => {
try {
//アプリを実行しているデバイスはモバイルかどうかを確認する
if (!Device.isDevice) {
alert("このアプリはモバイルデバイスのみで実行できます");
return;
}
//アプリは通知を受ける許可があるかどうかを確認する
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
//まだ許可されていない場合には、許可を求める
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
//許可は否定されたら、ユーザに知らせる
if (finalStatus !== "granted") {
alert("プッシュ通知のトークンの取得ができませんでした。");
return;
}
//トークンを取得して、スマホの画面で表示する
const token = (await Notifications.getExpoPushTokenAsync()).data;
console.log("token", token);
setExpoPushToken(token);
//アンドロイドなら、通知のオプションを変更することができます。
//vibrationPatternとlightColorを変更してみてください!
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
} catch {
(err) => alert(err);
}
};
useEffect(() => {
registerForPushNofications();
};
}, []);
return (
<View
style={{
flex: 1,
alignItems: "center",
justifyContent: "space-around",
}}
>
<Text>あなたのExpoプッシュトークン: {expoPushToken}</Text>
</View>
);
}
デバッグ
Notifications.getPermissionsAsync() is not a function
初めてコードを実行した時、expo-notificationsがインストールしていたのに、モバイルでNotificationsオブジェクトは空でありました。
同じエラーが発生すれば、次の手順に従って下さい:
1. 開発中のアプリとExpo Goアプリを閉じて、IDEのターミナルでサーバーを切って、もう一回npm start
を実行します。
2.問題が続ければ、npm uninstall expo-notifications
,npm i expo-notifications
を実行します。
3. 問題が続ければ、プロジェクトを削除して、再開します。新しいプロジェクトでnpm start
を実行する前に、スマホで、前のアプリとExpo Goアプリを閉じます。
console.logが機能しません
Expoで, コードの変更はスマホの画面で表示されるまで、時々何回ものセーブが必要です。時々、UIの変更が表示されるのに、console.logやalertが機能しません。この問題が発生すれば、次の手順に従って下さい:
1. 開発中のアプリとExpo Goアプリを閉じて、もう一回開く
2. サーバーを切って、npm start
をもう一度実行する
3. スマホの電源を切って、もうー同オンにする
通知受信の設定
アプリが通知を受け取る時の応答を設定しましょう。App.jsxに以下のコード追加します。
//ハンドラーを設定する
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
//通知を受け取る時に音が鳴らさないようにしたいなら、
//shouldPlaySoundをfalseにして下さい。
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
export default function App() {
...
//受け取った通知
const [notification, setNotification] = useState('');
const notificationListener = useRef();
const responseListener = useRef();
const registerForPushNofications = async () => {...};
useEffect(() => {
registerForPushNofications();
//notificationを受け取った通知に設定する
notificationListener.current =
Notifications.addNotificationReceivedListener((notification) => {
setNotification(notification);
});
//アプリがバックグラウンドにあり、ユーザーが通知をクリックした場合の対処方法
responseListener.current =
Notifications.addNotificationResponseReceivedListener((response) => {
setNotification(response.notification);
console.log(response.notification);
});
return () => {
Notifications.removeNotificationSubscription(
notificationListener.current
);
Notifications.removeNotificationSubscription(responseListener.current);
};
}, []);
return (
<View style={{...}}
>
<Text>あなたのExpoプッシュトークン: {expoPushToken}</Text>
{/* 通知のタイトル、内容とデータを表示する */}
<View style={{ alignItems: "center", justifyContent: "center" }}>
<Text>
タイトル: {notification && notification.request.content.title}{" "}
</Text>
<Text>内容: {notification && notification.request.content.body}</Text>
<Text>
データ:{" "}
{notification && JSON.stringify(notification.request.content.data)}
</Text>
</View>
</View>
);
}
テスト通知の送信
ローカル通知
通知を送る関数と「送信」ボタンをApp.jsxに追加します。
...
//ローカル通知お送る
async function schedulePushNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: "通知のタイトル! 📬",
body: "通知の内容",
data: { data: "通知のデータ" },
},
//通知が送信するまでに、何秒が掛かる
trigger: { seconds: 2 },
});
}
const registerForPushNofications = async () => {...};
...
<Button
title="通知を送信する"
onPress={async () => {
await schedulePushNotification();
}}
/>
...
ボタンを押すと、通知が受け取ります!
外部通知
ExpoはPush notifications toolを提供します。
1.アプリを実行する時にIDEのターミナルで、token <あなたのトーケン>がログされています。そのトーケンをコピーして、ここでペストします
2.通知のタイトル(何でもいいです)
3.通知の内容(何でもいいです))
4.通知のデータ
5.通知が送信するまで、何秒が掛かる
それ以外の枠は入力しなくても大丈夫です。最後に「Send a Notification」ボタンをクリックして、スマホが通知を受け取ります。
まとめ
ローカル通知も外部通知も受信できるアプリを作りました!
完成したApp.jsx:
import { Button, Platform, Text, View } from "react-native";
import * as Notifications from "expo-notifications";
import * as Device from "expo-device";
import { useEffect, useState, useRef } from "react";
//ハンドラーを設定する
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
//通知を受け取る時に音が鳴らさないようにしたいなら、
//shouldPlaySoundをfalseにして下さい。
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
export default function App() {
//プッシュトークンのバリュー
const [expoPushToken, setExpoPushToken] = useState("");
//受け取った通知
const [notification, setNotification] = useState("");
const notificationListener = useRef();
const responseListener = useRef();
//ローカル通知お送る
async function schedulePushNotification() {
await Notifications.scheduleNotificationAsync({
content: {
title: "通知のタイトル! 📬",
body: "通知の内容",
data: { data: "通知のデータ" },
},
//通知が送信するまで、何秒が掛かる
trigger: { seconds: 2 },
});
}
//プッシュ通知に登録する
const registerForPushNofications = async () => {
try {
//アプリを実行しているデバイスはモバイルかどうかを確認する
if (!Device.isDevice) {
alert("このアプリはモバイルデバイスのみで実行できます");
return;
}
//アプリは通知を受ける許可があるかどうかを確認する
const { status: existingStatus } =
await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
//まだ許可されていない場合には、許可を求める
if (existingStatus !== "granted") {
const { status } = await Notifications.requestPermissionsAsync();
finalStatus = status;
}
//許可は否定されたら、ユーザに知らせる
if (finalStatus !== "granted") {
alert("プッシュ通知のトークンの取得ができませんでした。");
return;
}
//トークンを取得して、スマホの画面で表示する
const token = (await Notifications.getExpoPushTokenAsync()).data;
console.log("token", token);
setExpoPushToken(token);
//アンドロイドなら、通知のオプションを変更することができます。
//vibrationPatternとlightColorを変更してみてください!
if (Platform.OS === "android") {
Notifications.setNotificationChannelAsync("default", {
name: "default",
importance: Notifications.AndroidImportance.MAX,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
});
}
} catch {
(err) => alert(err);
}
};
useEffect(() => {
registerForPushNofications();
//notificationを受け取った通知に設定する
notificationListener.current =
Notifications.addNotificationReceivedListener((notification) => {
setNotification(notification);
});
//受け取ったデータをログする
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>あなたのExpoプッシュトークン: {expoPushToken}</Text>
{/* 通知のタイトル、内容とデータを表示する */}
<View style={{ alignItems: "center", justifyContent: "center" }}>
<Text>
タイトル: {notification && notification.request.content.title}{" "}
</Text>
<Text>内容: {notification && notification.request.content.body}</Text>
<Text>
データ:{" "}
{notification && JSON.stringify(notification.request.content.data)}
</Text>
</View>
<Button
title="通知を送信する"
onPress={async () => {
await schedulePushNotification();
}}
/>
</View>
);
}
参考
Firebase Cloud Messaging (アンドロイド)
Expo Goアプリを使わずにアンドロイドアプリを実行したいなら、Firebase Cloud Messagingが必要です。 アプリをApp Storeにアップロードする場合は、この点に注意してください。Firebase Cloud Messagingの設定方法: ドキュメンテーション (英語) , 記事(日本語)。
バックエンド
ローカル通知のみを使用する場合を除いて、通知の送信ができるバックエンドを設定するのが必要です。そのバックエンドは、下のように、Expo Notifications APIにPOSTリクエストができる必要があります。
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({
to: <Expoトーケン>,
data: { data: 'データ' },
title: 'タイトル',
body: '内容',
}),
})
これはこのチュートリアルの範囲外ですが、いくつかのオプションがあります:
- One Signal
- Next.jsでサーバーを作る (この記事を参考して下さい)