こんにちは。
最近ReactNative&ExpoでPush通知を実装する機会があったので、その内容を記事にさせていただきました。
私個人として、Expoを利用したPush通知機能の開発は
●難易度
仕組みを理解することで実装自体は比較的簡単
証明書などの手続きが基本的に不要。
●開発することによる効果
簡易に通知を実装し、アプリの価値を高めることができる。
という点から、Expoでのアプリ開発をする上では非常にオススメの機能です。
その反面、ExpoでのPush通知の実装においては、
・日本語の記事はいくつかあるものの、サンプルが動かなかった。
・Push通知の仕組みも押さえておきたかったが、実装のコードのみの記事が多かった。
・テスト時の情報があまりなく、push通知のテスト部分で少し苦労した。
そういった経験から今回の記事を作成させていただきました。
私自身、そもそもPush通知の仕組みとは?という知識でしたので、Push通知の仕組みも含めて解説させていただきます。
また、今回はiOSでのテストのみ対象としています。
※基本はandroidでも同様ですが、androidの場合は追加で少し設定が必要です。
対象読者
①Expoを利用してより簡易的にPush通知を実装・テストしたいという方。
②そもそもPush通知とは?という方。
目次
1.環境
2.そもそもPush通知とは
3.Expoの提供するPush通知とは
4.実装①ライブラリインストール
5.実装②Push通知許可と通知用トークンの取得
6.実装③通知を開く・フォアグラウンドでの通知受信時の動作
7.ポイント Expoへのログイン
8.テスト①Expo Goのインストール
9.テスト②Push通知を送る
10.まとめ
1.環境
本記事では下記環境が構築されていることを前提としています。
・Expo(40.0.0)
・その他(上記Expoのバージョンに依存)
・テスト用iPhone (今回はiPhoneSE iOS 14.4を使用)
※本記事はReactNative&Expoの環境構築は省いています。
2.そもそもiOSのPush通知とは

上記の図のように
①端末側でユーザからPush通知の許可を取得。
②APNsからPush通知先の端末を特定するトークンを発行。
③②で発行されたトークン情報をサーバに登録。
④③で登録したトークン情報をキーに通知したい情報をApple社のPush通知用サーバに送信。
⑤Apple社のPush通知用サーバから各ユーザの端末にPush通知を送信。
上記のような仕組みとなり、トークンの発行や通知の送信などはApple社のPush通知用サーバを介する必要があります。
※通常はFirebaseなどのツールを利用することが多いかと思います。
また、iOSのPush通知を利用する場合には証明書の発行などの手続きを行う必要があります。
3.Expo(expo-notifications)を利用したPush通知の仕組み

上記の図のように
①端末側でユーザからPush通知の許可を取得
②Expoを介してApple社のPush通知用サーバから端末を特定するトークンを発行。
③②で発行されたトークン情報をサーバに登録
④③で登録したトークン情報をキーに通知したい情報をExpoのサーバを介してApple社のPush通知用サーバに送信。
⑤Apple社のPush通知用サーバから各ユーザの端末にPush通知を送信
基本的にはやはりApple社のサーバを介す必要があるのですが、そのあたりのやり取り(トークンの取得や通知情報の送信)をExpoが代行して行ってくれるため、
「とりあえずPush通知を実装したい」という場合は非常に簡易的にPush通知を実装することができます。
また、何より証明書発行などの手続きが必要ないということがとても大きなメリットかと思います。
4.実装①ライブラリインストール
今回必要となるライブラリは以下の通りです。
expo-notifications
Push通知を実装するためのコアとなるライブラリ
expo install expo-notifications
expo-constants
Push通知は実機でのみ確認可能となるため、実機かどうかの判定を入れています。
expo install expo-constants
5.実装②Push通知許可と通知用トークンの取得
registerForPushNotificationsAsync
①このアプリからのPush通知の許可を取得
②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
③通知用トークンの取得
※今回はサーバなどには送信せず、画面にトークンを表示します。
App.js
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, Button } from 'react-native';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
export default function App() {
const [expoPushToken,setExpoPushToken] = useState(null);
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'space-around',
}}>
<Text>push通知のトークン: {expoPushToken}</Text>
<Button
title="push通知用のトークンを取得"
onPress={async () => {
const pushToken = await registerForPushNotificationsAsync()
setExpoPushToken(pushToken);
}}
/>
</View>
);
}
async function registerForPushNotificationsAsync() {
let token;
if (Constants.isDevice) {
//①このアプリからのPush通知の許可を取得
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
//②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
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');
}
return token;
}
6.実装③通知を開く・フォアグラウンドでの通知受信時の動作
④ユーザが通知をフォアグラウンドで開いた場合のリスナー
今回は「フォアグラウンドで通知を受信しました」と表示することにします。
⑤ユーザが通知を開いた場合のリスナー
今回は「通知を開きました」と表示することにします。
App.js
import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, Button } from 'react-native';
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: false,
shouldSetBadge: false,
}),
});
export default function App() {
const notificationListener = useRef();
const responseListener = useRef();
const [pushState,setPushState] = useState(null);
const [expoPushToken,setExpoPushToken] = useState(null);
useEffect(() => {
// ④ユーザが通知をフォアグラウンドで開いた場合のリスナー
notificationListener.current = Notifications.addNotificationReceivedListener(notification => {
setPushState("フォアグラウンドで通知を受信しました。");
});
// ⑤ユーザが通知を開いた場合のリスナー
responseListener.current = Notifications.addNotificationResponseReceivedListener(response => {
setPushState("通知を開きました。")
});
// userEffectのreturnに登録する関数は、コンポーネントがunmountされるときに実行される。ここで主にcleanup処理を定義する
return () => {
Notifications.removeNotificationSubscription(notificationListener);
Notifications.removeNotificationSubscription(responseListener);
};
}, []);
return (
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'space-around',
}}>
<Text>push通知のトークン: {expoPushToken}</Text>
<View style={{ alignItems: 'center', justifyContent: 'center' }}>
<Text>push通知受信時の動作: {pushState} </Text>
</View>
<Button
title="push通知用のトークンを取得"
onPress={async () => {
const pushToken = await registerForPushNotificationsAsync()
setExpoPushToken(pushToken);
}}
/>
</View>
);
}
async function registerForPushNotificationsAsync() {
let token;
if (Constants.isDevice) {
////①このアプリからのPush通知の許可を取得
const { status: existingStatus } = await Notifications.getPermissionsAsync();
let finalStatus = existingStatus;
if (existingStatus !== 'granted') {
//②初回起動時は許可ダイアログを出してユーザからPush通知の許可を取得
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');
}
return token;
}
7.ポイント Expoへのログイン
expo-notifiationsの機能を利用してテストをするためには、Expoにログインしておく必要があります。
以下のコマンドでログインしておくことでテストが可能になります。
Expoのユーザはこちらで作成可能です。
expo login
8.テスト①Expo Goのインストール
storeから「Expo Goアプリ」をインストールします。

アプリインストール後、[expo start]を実行した際に表示されるQRコードを実機でスキャンします。
これで画面が表示されるはずです。

9.テスト②Push通知を送る
Push通知を送信するためには、Expoの提供するAPIに必要な情報を送信する必要があります。
下記のようなJSONを「https://exp.host/–/api/v2/push/send」に対してPOST送信します。
[
{
"to": "取得したpush通知用のトークン",
"title":"通知のタイトル部分",
"body": "通知の内容部分"
}
]
この際、ヘッダー情報は下記のものを設定します。
host: exp.host
accept: application/json
accept-encoding: gzip, deflate
content-type: application/json
例えば以下のようなPOST送信用のツールから情報を送信した場合

通知受信時(フォアグラウンド)

通知を開いた場合

10.まとめ
今回はできるだけ時間をかけずに早くリリースしたいということから「Expo」と「Expoが提供するPush通知用ライブラリ」の組み合わせでPush通知の実装・テストをより簡易的に行いました。
Push通知と聞くと「何やら難しそう」と思っていましたが、Expoを利用することでとても簡単に実装することができます。
是非皆さんも気軽にPush通知を実装してみてください。