React Native SDK
@opennotification/react-native iOS ve Android'i tek JavaScript API'sinden kapsar ve native tarafın tamamı paketin içinde gelir: @react-native-firebase/* yok, Notifee yok, AsyncStorage yok. iOS native bir modülle doğrudan APNs'e konuşur — Firebase iOS SDK'sı yok. Android, Kotlin SDK'yı Firebase Messaging üzerinde gömülü çalıştırır ve her bildirimi kendisi çizer; Firebase Messaging npm'den değil Gradle'dan gelir.
1 Kur
bun add @opennotification/react-native
Sonra birini seçin: Expo plugin ya da elle kurulum.
2 Başlat
import { OpenNotification } from "@opennotification/react-native";
await OpenNotification.init({
endpoint: "https://push.example.com",
appKey: "pk_live_…",
autoRegister: false, // true: init sırasında izin iste
androidSmallIcon: "ic_notification", // drawable adı, tek renkli
});
init native dinleyicileri bağlar ve Android'de FCM token'ını alıp hemen kaydeder (token almak için izin gerekmez). iOS'ta izin verilene kadar hiçbir şey gönderilmez. index.js'e kaydedilecek bir arka plan handler'ı yok: çizim ve takip native olduğu için FCM'in süreci içinde JavaScript olmadan uyandırması sorun değil.
3 İzin, kimlik, tag'ler, açılmalar
const result = await OpenNotification.requestPermission();
if (!result.ok) console.warn(result.error.code); // permission_denied | no_token | api_error | network_error
await OpenNotification.login("user_123");
await OpenNotification.setTags({ plan: "platinum", streak: 42 });
const off = OpenNotification.onOpen((message) => {
navigate(message.data.screen ?? "Home", message.data); // message.url, message.actionId de var
});
OpenNotification.onReceive((message) => {
if (message.silent) sync(message.data); // arka plan push'u: bir şey gösterilmedi, mesaj data'dır
});
await OpenNotification.logout();
await OpenNotification.unsubscribe();
await OpenNotification.trackSession(); // isteğe bağlı; AppState "active" bunu kendiliğinden yapar
onOpen soğuk açılışta da tetiklenir: native taraf basışı JavaScript hazır olana kadar tutar.
Oturumlar sizin için sayılır: start() AppState'i dinler ve her ön plana dönüşte /session'a ping atar; sunucu 30 dakika boşluk kuralını uygular, çift sayım olmaz. Sessiz push'lar onReceive'e message.silent === true ile gelir — iOS'ta application(_:didReceiveRemoteNotification:fetchCompletionHandler:)'ı OpenNotification.didReceiveBackground(userInfo:)'ya iletin (aşağıdaki AppDelegate) ve Remote notifications background mode'unu açın.
await OpenNotification.permissionStatus() granted | denied | provisional | not_determined döner; OpenNotification.register() kaydı açıkça yeniden gönderir.
removeTags / setLanguage için alttaki istemciyi kullanın: const client = await OpenNotification.init(…); client.removeTags(["streak"]).
Expo config plugin
{
"expo": {
"ios": { "bundleIdentifier": "com.acme.app" },
"android": { "googleServicesFile": "./google-services.json" },
"plugins": [
["@opennotification/react-native", {
"endpoint": "https://push.example.com",
"androidSmallIconPath": "./assets/ic_notification.png"
}]
]
}
}
npx expo prebuild (ya da EAS build) aşağıdaki elle kurulumun listelediği her şeyi uygular:
| Platform | Plugin ne yapar |
|---|---|
| iOS | aps-environment entitlement'ı, remote-notification arka plan modu, dört AppDelegate callback'i, Info.plist'inde OpenNotificationApiUrl = endpoint olan bir NotificationService extension hedefi. |
| Android | POST_NOTIFICATIONS izni, androidSmallIconPath'i res/drawable/ic_notification.png'ye kopyalar. google-services.json ve Gradle eklentisi Expo'nun kendi android.googleServicesFile'ından gelir. |
| Seçenek | Varsayılan | |
|---|---|---|
endpoint | — | Extension için API taban URL'si. |
iosServiceExtension | true | Extension'ı atlamak için false (o zaman iOS'ta delivered yok). |
iosServiceExtensionName | NotificationService | Hedef adı; bundle id <bundleIdentifier>.<ad>. |
iosDeploymentTarget | uygulamanınki | |
iosApsEnvironment | development | EAS build sırasında doğrusunu koyar. |
androidSmallIconPath | — | Tek renkli PNG, saydam üzerine beyaz. |
androidSmallIcon | ic_notification | Yukarıdaki PNG'nin drawable adı. |
Sizde kalanlar: extension'ın App ID'si ve profili (com.acme.app.NotificationService) — ya da extra.eas.build.experimental.ios.appExtensions ile EAS'a bırakın — ve .p8 yüklemesi (iOS platform kurulumu). Plugin Expo SDK 53+'ın Swift AppDelegate'ini yamalar ve aynı bildirim delegate'ini sahiplenen expo-notifications ile birlikte çalışmaz.
Elle kurulum (bare React Native)
Android
1 android/app/ içinde google-services.json ve Gradle eklentisi — Android platform kurulumu. Firebase Messaging paketin Gradle modülüyle gelir; dependencies'e bir şey eklemeyin.
2 android/app/src/main/res/drawable/ic_notification.png konumunda tek renkli durum çubuğu simgesi (saydam üzerine beyaz), androidSmallIcon olarak verilir. Android başka her şeyi gri kare çizer.
3 Android 13+: requestPermission() POST_NOTIFICATIONS ister; izni modülün manifest'i bildirir.
Autolinking modülü bir sonraki build'de alır. Zaten bir FirebaseMessagingService'iniz var mı? onNewToken ve onMessageReceived'i Kotlin SDK'nın anlattığı gibi iletin — aynı kod.
iOS
1 cd ios && pod install.
2 Xcode → uygulama hedefi → Signing & Capabilities → Push Notifications ve Background Modes → Remote notifications ekleyin.
3 AppDelegate'ten dört callback'i iletin. Swift:
import OpenNotification
import UserNotifications
// application(_:didFinishLaunchingWithOptions:) içinde
UNUserNotificationCenter.current().delegate = self
OpenNotification.setLaunchNotification(launchOptions?[.remoteNotification] as? [AnyHashable: Any])
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
OpenNotification.didRegister(deviceToken: deviceToken)
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
OpenNotification.didFailToRegister(error: error)
}
extension AppDelegate: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
OpenNotification.didReceive(response: response)
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
OpenNotification.willPresent(notification: notification)
completionHandler([.banner, .sound, .badge])
}
}
Objective-C AppDelegate.mm: #import "YourApp-Swift.h" ve aynı dört OpenNotification sınıf metodunu çağırın.
Bunlar olmadan izin verilir, token hiç gelmez ve requestPermission() no_token ile döner.
4 Notification Service Extension — iOS'ta delivered, görsel ve buton için zorunlu:
- File → New → Target… → Notification Service Extension, adı
NotificationService, deployment target = uygulamanınki. NotificationService.swift'ininode_modules/@opennotification/react-native/ios/NotificationServiceExtension/NotificationService.swiftile değiştirin.- Extension'ın
Info.plist'ine StringOpenNotificationApiUrl= API taban URL'niz ekleyin. - Kendi App ID / profilini verin (
com.acme.app.NotificationService).
5 .p8'i yükleyin — iOS platform kurulumu.
Ne neyi bildirir
| Olay | iOS | Android |
|---|---|---|
delivered | Notification Service Extension | FirebaseMessagingService (native) |
opened | didReceive response → native modül | NotificationReceiver (native) |
clicked (buton) | action identifier'lı didReceive | buton id'li NotificationReceiver |
dismissed | iOS'ta yok | NotificationReceiver (native) |
Android'de her ping native gönderilir — FCM süreci içinde JavaScript olmadan uyandırabilir — JavaScript istemcisi olayları yalnızca dinleyicilerinize iletir. iOS'ta açılmaları istemci kendisi bildirir.
Notlar
- Mesajlar normalize edilir: APNs
onbloğu ve FCM düzdata, ikisi de tekOpenNotificationMessageolarak gelir. @opennotification/core'dan yalnızca tipler içe aktarılır — sunucudan hiçbir şey bundle'ınıza girmez.- Abonelik kimliği UserDefaults / SharedPreferences'ta durur. Uygulama kalıcılığı kendi yönetmek isterse
createClient'a kendistorage'ınızı verin; hiç native modül yokken (testler) bellekte kalır ve cihaz bir sonraki açılışta yeniden kaydolur, bu da aynı satırı token'a göre upsert eder.