Entwickler · API v1.0.0
Expo-Integration
Dieser Leitfaden richtet sich an Apps, die mit Expo (Managed Workflow oder Development Build) entwickelt werden. Die allgemeine API-Referenz finden Sie in der Überblick.
Unterstützte Versionen: Expo SDK 50+ (empfohlen: aktuelles SDK) · iOS 13.4+ · Android 7.0+ (API 24)
Remote-Push-Benachrichtigungen funktionieren nicht in Expo Go (unter Android seit SDK 53 entfernt). Verwenden Sie zum Testen einen Development Build oder einen mit EAS Build erstellten Build. Push-Benachrichtigungen sollten nicht im Emulator/Simulator, sondern auf einem physischen Gerät getestet werden.
1. Installation
npx expo install expo-notifications expo-device expo-constants expo-secure-store expo-localization expo-crypto
app.json / app.config.js:
{
"expo": {
"plugins": [
["expo-notifications", { "defaultChannel": "default" }]
],
"extra": {
"eas": { "projectId": "IHRE-EAS-PROJEKT-ID" }
}
}
}
Laden Sie die Push-Zugangsdaten in Ihr Expo-Projekt hoch (einmalig):
eas credentials # Android: JSON des FCM-V1-Dienstkontos, iOS: APNs Key
2. NotiPilot-Client
src/notipilot.ts:
import * as Notifications from 'expo-notifications';
import * as Device from 'expo-device';
import * as SecureStore from 'expo-secure-store';
import * as Localization from 'expo-localization';
import * as Crypto from 'expo-crypto';
import Constants from 'expo-constants';
import { Platform } from 'react-native';
const NOTIPILOT_BASE_URL = 'https://app.notipilot.com/api/v1';
// Muss mit der "Expo Project ID" im NotiPilot-Dashboard übereinstimmen
const PROJECT_ID: string =
Constants.expoConfig?.extra?.eas?.projectId ?? Constants.easConfig?.projectId;
const DEVICE_UID_KEY = 'notipilot_device_uid';
// Unter SDK 52 und älter statt shouldShowBanner/shouldShowList shouldShowAlert: true verwenden
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowBanner: true,
shouldShowList: true,
shouldPlaySound: true,
shouldSetBadge: false,
}),
});
async function getDeviceUid(): Promise<string> {
let uid = await SecureStore.getItemAsync(DEVICE_UID_KEY);
if (!uid) {
uid = Crypto.randomUUID();
await SecureStore.setItemAsync(DEVICE_UID_KEY, uid);
}
return uid;
}
async function post(path: string, body: object, attempt = 0): Promise<any> {
const res = await fetch(`${NOTIPILOT_BASE_URL}${path}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify(body),
});
const json = await res.json().catch(() => ({}));
if ((res.status === 429 || res.status >= 500) && attempt < 3) {
const waitSec = Number(json.retry_after) || 2 ** attempt;
await new Promise((r) => setTimeout(r, waitSec * 1000));
return post(path, body, attempt + 1);
}
if (!res.ok) {
console.warn('[NotiPilot]', res.status, json.error, json.errors ?? json.message);
}
return json;
}
async function getExpoPushToken(): Promise<string | null> {
if (!Device.isDevice) return null;
if (Platform.OS === 'android') {
await Notifications.setNotificationChannelAsync('default', {
name: 'Allgemein',
importance: Notifications.AndroidImportance.HIGH,
});
}
let { status } = await Notifications.getPermissionsAsync();
if (status !== 'granted') {
({ status } = await Notifications.requestPermissionsAsync());
}
if (status !== 'granted') return null;
const { data } = await Notifications.getExpoPushTokenAsync({ projectId: PROJECT_ID });
return data; // "ExponentPushToken[...]"
}
export type NotiPilotAttributes = Record<string, string | number | boolean | null>;
/** Bei jedem App-Start aufrufen. */
export async function registerDevice(extra: NotiPilotAttributes = {}) {
const token = await getExpoPushToken();
if (!token) return null;
const locale = Localization.getLocales()[0];
return post('/register-device', {
app_id: PROJECT_ID,
device_uid: await getDeviceUid(),
token,
platform: Platform.OS, // 'ios' | 'android'
provider: 'expo',
attributes: {
locale: locale?.languageCode ?? null, // "tr"
country: locale?.regionCode ?? null, // "TR"
app_version: Constants.expoConfig?.version ?? null,
...extra, // z. B. { city: 'Istanbul' }
},
});
}
/** Aufrufen, wenn sich der Nutzer anmeldet. */
export async function identify(externalId: string, attributes?: NotiPilotAttributes) {
return post('/identify-device', {
app_id: PROJECT_ID,
device_uid: await getDeviceUid(),
external_id: externalId,
...(attributes ? { attributes } : {}),
});
}
/** Aufrufen, wenn sich der Nutzer abmeldet. */
export async function logout() {
const token = await getExpoPushToken();
if (!token) return null;
return post('/register-device', {
app_id: PROJECT_ID,
device_uid: await getDeviceUid(),
token,
platform: Platform.OS,
external_id: null,
});
}
/** Hält NotiPilot bei Token-Erneuerung aktuell. Einmal beim App-Start aufrufen. */
export function listenForTokenChanges() {
return Notifications.addPushTokenListener(() => {
registerDevice().catch(() => {});
});
}
3. Verwendung
import { useEffect } from 'react';
import * as Notifications from 'expo-notifications';
import { registerDevice, listenForTokenChanges, identify } from './src/notipilot';
export default function App() {
useEffect(() => {
registerDevice({ city: 'Istanbul' }).catch(console.warn);
const tokenSub = listenForTokenChanges();
// Beim Tippen auf die Benachrichtigung das vom Dashboard gesendete Feld `data` auslesen
const tapSub = Notifications.addNotificationResponseReceivedListener((response) => {
const data = response.notification.request.content.data;
// z. B. data.screen === 'product' → navigation.navigate('Product', { id: data.product_id })
});
return () => {
tokenSub.remove();
tapSub.remove();
};
}, []);
// Nach dem Login: await identify(user.id, { gender: user.gender });
return null;
}
4. Checkliste
- Expo Project ID im Dashboard =
extra.eas.projectId - FCM-V1- und APNs-Zugangsdaten mit
eas credentialshochgeladen - Auf einem physischen Gerät mit Development-/Production-Build getestet
-
countryund nach Möglichkeitcitywerden gesendet (für Standortsegmente) - Nach dem Login wird
identify, beim Logoutlogoutaufgerufen
Häufige Probleme
| Symptom | Lösung |
|---|---|
404 unknown_app |
app_id ist im Dashboard nicht registriert oder falsch. Prüfen Sie die Expo Project ID im Dashboard. |
| Token kann nicht abgerufen werden | Verwenden Sie ein physisches Gerät, prüfen Sie die Benachrichtigungsberechtigung und stellen Sie sicher, dass Sie den Parameter projectId übergeben. |
| Registrierung erfolgreich, aber keine Benachrichtigung | Im Expo-Projekt fehlen möglicherweise die FCM-V1- / APNs-Zugangsdaten. Senden Sie mit dem Expo-Push-Tool eine Testbenachrichtigung an den Token. |
| Benachrichtigungen kommen unter Android stumm an | Legen Sie einen Benachrichtigungskanal mit der ID default und der Wichtigkeitsstufe HIGH an. |