Паведамленні React Native: разрэшэння, каналы і жыцёвы цикл FCM
Дакледзіце, як разрэшэння, каналы Android, токены FCM і працоўнікі стану фарграунда, бэкграунда і завершэння работы адносуюцца ў системе паведамленняў React Native з Notifee.
Крыніцы: React Native Notifications & Permissions: A Complete Guide for Android and iOS
Для пользователя прытака — это адно рэчыпце тексту, напрыклад "Ваша замовка была адправлена". Для прыгрынку, які яго адправіў, гэты рэчыпе залежыць ад разрэшэнняў часу выканання, каналаў прытакаў Android, токэнаў прыстрою, Firebase Cloud Messaging (FCM), адпрацоўвальнікаў у фоне і набору разлікоў межы платформамі Android і iOS. Пакрытчына ў будзь-яму з этых слоёў прыводзіць да таго, што прытакі ніколі не падаюць або ачынаецца некалькі экран. У гэтым кярыянтэ разбіраецца кожны слой з выкарыстоўваннем Notifee і React Native Firebase, каб вы моглі стварыць систему прытакаў, якая будзе праведна дзейсціць у кожным стане прыгрынку.
Локальныя прытакі і прытакі на адшыпканні
Локальныя прытакі
Локальны прытак ствараецца на прыстрою самым прыгрынкам, без участі сервера. Типовым прыкладам є нагадка пра зустрэч:
Reminder
Your meeting starts in 10 minutes.
Аплікацыя можа паказваць ўведамленні або запланаваць іх на выконанне без падключэння да Інтернету. Notifee адказвае за адна API для React Native, яка працуе через вялікія системы уведамлення обох платформ.
Уведамленні типу push
Процес выдачы уведамлення типу push пачынаецца на сервере. Ваш бэкенд перадае паведамленне FCM, FCM доставляе яго на прыстрой, а аплікацыя React Native реагуе на яго:
Your Backend
│
▼
Firebase Cloud Messaging
│
▼
Android / iOS Device
│
▼
React Native Application
FCM разлічае уведамленні (якія система можа паказаць вам) і паведамленні з дадзенням (довільныя пакеты з ключамі і значэнням для вашага коду), пры чым можа адресаваць як адзін прыстрой, так і групу прыстроў за дапамогою тэм.
Дазволы ўскладневаюць стан аплікацыі
Установка прыгункі не павінна яшчэ значаць, што ён можа паказваць спавешчанні. З Андроѓ 13 POST_NOTIFICATIONS ёсць дазвол, які трэба атрыбуаваць пад час выканання, і прыгункі, назначаныя для Андроѓ 13 або новейшых версій, должны запытаць пра яго перад тым, як паказваць ўсё. У iOS завжды была неабходна явная дазвола корыстувальніка. Спрыяйце дазволам як стану прыгункі, яны можа змяніцца, а не як етапу наладжвання, який выкалічваецца раз.
Розумны алгорытм пераконтваецца ў статусе, пояснюе прычыны і тады запытае; будзь-якая адпаведзь дазволяе прыгункі продаць свою роботу:
Application starts
│
▼
Check notification permission
│
├── Granted ───────► Continue
│
└── Not granted
│
▼
Explain the benefit
│
▼
Request permission
│
┌─────┴─────┐
▼ ▼
Granted Denied
│ │
▼ ▼
Notifications Continue
Установка бібліятэк
Notifee адпавядае за паказванне спавешчанні:
npm install @notifee/react-native
React Native Firebase з’являе основны модуль прыгункі і модуль для перадачы паведамленняў:
npm install @react-native-firebase/app
npm install @react-native-firebase/messaging
У iOS пасля таго трэба установіць натыўныя залежнасці CocoaPods:
cd ios
pod install
cd ..
Натыўная настройка разніцяецца залежна ад версіі React Native і налаштавання проекта, а для падачы спам-паведамленняў на iOS таксама патрэбны кранты APNs у Firebase і можлівасць падачы спам-паведамленняў у Xcode. Следзіце актуальную дакументацыю кожнай бібліятэкі.
Адзначэнне першага натыўнага спам-паведамлення
Мэтай першага прыклада є спам-паведамленне з такім заглавлём і тэкстам:
New Message
You have received a new message.
Спачатку імпортуйце Notifee разам з enum для пазначэння значынь важлівасці каналаў у Android:
import notifee, {
AndroidImportance,
} from '@notifee/react-native';
Функцыя нижэй выконвае тры дзеянні па спрабе: яна запрашвае дазвол, стварае (або перысваіць) канал у Android пад назвай default, і адзначае спам-паведамленне на гэтым канале. Параметр pressAction з ідэнтыфікатаром default прыказвае Android ачыніць прыкладку, калі спам-паведамленне будзе нажата; без яго нажаты ўсё не паўлічваецца.
export async function displayNotification() {
// Request permission
await notifee.requestPermission(); // Create Android notification channel
const channelId = await notifee.createChannel({
id: 'default',
name: 'Default Notifications',
importance: AndroidImportance.DEFAULT,
}); // Display notification
await notifee.displayNotification({
title: 'New Message',
body: 'You have received a new message.', android: {
channelId,
pressAction: {
id: 'default',
},
},
});
}
Парадоксальна вызначэнне createChannel адзіноўсе безпечна; існуючы канал проста вяртае свой ідэнтыфікатор. Каналы ўмовныя для Android 8.0 (API 26) і новейшых версіях. Функцыю можна актывацыя з паканчика:
<Button
title="Show Notification"
onPress={displayNotification}
/>
Запыт пра разрэшэнне Android 13
Полны назва разрэшэння ў Android:
android.permission.POST_NOTIFICATIONS
React Native выкладвае яго як сталячую значэнне ў PermissionsAndroid:
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS
Разрэшэнне таксама трэба адзначыць за дапамою uses-permission у файле AndroidManifest.xml, інакша запыт будзе тылуцься без паведамлення. Пачніце з імпортаў:
import {
PermissionsAndroid,
Platform,
} from 'react-native';
Памагальны клас вяртае true адразу на iOS і ў версіях Android нижэй 13 (API level 33), дзе прыметкі ўвесь час дазволеныя. У іншым случае ён паказывае дыалог системы і адмаўляе, чы рэзультат быў GRANTED:
export async function requestAndroidNotificationPermission() {
if (Platform.OS !== 'android') {
return true;
} if (Platform.Version < 33) {
return true;
} const result = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
); return result === PermissionsAndroid.RESULTS.GRANTED;
}
Выклікайце яго з экрана:
const granted =
await requestAndroidNotificationPermission();
і прымкніце да рэзультата:
if (granted) {
console.log('Notifications allowed');
} else {
console.log('Notifications denied');
}
Android можа вернуць тры значныя рэзультаты:
GRANTED
DENIED
NEVER_ASK_AGAIN
NEVER_ASK_AGAIN заслуговае на спецыяльную увагу. Пасля паўтаральных адмовы система перестае паказваць дыялог, і толькі настройкі системы можа зменіць адпаведны адказ.
Запыт у правы момент
Адкрыць системны запит на самым першым экране — это распашчаная і дорога памылка. Новы корыстнік, який адразу бачыць
"Allow MyApp to send notifications?"
не мае контексту і, верагатна, адмовіць. Спачатку поясніце, напрыклад, на экране прывітання:
Welcome to MyApp
праз які будзе паказана карточка, якая перыяднае, для чаго патрэбны спавешчанні, з кнопкай:
Enable notifications to receive:
✓ New messages
✓ Order updates
✓ Important alerts[Enable Notifications]
Толькі цей натыск запускае дыялог ОС, таму запыт адпаведае на выбор корыстніка, а не перакрывае яго дзеяння.
Разрэшэнне на iOS з Notifee
У iOS паўтаральнік должен явна адмаўліць або разрэшыць доставку паведамленняў. Notifee адзвяртаеся пра рэзультат за дапамогай AuthorizationStatus:
import notifee, {
AuthorizationStatus,
} from '@notifee/react-native';
Наведзены ў нижчым фрагменте калектар спрацоўвае два статусы як успех. AUTHORIZED означае повнае разрэшэнне. PROVISIONAL — це режым тыхасці ў iOS, калі паведамленняя доставляюцца безпосередна ў Центр паведамленняў, не пераскакваючы паўтаральніка, і паўтаральнік можа пазней яныя заставіць або выключыць. Усе інша спрацоўваецца як адмова:
export async function requestIOSNotificationPermission() {
const settings = await notifee.requestPermission(); if (
settings.authorizationStatus ===
AuthorizationStatus.AUTHORIZED
) {
console.log('Notifications authorized');
return true;
} if (
settings.authorizationStatus ===
AuthorizationStatus.PROVISIONAL
) {
console.log('Notifications provisionally authorized');
return true;
} console.log('Notifications denied'); return false;
}
Запрос у iOS можа включаць розныя опцыі:
Alerts
Sounds
Badges
CarPlay
Announcements
Provisional notifications
Запрашайце толькі тое, што вам патрэбна; напрыклад, временнае разрэшэнне абходзіце запит цалкам.
Адна функцыя разрэшэння для всіх прыкладнікаў
Уместа розпылення пераканальнікаў па разных экранах, викорыстоўваеце адны модуль службы:
src/
├── services/
│ └── notificationService.ts
├── screens/
├── components/
└── App.tsx
Файл службы:
// notificationService.ts
Спалюець шляхі з обох платформ. На Android выконваецца пераконтроль версіі та запит у час роботы; на iOS викорыстоўваецца Notifee і прыймаюцься як автарызаваны, так і тымчасовы статус:
import {
Platform,
PermissionsAndroid,
} from 'react-native';import notifee, {
AuthorizationStatus,
} from '@notifee/react-native';export async function requestNotificationPermission() {
if (Platform.OS === 'android') {
if (Platform.Version < 33) {
return true;
} const result = await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
); return result === PermissionsAndroid.RESULTS.GRANTED;
} const settings = await notifee.requestPermission(); return (
settings.authorizationStatus ===
AuthorizationStatus.AUTHORIZED ||
settings.authorizationStatus ===
AuthorizationStatus.PROVISIONAL
);
}
Паказчыкі пасля чаго вызываюць адну функцыю:
const enabled = await requestNotificationPermission();
і дзейнуюць на адпаведны адказ:
if (enabled) {
console.log('Ready for notifications');
}
Няўжоныя версіі Notifee таксама можуць запрашваць POST_NOTIFICATIONS на Android 13 через requestPermission(); пераканайцеся ў актуальных дасведчэннях Notifee, якщо хочаце адны запыт для обох платформ.
Каналы спавяшчэнняў Android
Android 8.0 адкрыў каналы, ўнаследкі чаго корыстувальнікі можаць незалежна кераваць категорыямі спавяшчэнняў. Аплікацыя можа выказваць калькольве:
MyApp
│
├── Messages
├── Orders
├── Promotions
└── Security
Кожны канал мае свою значымасць та звук. Паведамленні зазвычай заслуговуюць на высокую значымасць, таму яны паказваюцца:
const messageChannel = await notifee.createChannel({
id: 'messages',
name: 'Messages',
importance: AndroidImportance.HIGH,
});
Калі відбуваюцца змены замовлення, можна выкарыстоўваць стандартны рэжым:
const orderChannel = await notifee.createChannel({
id: 'orders',
name: 'Orders',
importance: AndroidImportance.DEFAULT,
});
Пасля чаго паведамленне называе канал, да якога ён належыць. Выклік показаны ў двух частях: спачатку загалоўкі, а потым тэла:
await notifee.displayNotification({
title: 'New Message',
body: 'You received a new message.',
А пасля чыраўкі опцый Android, якія аднасоўваюцца да ідэнтыфікатора каналу, вярнутага функцыёй createChannel:
android: {
channelId: messageChannel,
},
});
Каналы адзначаюцца для корыстувачоў, а не толькі як настройкі для разработчыкаў. Корыстувачы можаць выключыць або заблакаваць канал у настройках системы, і пасля стварэння каналу дапыт больш не можа програмна змяніць його значэнне; глыбокае рашэння за корыстувачам. Выбірайце адзячна, альбо пазней выкарыстаўце новы ідэнтыфікатор каналу.
Структура, якая добра працуе ў прымэтным режыме, раздзеляе каналы за мэтай:
notifications
│
├── messages
├── orders
├── payments
├── security
└── marketing
Адзінокі маркетынгавы канал дазволяе корыстувачам выключыць рекламныя спавешчэння, не втрачаючы паведамленняя пра безпеку.
Як FCM падходзіць да гэтага
Для функцыі push FCM знаходзится межа вашым бэкендам і кожным запускаемым дапрацоўкам:
┌─────────────────┐
│ Your Backend │
└────────┬────────┘
│
▼
┌─────────────────┐
│ FCM │
└────────┬────────┘
│
┌───────┴───────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ Android │ │ iOS │
└──────────┘ └──────────┘
Атрыманне токена прыстрою
Кожны запуск дапрацоўкі можа атрымаць токен рэгістрацыі FCM, і ваш бэкенд патрэбуе гэты токен, каб звяжацца з конкрэтным прыстроем. Імпортуйце модуль для перадачы паведамленняў:
import messaging from '@react-native-firebase/messaging';
і запытайце токен:
export async function getFCMToken() {
const token = await messaging().getToken(); console.log('FCM Token:', token); return token;
}
У рэальнай дапрацоўкі токен адправляецца на ваш сервер ведамо пасля таго, як ён быў атрыманы:
const token = await messaging().getToken();
await fetch('https://api.example.com/device-token', {
method: 'POST', headers: {
'Content-Type': 'application/json',
}, body: JSON.stringify({
token,
}),
});
Пасля чаго бэкенд зберагае токен пры адпаведным заўвязаным корыстніку і прыстрою:
User
│
├── userId
├── deviceId
└── fcmToken
Адкрэптаванне токенаў
Токены мяняюцца, напрыклад пасля перзапуску дапрацоўкі аб чысткі ўсіх дадзенаў дапрацоўкі. Слухайце за падзеямі адкрэптавання:
import messaging from '@react-native-firebase/messaging';
Слухальнік перадае кожны новы токен, а функцыя вяртае функцію для анулявання падпіску:
export function subscribeToTokenRefresh() {
return messaging().onTokenRefresh(async token => {
console.log('New FCM token:', token); await sendTokenToBackend(token);
});
}
Мінімальны помачык для аплоаду, знову паказаны ў двух частях, выконвае JSON POST:
async function sendTokenToBackend(token: string) {
await fetch('https://api.example.com/device-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
}, body: JSON.stringify({
token,
}),
});
}
Саветы самай Firebase — караць змены токенаў і дасылать новяныя значэнні на сервер вашага прыемніка кожны раз, калі яны змянююцца. На серверной стороне таксама трэба адмахнуцца токенаў, якія FCM прызнае нэваліднымі, каб не накапліваўся застарэлыя прыстроі.
Паведамленні ў фонавым режыме не аплываюць автаматычна
Найбольш заплутаны случаек — калі паведамленне прыходзіць, калі прыемнік ачыны:
User
│
▼
React Native App
│
▼
FCM message
Аслухвайцеся на паведамленні ў фонавым режыме:
import messaging from '@react-native-firebase/messaging';
const unsubscribe = messaging().onMessage(
async remoteMessage => {
console.log('Foreground message:', remoteMessage);
},
);
Аднак прыема паведамлення і аплыванне системнага прыемніка — гэта разныя крокі. Калі прыемнік знаходзіцца ў фонавым режыме, FCM перадае паведамленне вашаму коду і сама не аплывае нічога. Чырабяць прыемнік трэба, перадаўшы ўместа яго контент у Notifee:
import notifee from '@notifee/react-native';
Наведзены выкладчык пераканаецца, што канал існуе, пасля чаго адразу выводзіць упаведамленне; калі у прыемніку няма блока notification (напрыклад, у прыемніку з толькі дадзенням), выкарыстоўваецца стандартны тэкст:
messaging().onMessage(async remoteMessage => {
const channelId = await notifee.createChannel({
id: 'messages',
name: 'Messages',
}); await notifee.displayNotification({
title:
remoteMessage.notification?.title ??
'New Message', body:
remoteMessage.notification?.body ??
'You have a new message.', android: {
channelId,
pressAction: {
id: 'default',
},
},
});
});
Вы кантролюеце адзінство візуальнага выкладку, уключаючы можлівасць яго прыховання, калі адпаведны экран вялікі ўжо видны:
Упаведамленні на фоне і у стане завершэння
Калі прыкладка знаходзіцца на фоне, яе поведзенне зміняецца. У Android упаведамленні FCM праходзяць адразу ў системную панель без вызову вашага калебарды на першы план, а прыемнікі, якія ўключаюць як упаведамленні, так і дадзення, паўнажываюцца сабой правіламі для роботы на фоне. У iOS прыемнікі з толькі дадзенняма на фоне адправляюцца за прынципам «зусібытку зусілляў» і можу быць запазджаныя або обмежаныя системай.
React Native Firebase задае спецыяльны выкладчык для прыемнікаў на фоне:
import messaging from '@react-native-firebase/messaging';
messaging().setBackgroundMessageHandler(
async remoteMessage => {
console.log(
'Background message:',
remoteMessage,
);
},
);
Частая памяць – рэгістрацыя гэтага хендлера ўнутрь компонента React, як у наступным фрагменте:
function App() {
messaging().setBackgroundMessageHandler(...);
return <Navigation />;
}
Фонавы процес можа не запускаць жадных компанентоў, таму хендлер ніколі не будзе існаваць. Рэгіструйце яго ў точцы запуску:
// index.js
import messaging from '@react-native-firebase/messaging';messaging().setBackgroundMessageHandler(
async remoteMessage => {
console.log(
'Background message:',
remoteMessage,
);
},
);
і толькі пасля чаго рэгіструйце корневы компонент:
AppRegistry.registerComponent(
appName,
() => App,
);
Реакцыя на нажатыя на упавядомленні
Нажатые зазвычай должна прыводзіць користувальніка ў конкрэтную пазіцыю:
Notification
│
▼
User taps
│
▼
Application opens
│
▼
Order Details
Падазроўваючы, што у даных паведамлення є ідэнтыфікатор замовлена:
{
"orderId": "12345"
}
Для аплікацыяў, якія запускаюцца з фону, onNotificationOpenedApp актываецца, калі корыстувальнік нажымае на упавядомленне. Калебак вызначае ідэнтыфікатор з remoteMessage.data і можа адтуды перейсці:
messaging().onNotificationOpenedApp(
remoteMessage => {
const orderId =
remoteMessage.data?.orderId;
if (orderId) {
// Navigate to order details
console.log(
'Open order:',
orderId,
);
}
},
);
Калі аплікацыя была цэлкам закрыта
Якщо аплікацыя была завершана, праграма дзеяння выглядае так:
App completely closed
│
▼
User receives notification
│
▼
User taps notification
│
▼
App launches
У такім случае onNotificationOpenedApp не запускаецца. У замене пад час запуску трэба адзін раз запытаць пра паведамленне, якое запускае аплікацыю:
const remoteMessage =
await messaging().getInitialNotification();
if (remoteMessage) {
const orderId =
remoteMessage.data?.orderId; console.log(
'App opened from notification:',
orderId,
);
}
Оба методы адпрацоўваюць толькі тыя паведамленні, якія адобразіў FCM. Нажатыя на паведамленні, якія вы самі адобразілі за дапамогою Notifee, напрыклад тыя, якія адобразяюцца на першам плане, прыходзяць через сабэчныя API-і Notifee (onForegroundEvent, onBackgroundEvent і ўсё, што звяжана з getInitialNotification). Адпрацоўка толькі адной групы паведамленняяў — частая прычына багоў типу „нажатые не дазволяюць нічога зробіць“.
Пакеты дадзеных, прызначаныя для навігацыі
Паведамленне, якое толькі пішае
New Order
нічога не паведамляе аплікацыі пра тое, дзе павінен знаходзіцца корыстнік. Неабяжна дадаць структураваныя даны разам з візуальным тэкстам:
{
"notification": {
"title": "New Order",
"body": "Order #12345 has been confirmed"
},
"data": {
"type": "order",
"orderId": "12345"
}
}
Функцыя рутэра можа тады супарадаваць type з экранам:
function handleNotification(data: any) {
if (data.type === 'order') {
navigation.navigate(
'OrderDetails',
{
orderId: data.orderId,
},
);
}
}
Пакалькі, што працэўнікі паведамленняя часта запускаюцца за межамі компанентав, navigation у такіх дапаможных функцыях зазвычай являе сабою рэферэнс навігацыі, створаны ў корзене аплікацыі. Для дэтальнага разгляду рутавання праз глыбокія лінкі, адзірніце рутавання праз паведамленнія-пуш у React Native праз глыбокія лінкі.
Адказваўленне на змяны праваў пасля інсталляцыі
Права не застойваюцца з часам. Пользователь можа разрэшыць паведамленнія у панедзелак:
Monday:
Notifications = ON
і выключыць іх у настаўленнях системы ў сэрпень:
Wednesday:
User opens Android SettingsNotifications = OFF
Аплікацыя должна гэта заўважыць. Notifee чытае текущыя настаўленні без запиту:
import notifee, {
AuthorizationStatus,
} from '@notifee/react-native';
export async function checkNotificationPermission() {
const settings =
await notifee.getNotificationSettings(); if (
settings.authorizationStatus ===
AuthorizationStatus.AUTHORIZED
) {
return true;
} return false;
}
Заўважкі: гэты пераказ вяртае false для тымчасовага автарызавання; адключыце PROVISIONAL, якщо ваша аплікацыя спрацоўвае яго як актываўанае. Зноў запусціце яго, калі аплікацыя вернёцца на першы план.
Калі корыстнік адмовяецца
Не павтарайце запит. У замен пакажыце чыстае становішча, напрыклад банер:
Notifications are disabled
з дзеянням, якое ведае да налашоўкаў:
Enable notifications from Settings
to receive important updates.[Open Settings]
Notifee адказвае API, якія безпасэродзей ведаюць у налашоўкі прыемніка паведамленняя аплікацыі. Асновныя прынцыпы всьго гэтага можна паказаць на адной карточцы:
Don't force
Don't spam
Explain the value
Give the user control
Централізаванне налашоўкаў прыемніка паведамленняя
У коде для прыменнага выкарыстоўвання ўсё, што стосуецца прыемніка паведамленняя, трэба разместіць у калькох чыста апісаных модулях:
src/
│
├── services/
│ ├── notificationService.ts
│ └── firebaseMessaging.ts
│
├── navigation/
│ └── notificationNavigation.ts
│
├── screens/
│
└── App.tsx
Галоўны сервіс:
// notificationService.ts
Адаптаваець, які запрашоўвае разрешэння, зупынаецца, якщо корыстунач адмовіўся, і іншым чыным стварае стандартны канал:
import notifee, {
AndroidImportance,
AuthorizationStatus,
} from '@notifee/react-native';export async function initializeNotifications() {
const settings =
await notifee.requestPermission(); const authorized =
settings.authorizationStatus ===
AuthorizationStatus.AUTHORIZED ||
settings.authorizationStatus ===
AuthorizationStatus.PROVISIONAL; if (!authorized) {
return false;
} await notifee.createChannel({
id: 'default',
name: 'Default Notifications',
importance: AndroidImportance.DEFAULT,
}); return true;
}
Выклікванне яго з компонента ўсё проста:
useEffect(() => {
initializeNotifications();
}, []);
Адзярожна: на першам экране гэта запрашаецца негайна, як і было описана ранейша з проблемай часавага параметра. Кращэ выклікваты яго з кнопкі падтрымкі.
Бэкенд
Тыповая модель дадзэнняяхоўвае корыстуначаў і ўсія их прыстроі ў аднальных табліцах, адтолькі што адны корыстунач мага маты калькольве тэлефонаў або планшетаў:
users
│
├── id
├── name
└── email
user_devices
│
├── id
├── user_id
├── device_id
├── fcm_token
├── platform
├── created_at
└── updated_at
Запіс рэгістрацыі прыстрою можа выглядаць так:
{
"userId": 101,
"deviceId": "device-abc",
"fcmToken": "xxxxx",
"platform": "android"
}
Калі выйшае бізнес-з’явыцца, бэкенд шукае токены корыстунача і адправляе іх через FCM:
Order Created
│
▼
Backend
│
▼
Find user's FCM token
│
▼
Firebase Cloud Messaging
│
▼
User's phone
FCM спакоўваецца на тое, што паведамленні будуць адправляцца з надзеяныя среды, такой як ваш сервер аплікацыі чыста Cloud Functions, ніколі з кліента, адтуды што для адправкі трэбуюцца кранты сервера.
Паллады, якія падлягаюць масштабаванню
Проектуйце кожную палладу так, каб аплікацыя разумела заход, а не толькі текст. Падтверджэнне платежа можа мець:
{
"notification": {
"title": "Payment Successful",
"body": "Your payment of ₹999 was successful."
},
"data": {
"type": "payment",
"paymentId": "PAY12345",
"screen": "PaymentDetails"
}
}
Одні змены switch на data.type пазбірае ўсі відмены прыемных паведамленняў:
switch (data.type) {
case 'payment':
navigation.navigate(
'PaymentDetails',
{
paymentId: data.paymentId,
},
);
break;
case 'order':
navigation.navigate(
'OrderDetails',
{
orderId: data.orderId,
},
);
break;
}
Кожны новы тип прыемнага паведамлення — это новы кейс. Значэнні дадзеных FCM ёсць строкамі, таму числы трэба парсаваць явна.
Полная архітэктура
Як толькі асаблівы элементы з’едынаюцца, працоўная наладка выглядае так:
┌──────────────────┐
│ Backend API │
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Firebase / FCM │
└────────┬─────────┘
│
┌────────────┴────────────┐
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Android │ │ iOS │
└──────┬───────┘ └──────┬───────┘
│ │
▼ ▼
Notification APNs / FCM
Channel │
│ │
└────────────┬────────────┘
▼
React Native App
│
▼
Navigation / UI
У iOS FCM сам не доставляе паведамленні; ён іх перадае через службу Apple Push Notification (APNs), таму трэба налаштаваць кранты APNs.
Звычныя памылкі
Запит на дзеянне пад час першага запуску
Такі падход на першым экране, без жадных адказаў, ёсць найбольш распашчастая памылка:
useEffect(() => {
requestNotificationPermission();
}, []);
Спачатку трэба поясніць значэнне, а праз разыграш дзеяння корыстувальца — запросіць разрэшэння.
Забыванне пра каналы
Без канала паведамленні не будуць апыляцься на Android 8.0 і новейшых версіях. Створыце канал пры першай апляваціі:
await notifee.createChannel({
id: 'messages',
name: 'Messages',
});
Аспакоўкі на апыляцію паведамленняў у фонавым режыме
Адслухоўванне паведамленняў
messaging().onMessage(...)
не значыць, што ў кожным случае будзе апыляцца відразумелае системнае паведамленне. Ёжысткай апляваціі паведамленняў у фонавым режыме, аплявіце яе самі за дапамогою Notifee.
Ігнараванне змян токена
Токен, які быў запісаны ў адны раз, пасля таго нямае дзейнасці. Ожывайце
messaging().onTokenRefresh(...)
і апылайце кожны новы токен у серверную частыну.
Рэгістрацыя працоўнікаў у фонавым режыме ў компанентах
Канал обработкі паведамленняях адаптуюцца да точкі запуску, за межамі дрэва React, як паказана раней.
Ігнараванне пазнейшых змян дазволаў
Пользоваталі можуць анулюваць дазволы або заблакаваць адзін канал у будзь-вым часе. Вашы пераконтроўкі павинны урахоўваць кожны з гэтых станаў:
Granted
Denied
Changed externally
Channel blocked
App notifications disabled
Адчыпленне чутлівых дадзенняў
Тэкст паведамлення ёсць видны на экране блакання і для всіх, якія знаходзяцца поблізу прыстрою. Уместа таго
Your bank account ending in 1234 received ₹50,000.
надасці ўсё, што є нейтральным:
New account activity
Tap to view details.
і паказаць деталі толькі пасля таго, як пользоваталь няўпісаецца ў прыстрое.
Чарт перакантроўкі
Паведамленне разніцяеся залежна ад версіі ОС, стану прыстрою і самога прыстроя, таму трэба теставаць систематычна. На Android:
☐ Android 12
☐ Android 13+
☐ Permission granted
☐ Permission denied
☐ Permission disabled from Settings
☐ Channel enabled
☐ Channel disabled
☐ App foreground
☐ App background
☐ App killed
☐ Notification tapped
☐ Multiple notifications
На iOS:
☐ Permission granted
☐ Permission denied
☐ Permission changed from Settings
☐ App foreground
☐ App background
☐ App terminated
☐ Notification tapped
☐ Badge
☐ Sound
☐ Deep linking
А для інтэграцыі FCM ад початку да канца:
☐ Token generated
☐ Token stored on backend
☐ Token refresh handled
☐ Foreground message received
☐ Background message received
☐ Notification click handled
☐ Initial notification handled
Алгорытм работы прыстрою
Паўная последоўнасць, ад запуску прыстанку да выдачы і навігацыі, выглядае так:
APP START
│
▼
Check permissions
│
┌────────┴────────┐
│ │
Allowed Denied
│ │
▼ ▼
Initialize FCM Show explanation
│ │
▼ ▼
Get FCM token Request permission
│
▼
Send token to API
│
▼
App Running
│
┌──────┴──────┐
│ │
▼ ▼
Foreground Background
│ │
▼ ▼
onMessage FCM/APNs
│ │
▼ ▼
Notifee System UI
│ │
└──────┬──────┘
▼
User taps
│
▼
Read notification data
│
▼
Navigation
Локальныя пры падачы і ўжыванне якіх-небудзь з іх разам
Два типы прыемных паведамленняя разніцяюцца за калькама прызначэння:
- Актывацыя: локальныя прыемные паведамлення выходзяць з самага прыстанку або устройства; прыемные паведамлення па падачы выходзяць з вашага сервера.
- Сеть: локальныя прыемные паведамлення зазвычай работаюць без сеті; прыемные паведамлення па падачы выклакуюць наявнасць сетевага з’ѐеднання.
- FCM: не патрэбны для локальных прыемных паведамленняя; зазвычай неабходны для прыемных паведамлення па падачы.
- Запланаваныя нагадкі: яны пасуюць да локальных прыемных паведамленняя; не ўсходзяць у стандартны спосаб выкарыстоўвання прыемных паведамлення па падачы.
- Падзеі сервера, апдэты замовленняў, паведамленні ў чате: прыемныя паведамлення па падачы ўсходзяць у стандартны выбар; локальныя прыемные паведамлення можаць ўсунуць іх толькі часткова.
- Бібліятэкі: Notifee для локальных прыемных паведамленняя; FCM плюс бібліятэка для адображэння для прыемных паведамлення па падачы.
Яны таксама добра падаюць разам. У стандартный наладзе FCM адправляе прыемлівку, ваш код яе обрабоцвае, а Notifee яе паказывае:
FCM receives message
↓
React Native processes message
↓
Notifee displays native notification
Што павінны бачыць корыстувальнікі на кожным кроку
Для ручнай перацэнкі трэба знать, чаго спакавацца. У Android 13+ праказваецца дыялог системы:
Allow MyApp to send you notifications?
У наладках системных прыемліваў аплікэцыі каналы, якія вы створылі, праказваюцца як окольныя пераключычкі:
MyApp
├── Messages
├── Orders
└── Promotions
У iOS праказваецца запит на разрэшэння системы, а адправленыя прыемлівкі паказваюцца ў Центре прыемліваў. Для пуш-прыемліваў консоль Firebase можа адправіць тэставую прыемлівку безпасова на токен прыстрою, што ўсё прыгожэйшы спосаб разлучыць багі сервера ад баго кліента:
Firebase Console
↓
Cloud Messaging
↓
Test Message
↓
FCM Token
У канцы, пасля натыкання на прыемлівку аб ардэре:
Notification
↓
Order #12345
трэба прайсці на адпаведны экран:
Order Details Screen
Аптальнейшыя практыкі для працы ў прыемлівах
Задаючы час запиту на разрэшэнне, нехай корыстувальнікі разумеюць, чаму прыемліванні дапамагаюць, а не толькі тое, што дадзенне запускаецца. Зберагаюце логіку ў аднам сервісе, а не копіюйце яе на розных экранах:
notificationService.ts
Раздзеляйце типы прыемлівання на каналы або катэгоріі, напрыклад:
messages
orders
payments
security
marketing
Проектавайце пакеты дадзення для навігацыі, включаючы, як тое можліва, такія поля:
type
id
screen
Крэму таго:
- Праўяйце токены да аутентыфікованых корыстувальнікаў і прыстроёў, храніце іх абяцка і керуйце ўпэўненнямі.
- Не включайце чутлівую інфармацыю ў тэкст прыемлівання, адтак яна будзе видна за межамі дадзення.
- Тэставайце на рэальных прыстроях, адтак эмуляторы і сімуляторы можаць праявацца аднародна.
Заключэнне
Функцыональная система прыемлівання — гэта не проста адзін вызов, як
showNotification();
Это сумяжэнне ўсіх эйных аспектаў:
Permissions
+
Notification Channels
+
FCM Tokens
+
Foreground Handling
+
Background Handling
+
Notification Clicks
+
Deep Linking
+
Backend Integration
Ключовы момант — чыстая раздзеленасць абавяскаў. FCM дастаёна паведамленні. Аператывная система карыстаецца правамі і натыўным адображэнням. Notifee дае React Native кантроль над локальным адображэнням. Я ваш бэкенд вяршыць рашэнне, калі і што адправіць, і каму. Калі спаглядаць як адна система, ёй выглядае так:
┌─────────────────┐
│ Backend API │
└────────┬────────┘
│
▼
┌─────────────────┐
│ FCM │
└────────┬────────┘
│
┌────────┴────────┐
▼ ▼
┌───────────┐ ┌───────────┐
│ Android │ │ iOS │
│ Channel │ │ APNs │
└─────┬─────┘ └─────┬─────┘
│ │
└────────┬────────┘
▼
React Native
│
▼
Notifee
│
▼
Native UI
Калі гэтыя межы ўстановлены, паведамленні ведаюць ся прыемна як на Android, так і на iOS, а таксама ў станах фарграунда, бэкграунда і завершання.
Короткая інфармацыя
Запрашайце разрэшэнне на Android:
await PermissionsAndroid.request(
PermissionsAndroid.PERMISSIONS.POST_NOTIFICATIONS,
);
Запрашайце разрэшэнне на iOS:
await notifee.requestPermission();
Ствараеце канал на Android:
await notifee.createChannel({
id: 'messages',
name: 'Messages',
});
Адображаеце паведамленне:
await notifee.displayNotification({
title: 'New Message',
body: 'You have a new message.',
android: {
channelId: 'messages',
},
});
Аслухваецеся за паведамленнямі FCM у фарграундзе:
messaging().onMessage(async message => {
console.log(message);
});
Аслухваецеся за змянамі токена:
messaging().onTokenRefresh(token => {
console.log(token);
});
Адмініструванне аплікацыі паведамленняў, якія ачынаюцца з фону:
messaging().onNotificationOpenedApp(message => {
console.log(message.data);
});