Push Notification: FCM ve APNs Entegrasyonu
Push Notification Nedir ve Neden Önemlidir?
Push notification, mobil uygulamaların kullanıcılarına uygulama açık olmasa bile anlık bildirimler göndermesini sağlayan bir iletişim mekanizmasıdır. Kullanıcı etkileşimini artırmak, kritik bilgileri zamanında iletmek ve uygulama retansiyon oranlarını yükseltmek için vazgeçilmez bir araçtır. Bu yazıda, Android tarafında Firebase Cloud Messaging (FCM) ve iOS tarafında Apple Push Notification service (APNs) entegrasyonunu detaylı şekilde inceleyeceğiz.
Mimari Genel Bakış
Push notification sistemi temel olarak üç katmandan oluşur:
- Uygulama (Client): Kullanıcının cihazında çalışan mobil uygulama. Bildirim almak için platforma özel bir token üretir.
- Uygulama Sunucusu (Backend): Bildirimleri tetikleyen ve platform servislerine ileten sunucu tarafı.
- Platform Servisi: FCM (Google) veya APNs (Apple) gibi bildirimi son kullanıcıya ulaştıran aracı servis.
Akış şu şekilde işler: Client bir device token alır → Bu token backend'e kaydedilir → Backend, bildirim göndermek istediğinde bu token ile FCM veya APNs'e istek atar → Platform servisi bildirimi cihaza iletir.
Firebase Cloud Messaging (FCM) Entegrasyonu
Android Tarafı Kurulum
FCM entegrasyonu için öncelikle Firebase projenizi oluşturmanız ve google-services.json dosyasını Android projenize eklemeniz gerekir. Ardından gerekli bağımlılıkları ekleyin:
// build.gradle (app level)
dependencies {
implementation platform('com.google.firebase:firebase-bom:33.7.0')
implementation 'com.google.firebase:firebase-messaging'
}
Ardından, FCM token'ını almak ve gelen bildirimleri işlemek için bir servis sınıfı oluşturmanız gerekir:
class MyFirebaseMessagingService : FirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
// Token'ı backend sunucunuza gönderin
sendTokenToServer(token)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
remoteMessage.notification?.let { notification ->
showNotification(notification.title, notification.body)
}
// Data payload varsa işleyin
if (remoteMessage.data.isNotEmpty()) {
handleDataPayload(remoteMessage.data)
}
}
private fun showNotification(title: String?, body: String?) {
val channelId = "default_channel"
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
channelId, "Varsayılan Kanal",
NotificationManager.IMPORTANCE_HIGH
)
manager.createNotificationChannel(channel)
}
manager.notify(System.currentTimeMillis().toInt(), notificationBuilder.build())
}
}
AndroidManifest.xml dosyasına servisi kaydetmeyi unutmayın:
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Backend'den FCM ile Bildirim Gönderme
Sunucu tarafında FCM HTTP v1 API kullanarak bildirim gönderebilirsiniz. Aşağıda Node.js ile bir örnek verilmiştir:
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.cert('./serviceAccountKey.json'),
});
async function sendPushNotification(deviceToken, title, body, data = {}) {
const message = {
token: deviceToken,
notification: {
title: title,
body: body,
},
data: data,
android: {
priority: 'high',
notification: {
click_action: 'OPEN_ACTIVITY',
channel_id: 'default_channel',
},
},
};
try {
const response = await admin.messaging().send(message);
console.log('Bildirim gönderildi:', response);
} catch (error) {
console.error('Bildirim gönderilemedi:', error);
}
}
Apple Push Notification service (APNs) Entegrasyonu
iOS Tarafı Kurulum
APNs entegrasyonu için öncelikle Apple Developer hesabınızdan Push Notification capability'sini etkinleştirmeniz ve bir APNs anahtarı (p8) veya sertifikası (p12) oluşturmanız gerekir. Xcode projenizde Signing & Capabilities sekmesinden "Push Notifications" ekleyin.
import UserNotifications
import UIKit
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
UNUserNotificationCenter.current().delegate = self
UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .badge, .sound]
) { granted, error in
if granted {
DispatchQueue.main.async {
application.registerForRemoteNotifications()
}
}
}
return true
}
func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
print("APNs Device Token: \(token)")
// Token'ı backend'e gönderin
sendTokenToServer(token)
}
func application(
_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error
) {
print("APNs kayıt hatası: \(error.localizedDescription)")
}
// Uygulama açıkken gelen bildirimler
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .badge, .sound])
}
}
Backend'den APNs ile Bildirim Gönderme
APNs'e doğrudan HTTP/2 üzerinden bildirim göndermek için token tabanlı kimlik doğrulama (p8 anahtarı) kullanabilirsiniz. Aşağıda Node.js ile bir örnek verilmiştir:
const apn = require('apn');
const apnProvider = new apn.Provider({
token: {
key: './AuthKey_XXXXXXXXXX.p8',
keyId: 'YOUR_KEY_ID',
teamId: 'YOUR_TEAM_ID',
},
production: true, // Sandbox için false yapın
});
function sendAPNsNotification(deviceToken, title, body, payload = {}) {
const notification = new apn.Notification();
notification.alert = { title, body };
notification.badge = 1;
notification.sound = 'default';
notification.topic = 'com.yourapp.bundleid';
notification.payload = payload;
notification.expiry = Math.floor(Date.now() / 1000) + 3600;
apnProvider.send(notification, deviceToken).then((result) => {
if (result.failed.length > 0) {
console.error('Başarısız:', result.failed);
} else {
console.log('Bildirim gönderildi');
}
});
}
FCM Üzerinden Hem Android Hem iOS'a Gönderim
FCM, yalnızca Android değil iOS cihazlara da bildirim göndermeyi destekler. Firebase konsolundan APNs anahtarınızı (p8) yükleyerek, tek bir API üzerinden her iki platforma da ulaşabilirsiniz. Bu yaklaşım backend kodunuzu büyük ölçüde sadeleştirir:
async function sendCrossPlatformNotification(token, title, body) {
const message = {
token: token,
notification: { title, body },
android: {
priority: 'high',
},
apns: {
headers: { 'apns-priority': '10' },
payload: {
aps: {
badge: 1,
sound: 'default',
},
},
},
};
return admin.messaging().send(message);
}
Topic ve Grup Bazlı Bildirimler
Tüm kullanıcılara veya belirli bir gruba bildirim göndermek için FCM'in topic özelliğini kullanabilirsiniz:
// Client tarafında topic'e abone olma (Android)
FirebaseMessaging.getInstance().subscribeToTopic("haberler")
// Backend'den topic'e bildirim gönderme
const topicMessage = {
topic: 'haberler',
notification: {
title: 'Son Dakika',
body: 'Yeni bir haber yayınlandı!',
},
};
admin.messaging().send(topicMessage);
Bu yöntem, her kullanıcının token'ını tek tek saklamak yerine, ilgi alanlarına göre gruplama yapmanızı sağlar ve büyük ölçekli bildirimlerde çok daha verimlidir.
En İyi Pratikler ve Dikkat Edilmesi Gerekenler
- Token Yönetimi: Device token'lar zaman içinde değişebilir.
onNewToken(Android) veyadidRegisterForRemoteNotificationsWithDeviceToken(iOS) her çağrıldığında token'ı backend'e güncelleyin. - Geçersiz Token Temizliği: FCM veya APNs'den dönen
InvalidRegistrationveyaUnregisteredhatalarını yakalayın ve bu token'ları veritabanınızdan silin. - Bildirim Kanalları (Android 8+): Android Oreo ve üzeri sürümlerde
NotificationChanneloluşturmak zorunludur. Farklı bildirim türleri için ayrı kanallar tanımlayın. - Silent (Sessiz) Bildirimler: Arka planda veri senkronizasyonu için
content-available: 1(iOS) veyadata-only message(Android) kullanın. - Rate Limiting: Kullanıcıları bildirim yağmuruna tutmayın. Günlük/saatlik limitler belirleyin ve kullanıcı tercihlerini saklayın.
- Payload Boyutu: FCM maksimum 4 KB, APNs ise maksimum 4 KB (HTTP/2) payload destekler. Büyük verileri bildirime koymak yerine, bildirimde bir referans ID gönderin ve detayları uygulama açıldığında çekin.
- Güvenlik: Sunucu anahtarlarınızı ve p8 dosyalarınızı asla client tarafında saklamayın. Bu değerler yalnızca backend'de, tercihen environment variable veya secret manager ile korunmalıdır.
Hata Ayıklama ve Test
Geliştirme sürecinde bildirimleri test etmek için şu araçları kullanabilirsiniz:
- Firebase Console: FCM bildirimleri doğrudan Firebase konsolundan test edebilirsiniz.
- APNs Sandbox: iOS için
production: falseayarıyla sandbox ortamında test yapın. - curl ile Manuel Test: FCM HTTP v1 API'sine doğrudan curl ile istek atarak bildirimi test edebilirsiniz.
- Xcode Console: iOS'ta bildirim ile ilgili hata loglarını Xcode konsolundan takip edin.
- adb logcat: Android'de
adb logcat | grep -i firebasekomutuyla FCM loglarını izleyin.
Sonuç
Push notification entegrasyonu, modern mobil uygulamaların olmazsa olmaz bileşenlerinden biridir. FCM'in çapraz platform desteği sayesinde tek bir backend altyapısıyla hem Android hem iOS kullanıcılarına ulaşabilirsiniz. Ancak APNs'in doğrudan kullanımı, iOS'a özel gelişmiş özelliklere erişim ve daha düşük gecikme süresi sağlayabilir. Projenizin ihtiyaçlarına göre yalnızca FCM kullanmak veya her iki servisi hibrit bir yapıda entegre etmek arasında karar verebilirsiniz. Token yönetimi, hata kontrolü ve kullanıcı tercihlerine saygı gibi konulara dikkat ederek sağlam ve ölçeklenebilir bir bildirim altyapısı kurabilirsiniz.