Ana içeriğe geç

iOS SDK (Swift)

Native Swift Package, iOS 15+, doğrudan APNs — Firebase yok. Yalnızca URLSession ve UserDefaults.

Uygulama tarafı çalışmadan önce APNs anahtarı yüklenmiş olmalı: iOS platform kurulumu.

1 Paketi ekle

Xcode → File → Add Package Dependencies… → depo URL'ini girip OpenNotification ürününü seçin. Monorepo'yu vendor'lıyorsanız yolla ekleyin (packages/sdk-ios).

// Package.swift
dependencies: [
.package(url: "https://github.com/Aproder/opennotification.git", from: "0.1.0")
],
targets: [
.target(name: "App", dependencies: [
.product(name: "OpenNotification", package: "opennotification")
])
]

2 Yetkiler

Hedef → Signing & Capabilities+ Capability: Push Notifications ve Background Modes → Remote notifications.

3 AppDelegate

SDK'ya dört şeyin iletilmesi gerekir. AppDelegate.swift'te:

import UIKit
import UserNotifications
import OpenNotification

@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

func application(_ app: UIApplication,
didFinishLaunchingWithOptions options: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
OpenNotification.shared.configure(endpoint: "https://push.example.com", appKey: "pk_live_…")

OpenNotification.shared.onOpen = { message in
Router.open(message.url, data: message.data) // derin bağlantı, actionId, data
}
OpenNotification.shared.onReceive = { message in
// uygulama ön plandayken push geldi
}

// Uygulamayı başlatan basış (soğuk başlatma) — onOpen'a yeniden oynatılır.
OpenNotification.shared.handleLaunch(userInfo: options?[.remoteNotification] as? [AnyHashable: Any])

UNUserNotificationCenter.current().delegate = self
return true
}

// APNs token verdi → SDK cihazı kaydeder
func application(_ app: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken token: Data) {
OpenNotification.shared.didRegister(deviceToken: token)
}

// Kullanıcı bildirime ya da butonlarından birine bastı
func userNotificationCenter(_ c: UNUserNotificationCenter,
didReceive r: UNNotificationResponse,
withCompletionHandler done: @escaping () -> Void) {
OpenNotification.shared.didReceive(response: r)
done()
}

// Uygulama ön plandayken banner göster
func userNotificationCenter(_ c: UNUserNotificationCenter,
willPresent n: UNNotification,
withCompletionHandler done: @escaping (UNNotificationPresentationOptions) -> Void) {
OpenNotification.shared.willPresent(notification: n)
done([.banner, .sound, .badge])
}
}

SwiftUI uygulamaları: @UIApplicationDelegateAdaptor(AppDelegate.self) ile bir AppDelegate tutun.

Uyarı
didRegister olmadan

İzin verilir, Apple token çıkarır ve sunucuya hiçbir şey ulaşmaz — cihaz hiç abone olmaz. En sık "çalışmıyor" nedeni budur.

4 İzin iste

Nedenini açıklayan bir ekrandan — ilk açılışta değil:

OpenNotification.shared.requestPermission { granted in
// granted → SDK registerForRemoteNotifications() çağırır;
// token didRegister'a gelir ve cihaz abone olur.
}

Kayıtta SDK şunları gönderir: platform, token, sdkVersion, OS sürümü, cihaz modeli, uygulama sürümü, cihazın dili, saat dilimi ve ülkesi.

5 Kimlik ve tag'ler

OpenNotification.shared.login("user_123") // kendi girişinizden sonra
OpenNotification.shared.setTags(["plan": "platinum", "streak": 42])
OpenNotification.shared.removeTags(["streak"])
OpenNotification.shared.setLanguage("tr")
OpenNotification.shared.logout() // çıkışta
OpenNotification.shared.unsubscribe() // kullanıcı ayarlar ekranında çıktı
OpenNotification.shared.trackSession() // isteğe bağlı: didBecomeActive'de zaten gider

Her çağrı isteğe bağlı completion: (Error?) -> Void alır. Token gelmeden login sorun değil — external id kayıtla birlikte gider. Semantik: Kimlik.

Destek için gerekirse OpenNotification.shared.subscriptionId saklanan kimliği verir.

Sessiz (arka plan) push'lar

Sessiz push kampanyası alert'siz content-available olarak gelir. Background Modes › Remote notifications'ı açın ve AppDelegate geri çağrısını iletin:

func application(_ app: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler done: @escaping (UIBackgroundFetchResult) -> Void) {
OpenNotification.shared.didReceiveBackground(userInfo: userInfo) { _ in done(.newData) }
}
OpenNotification.shared.onReceive = { message in
if message.silent { Sync.run(message.data) }
}

didReceiveBackground delivered bildirir (arka plan push'unda service extension çalışmaz) ve message.data'yı onReceive'e verir. iOS yaklaşık 30 saniye tanır.

Oturumlar

configure() didBecomeActive'i gözler ve POST /v1/subscriptions/:id/session'a ping atar; sunucu 30 dakika sessizlikten sonra yeni oturum sayar. sessionCount ve lastSessionAt böylece segment alanı olarak çalışır.

Notification Service Extension

delivered olayı, görseller ve aksiyon butonları için zorunlu. iOS bunları extension olmadan vermez.

1 Xcode → File → New → Target… → Notification Service Extension. NotificationService adını verin. Deployment target'ı uygulamayla eşleyin.

2 Üretilen NotificationService.swift'i packages/sdk-ios/Templates/NotificationService.swift ile değiştirin.

3 Extension hedefinin Info.plist'ine API taban URL'inizle (https://push.example.com) OpenNotificationApiUrl adlı String anahtar ekleyin. Extension ayrı bir süreçtir ve uygulamanın yapılandırmasını okuyamaz.

4 Extension'a kendi App ID'sini ve provisioning profilini verin (com.acme.shop.NotificationService) — otomatik imzalama bunu yapar.

Şablonun ~30 saniyelik çalışma süresinde yaptıkları:

AdımAyrıntı
delivered bildirBildirim analitik beklemesin diye 5 sn timeout ile POST /v1/e/d/<msgId>.
Görseli indiron.img'den, UNNotificationAttachment olarak ekler.
Butonları kaydeton.a'yı okur, on_<campaignId> adlı UNNotificationCategory kaydeder — iOS yalnızca tanıdığı kategorinin butonlarını gösterir ve sunucu aps.category'yi bu ada ayarlar.

Sunucu her zaman mutable-content: 1 gönderir; extension'ı uyandıran budur.

Açılmaları ele alma

onOpen bir OpenNotificationMessage alır:

public struct OpenNotificationMessage {
let msgId: String?, campaignId: String?
let title: String, body: String
let image: String?, url: String?
let actions: [NotificationAction] // {id, title, url?}
let actionId: String? // butona basıldıysa dolu
let data: [String: String]
}

opened (gövde) ya da clicked (buton) closure'ınız çalışmadan önce otomatik bildirilir. iOS kapatmaları asla bildirmez.

Test

  • packages/sdk-ios içinde swift test macOS'ta çalışır; UIKit parçaları #if canImport ile dışarıda kalır.
  • Cihazda: zamanlama adımındaki Test gönder ya da target.externalIds ile POST /v1/notifications.
  • Simülatör Apple Silicon'da (Xcode 11.4+) xcrun simctl push ile APNs alabilir ama ürettiği token gerçek APNs token'ı değildir; tam yolu test etmek için cihaz kullanın.