Push notification
目前主流為使用免費的 FCM (firebase cloud message) 服務
https://github.com/zo0r/react-native-push-notification
1.先去建立 firebase 專案,之後把 google-service.json 放進 android/app
2.yarn add react-native-push-notification
3.npx react-native link react-native-push-notification
另一模組為:
另一模組為:
範例
Local notification
const PushNotification = require("react-native-push-notification");
PushNotification.createChannel(
{
channelId: "channel-yasfasf123132", // (required)
channelName: "My channel", // (required)
channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
},
(created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
);
PushNotification.localNotification({
/* Android Only Properties */
channelId: "channel-yasfasf123132", // (required) channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel.
ticker: "My Notification Ticker", // (optional)
showWhen: true, // (optional) default: true
autoCancel: true, // (optional) default: true
largeIcon: "ic_launcher", // (optional) default: "ic_launcher". Use "" for no large icon.
largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher". Use "" for default small icon.
bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop
subText: "This is a subText", // (optional) default: none
bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
color: "red", // (optional) default: system default
vibrate: true, // (optional) default: true
vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
tag: "some_tag", // (optional) add tag to message
group: "group", // (optional) add group to message
groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false
ongoing: false, // (optional) set whether this is an "ongoing" notification
priority: "high", // (optional) set notification priority, default: high
visibility: "private", // (optional) set notification visibility, default: private
ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear)
shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined
onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false
when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null.
usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false.
timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null
messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module.
actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more
invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true
/* iOS only properties */
alertAction: "view", // (optional) default: view
category: "", // (optional) default: empty string
/* iOS and Android properties */
id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
title: "My Notification Title", // (optional)
message: "My Notification Message", // (required)
userInfo: {}, // (optional) default: {} (using null throws a JSON value '<null>' error)
playSound: false, // (optional) default: true
soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
repeatType: "day", // (optional) Repeating interval. Check 'Repeating Notifications' section for more info.
});
Remote notification
要先設定 App firebase init
1.安裝模組
yarn add @react-native-firebase/app
2.建立專案並放入 google-services.json
android/app/google-services.json
3.
In android/build.gradle
buildscript {
...
dependencies {
...
classpath('com.google.gms:google-services:4.3.3')
...
}
}
In android/app/build.gradle
dependencies {
...
implementation 'com.google.firebase:firebase-analytics:17.3.0'
...
}
apply plugin: 'com.google.gms.google-services'
4. 重啟後即可
npx react-native run-android
5.新增 config code
const PushNotification = require("react-native-push-notification");
PushNotification.configure({
// (optional) Called when Token is generated (iOS and Android)
onRegister: function (token) {
console.log("TOKEN:", token);
},
// (required) Called when a remote is received or opened, or local notification is opened
onNotification: function (notification) {
console.log("NOTIFICATION:", notification);
// process the notification
// (required) Called when a remote is received or opened, or local notification is opened
notification.finish(PushNotificationIOS.FetchResult.NoData);
},
// (optional) Called when Registered Action is pressed and invokeApp is false, if true onNotification will be called (Android)
onAction: function (notification) {
console.log("ACTION:", notification.action);
console.log("NOTIFICATION:", notification);
// process the action
},
// (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
onRegistrationError: function(err) {
console.error(err.message, err);
},
// IOS ONLY (optional): default: all - Permissions to register.
permissions: {
alert: true,
badge: true,
sound: true,
},
// Should the initial notification be popped automatically
// default: true
popInitialNotification: true,
/**
* (optional) default: true
* - Specified if permissions (ios) and token (android and ios) will requested or not,
* - if not, you must call PushNotificationsHandler.requestPermissions() later
* - if you are not using remote notification or do not have Firebase installed, use this:
* requestPermissions: Platform.OS === 'ios'
*/
requestPermissions: true,
});
之後就會看到 token
監聽 foreground message
加上 onmessage 監聽前台訊息
yarn add @react-native-firebase/messaging
import messaging from '@react-native-firebase/messaging';
componentDidMount() {
messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
...
}
7. server 加上推送
要先初始化 server
完整文件:https://firebase.google.com/docs/cloud-messaging/send-message
yarn add firebase-admin
然後加上
完整如下:
const admin = require('firebase-admin');
var serviceAccount = require("./driven-entity-firebase-adminsdk-d7oiu-47bf13bcf6.json");
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
databaseURL: "https://driven-entity-18909.firebaseio.com"
});
// 從 app init 出的 token
const deviceToken = "u9Z8gEd:APA91bFTYl3avh2u96CfgWIz1_tjd57CFH9nDsBeaYbtPh_tbf7_gG3x36no0ck2S6kZ1c150x3AJ5niEH6mkRdf2JCdvC2ePvRq4pMapL6YkcVVAaGTFAoAke0Ory5oqbNS2WVxE8bT";
var message = {
data: {
score: '850',
time: '2:45'
},
token: deviceToken
};
// registration token.
admin.messaging().send(message)
.then((response) => {
// Response is a message ID string.
console.log('Successfully sent message:', response);
})
.catch((error) => {
console.log('Error sending message:', error);
});
有關 postman 發送訊息可參考
Background notification
如果關閉 app 後沒有跳通知可以把後端送的 notification payload 移除,或是不使用 setBackgroundMessageHandler 直接只加上 後端送的 notification payload 也會觸發背景與關閉 app 後的通知。
.sendToDevice(device_token, {
data: {
from_person,
content,
timestamp: Date.now().toString(),
},
// notification: { // 如果有這個的話前端一定會接到 push notification,
// 所以如果要手動控制是否開啟,必須移除此處,並且在前端加上 setBackgroundMessageHandler
// title: from_person,
// body: content,
// icon: 'ic_notification',
// },
})
https://rnfirebase.io/messaging/usage#background--quit-state-messages
在最外層 index.js 加上如下即可
不用去 Androidmanifest.xml 新增 permission
import messaging from '@react-native-firebase/messaging';
// Register background handler
messaging().setBackgroundMessageHandler(async remoteMessage => {
console.log('Message handled in the background!', remoteMessage);
});
....
AppRegistry.registerComponent(appName, () => App);
如果想要產生在手機桌面跳出 APP 通知的效果,只要把 local notification 放入 裡面即可
記得要先在 component 內建立好 channel
PushNotification.createChannel(
{
channelId: "channel-yasfasf123132", // (required)
channelName: "My channel", // (required)
channelDescription: "A channel to categorise your notifications", // (optional) default: undefined.
soundName: "default", // (optional) See `soundName` parameter of `localNotification` function
importance: 4, // (optional) default: 4. Int value of the Android notification importance
vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
},
(created) => console.log(`createChannel returned '${created}'`) // (optional) callback returns whether the channel was created, false means it already existed.
);
最外層 index.js
messaging().setBackgroundMessageHandler(async remoteMessage => {
PushNotification.localNotification({
/* Android Only Properties */
channelId: "channel-yasfasf123132", // (required) channelId, if the channel doesn't exist, it will be created with options passed above (importance, vibration, sound). Once the channel is created, the channel will not be update. Make sure your channelId is different if you change these options. If you have created a custom channel, it will apply options of the channel.
ticker: "My Notification Ticker", // (optional)
showWhen: true, // (optional) default: true
autoCancel: true, // (optional) default: true
largeIcon: "ic_launcher", // (optional) default: "ic_launcher". Use "" for no large icon.
largeIconUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
smallIcon: "ic_notification", // (optional) default: "ic_notification" with fallback for "ic_launcher". Use "" for default small icon.
bigText: "My big text that will be shown when notification is expanded", // (optional) default: "message" prop
subText: "This is a subText", // (optional) default: none
bigPictureUrl: "https://www.example.tld/picture.jpg", // (optional) default: undefined
color: "red", // (optional) default: system default
vibrate: true, // (optional) default: true
vibration: 300, // vibration length in milliseconds, ignored if vibrate=false, default: 1000
tag: "some_tag", // (optional) add tag to message
group: "group", // (optional) add group to message
groupSummary: false, // (optional) set this notification to be the group summary for a group of notifications, default: false
ongoing: false, // (optional) set whether this is an "ongoing" notification
priority: "high", // (optional) set notification priority, default: high
visibility: "private", // (optional) set notification visibility, default: private
ignoreInForeground: false, // (optional) if true, the notification will not be visible when the app is in the foreground (useful for parity with how iOS notifications appear)
shortcutId: "shortcut-id", // (optional) If this notification is duplicative of a Launcher shortcut, sets the id of the shortcut, in case the Launcher wants to hide the shortcut, default undefined
onlyAlertOnce: false, // (optional) alert will open only once with sound and notify, default: false
when: null, // (optionnal) Add a timestamp pertaining to the notification (usually the time the event occurred). For apps targeting Build.VERSION_CODES.N and above, this time is not shown anymore by default and must be opted into by using `showWhen`, default: null.
usesChronometer: false, // (optional) Show the `when` field as a stopwatch. Instead of presenting `when` as a timestamp, the notification will show an automatically updating display of the minutes and seconds since when. Useful when showing an elapsed time (like an ongoing phone call), default: false.
timeoutAfter: null, // (optional) Specifies a duration in milliseconds after which this notification should be canceled, if it is not already canceled, default: null
messageId: "google:message_id", // (optional) added as `message_id` to intent extras so opening push notification can find data stored by @react-native-firebase/messaging module.
actions: ["Yes", "No"], // (Android only) See the doc for notification actions to know more
invokeApp: true, // (optional) This enable click on actions to bring back the application to foreground or stay in background, default: true
/* iOS only properties */
alertAction: "view", // (optional) default: view
category: "", // (optional) default: empty string
/* iOS and Android properties */
id: 0, // (optional) Valid unique 32 bit integer specified as string. default: Autogenerated Unique ID
title: "My Notification Title", // (optional)
message: "My Notification Message", // (required)
userInfo: {}, // (optional) default: {} (using null throws a JSON value '<null>' error)
playSound: false, // (optional) default: true
soundName: "default", // (optional) Sound to play when the notification is shown. Value of 'default' plays the default sound. It can be set to a custom sound such as 'android.resource://com.xyz/raw/my_sound'. It will look for the 'my_sound' audio file in 'res/raw' directory and play it. default: 'default' (default sound is played)
number: 10, // (optional) Valid 32 bit integer specified as string. default: none (Cannot be zero)
repeatType: "day", // (optional) Repeating interval. Check 'Repeating Notifications' section for more info.
});
});
成果如下
左上角的灰色方形更改必須加上 ic_notification
1.可使用產生器:
記得圖案必須是白色,然後透明底色
之後把圖片放入以下產生器產生不同尺寸的圖片:
2.然後使用放入對應的 mipmap-*資料夾
3.最後加入以下到 AndroidManifest
<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@mipmap/ic_notification" />
點擊通知後跳轉到其他畫面
不建議用 getInitialNotification 可能會再開啟程式時觸發
PushNotification.configure({
onNotification: ...
})
記得要註冊
const NotificationHandler = async (message) => {
console.warn('RNFirebaseBackgroundMessage1: ', message);
return Promise.resolve();
};
AppRegistry.registerHeadlessTask(
'ReactNativeFirebaseMessagingHeadlessTask',
() => NotificationHandler,
);
方法2:
使用 admin message 傳入 click_action
但因為要給 intent filter ,所以在 react native 只能用上面的方法
https://firebase.google.com/docs/cloud-messaging/send-message#example-notification-click-action
常見問題
1.local notification 沒反應
關掉模擬器,重啟即可
2. server 發出訊息後 device onMessage 沒反應
曾經遇到過了十分鐘後連續跳出,發生在 android 模擬器上
3. 關閉 app後沒收到通知
如果在傳送時加上 notification payload 則可以再關閉 app 後也跳出通知,如果一並帶上 data 屬性則 onmessage也會觸發(如果不加 notification payload 只加上 apns 或 android priority 不會有作用,可以不用加上 android priority)。
Notification payload 可設定參數:https://firebase.google.com/docs/reference/admin/node/admin.messaging.NotificationMessagePayload
如果更改正方形 icon 可設定如下
但記得只有 sendToDevice 等具有 options: MessagingOptions 才可使用https://firebase.google.com/docs/reference/admin/node/admin.messaging.NotificationMessagePayload
如果是 send 或 sendMulticast 必須參考 https://firebase.google.com/docs/reference/admin/node/admin.messaging.Notification
或是直接去 androidmanifest.xml 設定,則可以不用傳送 icon 參數,但這樣 原本的 app icon 會消失
4. admin message 可用方法
https://firebase.google.com/docs/reference/admin/node/admin.messaging.Messaging
Last updated