react-native-noti-sdk
v0.3.2
Published
SDK lấy FCM token và nhận/hiển thị thông báo cho React Native (bọc @react-native-firebase/messaging + @notifee/react-native), hỗ trợ Android + iOS.
Maintainers
Readme
react-native-noti-sdk
SDK lấy FCM token và nhận/hiển thị thông báo UI tuỳ biến (ảnh + nút hành động) cho React Native, hỗ trợ cả Android và iOS.
Bọc quanh @react-native-firebase/messaging (FCM) và
@notifee/react-native (hiển thị), cộng native module
riêng cho custom UI.
1. Cài đặt
npm install react-native-noti-sdk
# + peer dependencies (BẮT BUỘC — chứa phần native)
npm install @react-native-firebase/app @react-native-firebase/messaging @notifee/react-nativeiOS:
cd ios && pod install2. Cấu hình Firebase
Tạo project trên Firebase Console.
2.1. Android
- Thêm Android app với đúng
applicationId. - Tải
google-services.json→ đặt tạiandroid/app/google-services.json. android/build.gradle(project-level) — thêm classpath:buildscript { dependencies { classpath("com.google.gms:google-services:4.4.2") } }android/app/build.gradle— áp plugin (gần đầu file):apply plugin: "com.google.gms.google-services"- Đảm bảo
compileSdkVersion >= 33(quyềnPOST_NOTIFICATIONSAndroid 13+).
2.2. iOS
- Thêm iOS app với đúng bundle ID.
- Tải
GoogleService-Info.plist→ kéo vào Xcode (tick Copy items if needed, chọn đúng Target). - Podfile — bật modular headers (Firebase cần khi link tĩnh):
target 'YourApp' do use_modular_headers! # ... end - Bật capability trong Xcode: Push Notifications và Background Modes → Remote notifications.
- Khởi tạo Firebase trong
AppDelegate.swift:import FirebaseCore // trong didFinishLaunchingWithOptions, trước khi start React Native: FirebaseApp.configure()
Chạy lại
cd ios && pod installsau khi đổi Podfile.
3. Đăng ký background handler (BẮT BUỘC)
Gọi ở top-level trong index.js, trước registerComponent:
// index.js
import { AppRegistry } from 'react-native';
import NotiSdk from 'react-native-noti-sdk';
import App from './App';
import { name as appName } from './app.json';
NotiSdk.registerBackgroundHandler();
AppRegistry.registerComponent(appName, () => App);4. Sử dụng cơ bản
import NotiSdk from 'react-native-noti-sdk';
async function setupPush() {
await NotiSdk.init({ debug: __DEV__ });
// Lấy FCM token gửi lên server
const token = await NotiSdk.getToken();
await sendTokenToServer(token);
// Token được làm mới
NotiSdk.onTokenRefresh(t => sendTokenToServer(t));
// Nhận message (foreground; cả background nếu đã registerBackgroundHandler)
NotiSdk.onMessage(msg => console.log('message:', msg.title, msg.data));
// Người dùng nhấn thông báo mở app (từ background)
NotiSdk.onNotificationOpened(msg => navigate(msg.data.screen));
// Thông báo mở app từ trạng thái đã tắt (quit) — gọi 1 lần lúc khởi động
const initial = await NotiSdk.getInitialNotification();
if (initial) navigate(initial.data.screen);
}5. Thông báo UI tuỳ biến (ảnh + nút)
await NotiSdk.displayCustomNotification({
title: 'Tiêu đề', // HTML cơ bản trên Android
body: 'Nội dung thông báo',
summary: 'Tên nhóm',
imageUrl: 'https://.../banner.jpg',
logoUrl: 'https://.../logo.png',
clickAction: 'yourapp://home', // mở khi nhấn thân thông báo
data: { screen: 'detail', id: '123' },
buttons: [
{ name: 'Gọi điện', type: 'phone', value: '0900000000' },
{ name: 'Mở', type: 'deep_link', value: 'yourapp://promo' },
],
});Loại nút (type)
| type | Hành vi khi nhấn |
| --- | --- |
| phone | Mở trình quay số với value. |
| deep_link / url | Mở URI value. |
| share | Mở hộp chia sẻ với nội dung value. |
| copy | Sao chép value vào clipboard (kèm toast xác nhận). |
Android giới hạn tối đa 3 nút.
- Android: native module; nút xử lý bởi
NotificationActionActivity(tự autolink, không cần cấu hình thêm). - iOS: native; nút xử lý trong AppDelegate (xem mục 6).
6. Cấu hình iOS để nút hoạt động (BẮT BUỘC trên iOS)
Thêm vào AppDelegate.swift:
import UserNotifications
import react_native_noti_sdk // module của SDK
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
private var previousNotifDelegate: UNUserNotificationCenterDelegate?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: ...) -> Bool {
FirebaseApp.configure()
// ... start React Native ...
// Giành delegate SAU khi RN/RNFB/Notifee đã set
let center = UNUserNotificationCenter.current()
previousNotifDelegate = center.delegate
center.delegate = self
return true
}
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
completionHandler([.banner, .sound, .badge])
previousNotifDelegate?.userNotificationCenter?(center, willPresent: notification) { _ in }
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
if RNNotiUiActionHandler.handle(response) { // action nút của NotiSdk
completionHandler()
return
}
if let prev = previousNotifDelegate { // còn lại -> RNFB/Notifee
prev.userNotificationCenter?(center, didReceive: response, withCompletionHandler: completionHandler)
} else {
completionHandler()
}
}
}Deep link mở app
Để nút deep_link (vd yourapp://...) mở app, khai báo URL scheme trong
ios/YourApp/Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array><string>yourapp</string></array>
</dict>
</array>Android: khai báo intent-filter cho scheme trong AndroidManifest.xml.
7. Gửi push từ server
Để custom UI hiển thị ở background/đã tắt, gửi data-only message (KHÔNG
kèm block notification), mọi giá trị là string:
{
"message": {
"token": "<FCM_TOKEN>",
"android": { "priority": "high" },
"data": {
"title": "Tiêu đề",
"body": "Nội dung",
"image": "https://.../banner.jpg",
"logo_url": "https://.../logo.png",
"click_action": "yourapp://home",
"summary": "Tóm tắt",
"buttons": "[{\"name\":\"Gọi\",\"type\":\"phone\",\"value\":\"0900000000\"},{\"name\":\"Mở\",\"type\":\"deep_link\",\"value\":\"yourapp://promo\"}]"
}
}
}SDK tự đọc các key: title, body, summary, image/imageUrl,
logo_url/logoUrl, click_action/clickAction, buttons. Nút hỗ trợ cả
format {name,type,value} lẫn {button_name,button_type,button_value}.
Đừng kèm block
notification— nếu có, Android tự hiện banner cơ bản và không gọi background handler (mất ảnh + nút).
iOS remote push ở killed: iOS không chạy JS khi app tắt hẳn. Để remote push hiện nút/ảnh ở background/killed cần thêm Notification Service Extension.
8. API
Khởi tạo & quyền
| Hàm | Mô tả |
| --- | --- |
| init(config?) | Khởi tạo SDK. Idempotent. |
| requestPermission() | Xin quyền → AuthorizationStatus. |
| hasPermission() | Trạng thái quyền hiện tại. |
FCM token
| Hàm | Mô tả |
| --- | --- |
| getToken() | FCM token (string) hoặc null. |
| deleteToken() | Xoá token hiện tại. |
| onTokenRefresh(listener) | Lắng nghe token mới → unsubscribe. |
Nhận & hiển thị
| Hàm | Mô tả |
| --- | --- |
| registerBackgroundHandler() | Nhận message ở background. Gọi tại index.js. |
| onMessage(handler) | Nhận NotiMessage → unsubscribe. |
| onNotificationOpened(handler) | Khi tap thông báo mở app → unsubscribe. |
| getInitialNotification() | Thông báo mở app từ quit, hoặc null. |
| displayNotification(options) | Local notification cơ bản. |
| displayCustomNotification(options) | Custom UI (ảnh + nút). |
| displaySimpleNotification(title, body) | Thông báo đơn giản. |
| resetBadge() | Đặt badge về 0. |
| isIgnoringBatteryOptimizations() | Android: có được miễn tối ưu pin? iOS: true. |
| requestIgnoreBatteryOptimizations() | Android: mở màn hình xin miễn tối ưu pin. |
| isCustomUiAvailable() | Native module custom UI có khả dụng không. |
NotiSdkConfig
| Trường | Mặc định | Mô tả |
| --- | --- | --- |
| requestPermissionOnInit | true | Tự xin quyền khi init(). |
| debug | false | Log [NotiSdk]. |
| defaultChannel | { id:'default', name:'Mặc định', importance:'high' } | Channel Android. |
| displayInForeground | true | Tự hiện banner khi nhận message lúc app mở. |
Kiểu dữ liệu
type AuthorizationStatus = 'authorized' | 'provisional' | 'denied' | 'notDetermined';
type NotiButtonType = 'phone' | 'deep_link' | 'url' | 'share' | 'copy';
interface NotiButton { name: string; type: NotiButtonType; value: string }
interface NotiMessage {
id?: string; title?: string; body?: string;
data: Record<string, string>;
}
interface CustomNotificationOptions {
id?: string | number;
title: string;
body: string;
summary?: string;
channelId?: string;
imageUrl?: string;
logoUrl?: string;
clickAction?: string;
fullScreen?: boolean; // Android: full-screen intent
buttons?: NotiButton[];
data?: Record<string, string>;
}9. Checklist tích hợp nhanh
- [ ]
npm install react-native-noti-sdk+ 3 peer deps - [ ]
cd ios && pod install - [ ] Android:
google-services.json+ plugin gms trong 2 file gradle - [ ] iOS:
GoogleService-Info.plist+FirebaseApp.configure()+ capability Push +use_modular_headers! - [ ]
NotiSdk.registerBackgroundHandler()trongindex.js - [ ] iOS: UNUserNotificationCenter delegate +
RNNotiUiActionHandler.handletrong AppDelegate - [ ] iOS:
CFBundleURLTypescho deep link scheme - [ ] Gọi
NotiSdk.init(), lấy token gửi server - [ ] Server gửi data-only message cho custom UI ở background
10. Lỗi thường gặp
| Triệu chứng | Nguyên nhân / cách sửa |
| --- | --- |
| No Firebase App '[DEFAULT]' | Thiếu FirebaseApp.configure() (iOS) hoặc plugin gms + google-services.json (Android). |
| iOS: không thấy GoogleService-Info.plist | Chưa add plist vào Xcode target (đừng chỉ kéo vào Finder). |
| messaging/unregistered (iOS) | Kiểm tra capability Push + provisioning. |
| Simulator iOS không có token | APNS không chạy trên simulator — test thiết bị thật. |
| Background không hiện ảnh/nút | Payload có kèm block notification (phải data-only) hoặc ảnh quá lớn. |
| Nút iOS không chạy | Chưa thêm delegate + RNNotiUiActionHandler.handle vào AppDelegate. |
| Deep link không mở app | Chưa khai báo URL scheme (CFBundleURLTypes iOS / intent-filter Android). |
License
MIT
