@hackbou/push-notification
v0.2.0
Published
SDK client Push Notification pour React Native / Expo — enregistrement appareil et liaison utilisateur
Maintainers
Readme
@hackbou/push-notification
SDK client TypeScript pour React Native et Expo.
Il enregistre le token push auprès de votre API Push Notification et lie
l’appareil à un utilisateur (external_id). Il ne récupère pas le token
FCM / APNs / Expo lui-même : vous fournissez getPushToken.
Dépôt : hardhacklife/push-notification-react-native-sdk
Prérequis
- React Native ≥ 0.72 (ou Expo SDK compatible)
- React ≥ 18
- Une clé API serveur avec le scope d’écriture appareils (jamais une clé admin)
- Un provider de token :
expo-notifications,@react-native-firebase/messaging, etc.
Optionnel mais recommandé :
npm install @react-native-async-storage/async-storageSans AsyncStorage, le SDK stocke deviceId / externalId en mémoire
(perdus au kill de l’app).
Installation
npm install @hackbou/push-notificationyarn add @hackbou/push-notificationpnpm add @hackbou/push-notificationDémarrage rapide (Expo)
import { Platform } from 'react-native'
import * as Notifications from 'expo-notifications'
import { PushNotification } from '@hackbou/push-notification'
async function setupPush() {
await PushNotification.initialize({
apiKey: process.env.EXPO_PUBLIC_PUSH_NOTIFICATION_API_KEY!,
baseUrl: process.env.EXPO_PUBLIC_PUSH_NOTIFICATION_URL!, // sans slash final
platform: Platform.OS === 'ios' ? 'ios' : 'android',
getPushToken: async () => {
const { status } = await Notifications.requestPermissionsAsync()
if (status !== 'granted') return null
const token = await Notifications.getExpoPushTokenAsync()
return token.data
},
})
const device = await PushNotification.register()
const user = await PushNotification.login('student_123')
await PushNotification.setTags({ language: 'fr' })
console.log(device.id, user.external_id)
}Expo Go a des limites pour le push réel. Préférez un development build ou un build store pour valider FCM / APNs.
React Native (Firebase)
import { Platform } from 'react-native'
import messaging from '@react-native-firebase/messaging'
import { PushNotification } from '@hackbou/push-notification'
await PushNotification.initialize({
apiKey: 'pf_live_…',
baseUrl: 'https://push.example.com',
platform: Platform.OS === 'ios' ? 'ios' : 'android',
getPushToken: async () => messaging().getToken(),
})
await PushNotification.register()
await PushNotification.login('user_42')
// Brancher l’ouverture de notif depuis Firebase
messaging().onNotificationOpenedApp((remoteMessage) => {
PushNotification.notifyOpened({
title: remoteMessage.notification?.title,
body: remoteMessage.notification?.body,
data: remoteMessage.data ?? {},
})
})
PushNotification.onNotificationOpened((n) => {
// navigation selon n.data
})Configuration (initialize)
| Option | Type | Requis | Description |
|--------|------|--------|-------------|
| apiKey | string | oui | Clé API (pf_live_…) |
| baseUrl | string | oui | URL de l’API, sans / final |
| platform | 'ios' \| 'android' \| 'web' | oui | Plateforme de l’appareil |
| getPushToken | () => Promise<string \| null> | oui | Fournit le token natif / Expo |
| timeoutMs | number | non | Timeout HTTP (défaut 15000) |
Appeler initialize une seule fois au démarrage (après auth app si besoin).
API publique
Surface stable — ne pas casser sans major version.
| Méthode | Retour | Description |
|---------|--------|-------------|
| initialize(config) | Promise<void> | Configure le client + storage |
| isInitialized() | boolean | true si initialize a réussi |
| register() | Promise<Device> | POST /v1/devices — enregistre / met à jour le token |
| login(externalId) | Promise<User> | POST /v1/users/{id}/login — lie l’appareil ; auto-register si besoin |
| setTags(tags) | Promise<Record<string, string>> | PUT /v1/users/{id}/tags — nécessite un login préalable |
| unregister() | Promise<Device \| null> | DELETE /v1/devices/{id} — désabonne l’appareil local |
| logout() | Promise<void> | Efface l’externalId local (pas d’appel API) |
| getDeviceId() | Promise<string \| null> | Id appareil stocké localement |
| getExternalId() | Promise<string \| null> | Utilisateur lié localement |
| onNotificationOpened(fn) | () => void | Abonne un handler ; retourne unsubscribe |
| notifyOpened(payload) | void | À appeler depuis le bridge natif (Firebase / Notifee / Expo) |
Types exportés
import {
PushNotification,
PushNotificationError,
type PushNotificationConfig,
type Device,
type User,
type Platform,
type OpenedNotification,
} from '@hackbou/push-notification'Erreurs
Toutes les erreurs SDK sont des PushNotificationError :
| code | Signification |
|--------|----------------|
| not_initialized | initialize() non appelé |
| validation | Paramètre manquant / invalide |
| missing_token | getPushToken() a renvoyé vide |
| not_logged_in | setTags sans login |
| timeout | Délai HTTP dépassé |
| network | Erreur réseau |
| http_error / code API | Réponse HTTP d’erreur |
| invalid_response | JSON inattendu (ex. sans id) |
import { PushNotification, PushNotificationError } from '@hackbou/push-notification'
try {
await PushNotification.register()
} catch (e) {
if (e instanceof PushNotificationError) {
console.error(e.code, e.status, e.message)
}
}Flux recommandé
- Demander les permissions push (Expo / Firebase / système).
initialize({ apiKey, baseUrl, platform, getPushToken }).register()au premier lancement (et quand le token change).- Après login app métier :
login(externalId)avec le même id que votre backend. - Optionnel :
setTags({ … })pour le ciblage. - Brancher
notifyOpeneddepuis le listener natif d’ouverture.
Sans register + login côté mobile, le backend qui envoie à un external_id
n’aura personne à joindre (recipients = 0).
Sécurité (production)
- Clé API mobile limitée (
devices:write) — jamais une clé admin. - Aucun credential FCM / APNs /
.p8dans l’app. - Ne loggez pas la clé API ni le token push complet.
- Les réponses sont validées (
idrequis) avant écriture en storage local.
Développement local
git clone https://github.com/hardhacklife/push-notification-react-native-sdk.git
cd push-notification-react-native-sdk
npm install
npm test
npm run typecheck
npm run buildLicence
Apache-2.0 © hackbou
