| name | expo-notifications |
| description | expo-notifications kurulumu, push token, FCM + APNs credentials, kategoriler, scheduled notifications, channels ve permission flow. Triggers on expo-notifications, push notification, fcm, apns, push token, notification permission, notification channel, notification category, action button, scheduled notification, local notification, badge, silent push. |
| license | MIT |
| compatibility | Works with Claude Code |
| allowed-tools | Read Write Edit Bash Grep |
| metadata | {"author":"badi","badi-version":">=1.27.0","category":"expo","scope":"advisory"} |
expo-notifications
expo-notifications ile push ve local notification kurulumu. iOS (APNs) + Android (FCM) credentials, permission flow, channels (Android 8+), categories ve scheduled notifications.
Ne Yapar
expo-notifications setup ve permission istegi
- Expo Push Token alma + backend'e gonderme
- iOS APNs Auth Key ve Android FCM Service Account
- Notification categories + action buttons
- Scheduled / repeating notifications
- Channels (Android 8+) ve importance levels
- Background notification handler ve silent push
Kurulum
npx expo install expo-notifications expo-device expo-constants
app.json:
{
"expo": {
"plugins": [
["expo-notifications", {
"icon": "./assets/notification-icon.png",
"color": "#ffffff",
"sounds": ["./assets/notification-sound.wav"]
}]
],
"ios": {
"infoPlist": {
"UIBackgroundModes": ["remote-notification"]
}
},
"android": {
"googleServicesFile": "./google-services.json"
}
}
}
Permission + Token
import * as Notifications from "expo-notifications";
import * as Device from "expo-device";
import Constants from "expo-constants";
import { Platform } from "react-native";
Notifications.setNotificationHandler({
handleNotification: async () => ({
shouldShowAlert: true,
shouldPlaySound: true,
shouldSetBadge: true,
}),
});
export async function registerForPushNotificationsAsync(): Promise<string | undefined> {
if (!Device.isDevice) {
console.warn("Push notifications require a physical device");
return;
}
if (Platform.OS === "android") {
await Notifications.setNotificationChannelAsync("default", {
: ,
: ..,
: [, , , ],
: ,
});
}
{ : existing } = .();
finalStatus = existing;
(existing !== ) {
{ status } = .();
finalStatus = status;
}
(finalStatus !== ) ;
projectId = .?.?.?.;
token = ( .({ projectId })).;
token;
}
iOS APNs Credentials
EAS uzerinden:
eas credentials -p ios
App Store Connect > Keys > APNs Auth Key:
- Tek key tum app'lerde kullanilabilir
- Bir kez indirilebilir — yedek tut
Android FCM Credentials
app.json:
{
"android": { "googleServicesFile": "./google-services.json" }
}
google-services.json .gitignore'a EKLE (commit etme; EAS Secrets veya CI'da inject).
Local & Scheduled Notification
await Notifications.scheduleNotificationAsync({
content: { title: "Test", body: "Hello", sound: true },
trigger: null,
});
await Notifications.scheduleNotificationAsync({
content: { title: "Hatirla", body: "Su iciver" },
trigger: { seconds: 60 },
});
await Notifications.scheduleNotificationAsync({
content: { title: "Sabah" },
trigger: { hour: 9, minute: 0, repeats: true },
});
await Notifications.scheduleNotificationAsync({
content: { title: "Pazartesi" },
trigger: { weekday: 2, hour: 9, minute: 0, repeats: },
});
Categories + Action Buttons
await Notifications.setNotificationCategoryAsync("message", [
{
identifier: "reply",
buttonTitle: "Yanitla",
textInput: { submitButtonTitle: "Gonder", placeholder: "Mesaj..." },
},
{
identifier: "mark_read",
buttonTitle: "Okundu",
options: { opensAppToForeground: false },
},
]);
await Notifications.scheduleNotificationAsync({
content: { title: "Yeni mesaj", body: "...", categoryIdentifier: "message" },
trigger: null,
});
Action handler:
Notifications.addNotificationResponseReceivedListener((response) => {
const action = response.actionIdentifier;
const userInput = (response as any).userText;
});
Android Channels (8+)
await Notifications.setNotificationChannelAsync("messages", {
name: "Mesajlar",
importance: Notifications.AndroidImportance.HIGH,
vibrationPattern: [0, 250, 250, 250],
lightColor: "#FF231F7C",
sound: "default",
});
await Notifications.setNotificationChannelAsync("silent", {
name: "Sessiz bildirimler",
importance: Notifications.AndroidImportance.LOW,
});
Android 8+ icin channel ZORUNLU. Channel yoksa bildirim gosterilmez.
Push Gonderme (Expo Push Service)
curl -X POST https://exp.host/--/api/v2/push/send \
-H "Content-Type: application/json" \
-d '{
"to": "ExponentPushToken[xxx]",
"title": "Selam",
"body": "Test",
"sound": "default",
"categoryId": "message",
"data": { "screen": "/posts/42" }
}'
Backend SDK: expo-server-sdk (Node.js).
Deep Link via Notification
const responseListener = Notifications.addNotificationResponseReceivedListener((res) => {
const path = res.notification.request.content.data?.screen;
if (path) router.push(path);
});
Best Practices
- Permission isteme zamanlamasi: feature gerektiginde, app acilir acilmaz degil
- Channel'lar her zaman setup (Android 8+)
- Silent push badge update icin (
contentAvailable: true)
- Token yenilenmesini dinle:
addPushTokenListener
- Backend'de token sakla (user + device key)
- Test cihazi: gercek cihaz zorunlu (simulator push almaz)
- Sound dosyalari plugin'de tanimla, build'e gomulsun
Sik Hata Kaliplari
- iOS push gelmiyor: APNs Auth Key eksik, capability "Push Notifications" yok
- Android push gelmiyor:
google-services.json eksik, FCM Service Account yanlis
- Channel yok → Android 8+ sessiz reddediyor
UIBackgroundModes: ["remote-notification"] yok → silent push gelmez
- Production'da
Notifications.scheduleNotificationAsync trigger: null yerine { seconds: 1 } → daha guvenli
- Permission request flood → kullanici reddeder, bir daha ac demek soyle
Hard Refusal
- Kullanici onayi olmadan permission abuse (her saat sor)
- Spam/yaniltici push iceriği (ASC + Play Store kurali)
- Health/finance verisini sifresiz push payload'da gondermek
- Marketing push'u opt-out olmadan zorunlu kilmak
- Tracking ID'sini push token ile cross-reference etmek (GDPR)
Cikti Formati
- Kurulum komutlari (kopya-yapistir)
- Permission flow kodu
- iOS + Android credentials adimlari
- Channel ve category setup
- Test komutu (curl)
- Risk: permission abuse, store kurali