Push Notification

Push Notification

2020/09/02 (修改內容)

簡介

手機裡有內建的推播功能,Android手機預設連接Firebase Cloud Message (FCM),iPhone手機預設連接Apple Push Notification service (APNs),有些公司會提供整合兩者的服務,例如,expo就有這樣的服務,可以簡化推播功能。

expo

首先,必須先在expo上新建一個帳號:

https://expo.io/

要先登入:

expo login

App.js的內容:

import Constants from 'expo-constants';

import * as Notifications from 'expo-notifications';

import * as Permissions from 'expo-permissions';

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);

Notifications.removeNotificationSubscription(responseListener);

};

}, []);


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 () => {

await sendPushNotification(expoPushToken);

}}

/>

</View>

);

}


// Can use this function below, OR use Expo's Push Notification Tool-> https://expo.io/dashboard/notifications

async function sendPushNotification(expoPushToken) {

const message = {

to: expoPushToken,

sound: 'default',

title: 'Original Title',

body: 'And here is the body!',

data: { data: 'goes here' },

};


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),

});

}


async function registerForPushNotificationsAsync() {

let token;

if (Constants.isDevice) {

const { status: existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);

let finalStatus = existingStatus;

if (existingStatus !== 'granted') {

const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);

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',

});

}


return token;

}

package.json

{

"dependencies": {

"expo-constants": "~9.2.0",

"expo-permissions": "~9.3.0",

"expo-notifications": "~0.7.2"

}

}

啟動App,直接按"Press to send notification",手機就會收到訊息了。

也可以打開

https://expo.io/notifications

將App上的看到的expo push token輸入到To (Expo push token from your app)

ExponentPushToken[5X7DEmK5xZqR7-6EzsX7BD]

並輸入想要送出的訊息,我們的手機就可以收到訊息了。

常見問題

如果看到:

[Unhandled promise rejection: Error: Error encountered while fetching Expo token, expected an OK response, received: 400 (body: "{"errors":[{"code":"API_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."}]}").]

就是忘了登入expo。

如果看到:

DeviceNotRegistered: "ExponentPushToken[5X7DEmK5xZqR7-6EzsX7BD]" is not a registered push notification recipient

那有可能是打錯字了,特別要檢查大寫i與小寫L,0與O的差別。

可以試試看,就算是把手機裡的expo關掉了,還是可以收到訊息。

定時提醒

也可以設定訊息的時間,例如,兩秒後提醒: (詳參: Notifications )

import * as Notifications from 'expo-notifications';


// Prepare the notification channel

Notifications.setNotificationChannelAsync('new-emails', {

name: 'E-mail notifications',

importance: Notifications.AndroidImportance.HIGH,

sound: 'email-sound.wav', // <- for Android 8.0+, see channelId property below

});

// Eg. schedule the notification

Notifications.scheduleNotificationAsync({

content: {

title: "You've got mail! 📬",

body: 'Open the notification to read them all',

sound: 'email-sound.wav', // <- for Android below 8.0

},

trigger: {

seconds: 2,

channelId: 'new-emails', // <- for Android 8.0+, see definition above

},

});

參考資料