# iOS Push Notifications Mülakatı 2026: APNs, token'lar ve sorun giderme > iOS mülakatlarına hazırlık için kapsamlı rehber: Push Notifications, APNs, token yönetimi ve sorun giderme. Sık sorulan sorular ve ayrıntılı yanıtlar. - Published: 2026-02-28 - Updated: 2026-04-29 - Author: SharpSkill - Tags: ios, push-notifications, apns, swift, interview - Reading time: 12 min --- Push Notifications iOS mülakatlarında kritik bir konu olmaya devam ediyor. APNs'nin nasıl çalıştığını anlamak, device token'ları yönetmek ve yaygın sorunları gidermek Apple ekosistemine dair derin bilgiyi gösterir. Bu rehber en sık sorulan mülakat sorularını ele alıyor. > **Mülakatın anahtar noktası** > > Mülakatçılar, cihaz kaydından bildirim teslimine kadar tüm yaşam döngüsünü ve her aşamada doğru hata yönetimini kavramış adayları arıyor. ## APNs mimarisi: iOS bildirimlerinin temeli Apple Push Notification service (APNs), Apple cihazlarına push bildirim teslimini yöneten merkezi servistir. Mimarisini bilmek mülakat sorularına etkili yanıt vermek için şarttır. ### APNs nasıl çalışır? İletişim akışı üç ana aktörü kapsar: iOS uygulaması, APNs ve backend sunucusu. Sürecin tamamı şöyledir: ```swift // AppDelegate.swift import UIKit import UserNotifications @main class AppDelegate: UIResponder, UIApplicationDelegate { func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { // Request notification authorization UNUserNotificationCenter.current().requestAuthorization( options: [.alert, .badge, .sound] ) { granted, error in guard granted else { return } // Register with APNs DispatchQueue.main.async { application.registerForRemoteNotifications() } } return true } } ``` APNs kaydı iki adımda gerçekleşir: kullanıcı izni alınır, ardından `registerForRemoteNotifications()` çağrılır. ### Device token yönetimi Device token, APNs tarafından belirli bir cihazı hedeflemek için üretilen benzersiz bir tanımlayıcıdır. Bu token değişebilir ve uygulamanın her açılışında backend sunucusuna gönderilmelidir. ```swift // AppDelegate.swift extension AppDelegate { // Callback when APNs provides the token func application( _ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data ) { // Convert token to hexadecimal string let tokenString = deviceToken.map { String(format: "%02.2hhx", $0) }.joined() print("Device Token: \(tokenString)") // Send to backend server sendTokenToServer(tokenString) } // Callback on registration failure func application( _ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error ) { print("Failed to register: \(error.localizedDescription)") } private func sendTokenToServer(_ token: String) { // Implement HTTP request to backend } } ``` Token `Data` olarak gelir ve sunucuya gönderilmeden önce onaltılık bir karakter dizisine dönüştürülmelidir. ## APNs hakkında sık sorulan mülakat soruları iOS mülakatları genellikle APNs'ye dair teorik ve pratik soruları birlikte içerir. En yaygın olanlar ve ayrıntılı yanıtları aşağıda yer alıyor. ### Soru 1: APNs sandbox ile production arasındaki fark nedir? > **APNs ortamları** > > APNs, farklı endpoint'lere sahip iki ayrı ortam sunar. Bir ortamda üretilen token'lar diğerinde çalışmaz. | Ortam | Endpoint | Kullanım | |-------|----------|----------| | Sandbox | api.sandbox.push.apple.com | Debug, TestFlight | | Production | api.push.apple.com | App Store | ### Soru 2: Token süresinin dolması nasıl yönetilir? Device token'lar farklı nedenlerle değişebilir: sistem geri yükleme, yeni cihaza kurulum veya APNs'nin periyodik yenilemesi. Sunucu, APNs'nin hata yanıtlarını doğru şekilde işlemelidir. ```swift // NotificationService.swift enum APNsError: Int { case badDeviceToken = 400 case unregistered = 410 case payloadTooLarge = 413 case tooManyRequests = 429 case internalServerError = 500 var shouldRemoveToken: Bool { // Remove token only if device is no longer registered return self == .unregistered || self == .badDeviceToken } } struct APNsResponse { let statusCode: Int let deviceToken: String func handleError() { guard let error = APNsError(rawValue: statusCode) else { return } if error.shouldRemoveToken { // Remove token from database TokenRepository.shared.remove(deviceToken) } } } ``` Sunucu tarafında APNs hata yönetimi, token veritabanını temiz tutmak ve gereksiz isteklerden kaçınmak için kritiktir. ### Soru 3: Silent notification nasıl uygulanır? Silent notification, uygulamayı arka planda uyandırarak kullanıcıya herhangi bir uyarı göstermeden işlem yapmayı sağlar. ```swift // AppDelegate.swift func application( _ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void ) { // Check if this is a silent notification guard let aps = userInfo["aps"] as? [String: Any], aps["content-available"] as? Int == 1 else { completionHandler(.noData) return } // Perform background task performBackgroundTask { result in switch result { case .success: completionHandler(.newData) case .failure: completionHandler(.failed) } } } ``` Silent notification'ın JSON payload'u `aps` nesnesi içinde `"content-available": 1` içermelidir. ## Notification Service Extension: gelişmiş özelleştirme Notification Service Extensions, bildirim içeriğinin görüntülenmeden önce değiştirilmesini sağlar. Bu özellik mülakatlarda sık sık ele alınır. ### Service Extension oluşturma ```swift // NotificationService.swift (in Extension target) import UserNotifications class NotificationService: UNNotificationServiceExtension { var contentHandler: ((UNNotificationContent) -> Void)? var bestAttemptContent: UNMutableNotificationContent? override func didReceive( _ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void ) { self.contentHandler = contentHandler bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent guard let bestAttemptContent = bestAttemptContent else { contentHandler(request.content) return } // Modify content if let imageURLString = bestAttemptContent.userInfo["image-url"] as? String, let imageURL = URL(string: imageURLString) { downloadImage(from: imageURL) { attachment in if let attachment = attachment { bestAttemptContent.attachments = [attachment] } contentHandler(bestAttemptContent) } } else { contentHandler(bestAttemptContent) } } override func serviceExtensionTimeWillExpire() { // Called when time limit (30 seconds) is exceeded if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { contentHandler(bestAttemptContent) } } private func downloadImage( from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void ) { URLSession.shared.downloadTask(with: url) { localURL, _, error in guard let localURL = localURL, error == nil else { completion(nil) return } let tempDirectory = FileManager.default.temporaryDirectory let fileName = url.lastPathComponent let destinationURL = tempDirectory.appendingPathComponent(fileName) try? FileManager.default.moveItem(at: localURL, to: destinationURL) let attachment = try? UNNotificationAttachment( identifier: fileName, url: destinationURL, options: nil ) completion(attachment) }.resume() } } ``` Extension içeriği değiştirmek için 30 saniyeye sahiptir. Bu sınır aşılırsa `serviceExtensionTimeWillExpire()` metodu çağrılır. ## Push Notifications sorun giderme Push notification hata ayıklama mülakatlarda tekrar eden bir konudur. Adayların araçları ve teşhis tekniklerini bilmesi beklenir. ### Kayıt durumunu doğrulama ```swift // DebugHelper.swift struct PushNotificationDebugger { static func checkNotificationStatus() async { let center = UNUserNotificationCenter.current() let settings = await center.notificationSettings() print("=== Push Notification Status ===") print("Authorization: \(settings.authorizationStatus.description)") print("Alert: \(settings.alertSetting.description)") print("Badge: \(settings.badgeSetting.description)") print("Sound: \(settings.soundSetting.description)") print("Notification Center: \(settings.notificationCenterSetting.description)") } } extension UNAuthorizationStatus { var description: String { switch self { case .notDetermined: return "Not Determined" case .denied: return "Denied" case .authorized: return "Authorized" case .provisional: return "Provisional" case .ephemeral: return "Ephemeral" @unknown default: return "Unknown" } } } ``` Bu debug fonksiyonu bildirimlerin yetkilendirme durumunu hızla kontrol etmeyi sağlar. ### Sık karşılaşılan hatalar ve çözümler > **Bilinmesi gereken yaygın hatalar** > > Mülakatçılar sık sık yaygın hataları ve çözümlerini sorar. Aşağıdakiler akılda tutulması gerekenlerdir. | Hata | Sebep | Çözüm | |------|-------|-------| | Geçersiz token | Yanlış ortam (sandbox/prod) | Provisioning profile'ı kontrol et | | Bildirim gelmedi | Düşük güç modu açık | Şarjlı pille test et | | Extension çağrılmadı | `mutable-content` eksik payload | `"mutable-content": 1` ekle | | Background fetch başarısız | Uygulama kullanıcı tarafından kapatıldı | Kullanıcıyı sınırlamadan haberdar et | ### APNs'yi doğrudan test etme Geliştirme sırasında bildirimleri test etmek için `curl` aracı doğrudan APNs'ye istek göndermeyi sağlar: ```swift // TestPayload.swift struct APNsTestPayload { static let silentNotification = """ { "aps": { "content-available": 1 }, "custom-data": "test" } """ static let richNotification = """ { "aps": { "alert": { "title": "New message", "body": "Message content" }, "mutable-content": 1, "sound": "default" }, "image-url": "https://example.com/image.jpg" } """ } ``` Bu test payload'ları, uygulamanın farklı bildirim türleriyle davranışını doğrulamak için kullanışlıdır. ## Production için en iyi uygulamalar En iyi uygulamalar üzerine sorular adayın production deneyimini ölçmeye yardımcı olur. ### Ağ hatalarını ele alma ```swift // PushTokenManager.swift actor PushTokenManager { private var pendingToken: String? private var retryCount = 0 private let maxRetries = 3 func registerToken(_ token: String) async { pendingToken = token await sendTokenWithRetry() } private func sendTokenWithRetry() async { guard let token = pendingToken else { return } do { try await APIClient.shared.registerPushToken(token) pendingToken = nil retryCount = 0 } catch { retryCount += 1 if retryCount < maxRetries { // Retry with exponential backoff let delay = UInt64(pow(2.0, Double(retryCount))) * 1_000_000_000 try? await Task.sleep(nanoseconds: delay) await sendTokenWithRetry() } } } } ``` Bir `actor` kullanmak, eşzamanlı ortamlarda token yönetiminde thread güvenliğini sağlar. ### Token'ın yerel kalıcılığı ```swift // TokenStorage.swift struct TokenStorage { private static let tokenKey = "com.app.pushToken" static func save(_ token: String) { UserDefaults.standard.set(token, forKey: tokenKey) } static func retrieve() -> String? { UserDefaults.standard.string(forKey: tokenKey) } static func hasTokenChanged(_ newToken: String) -> Bool { guard let savedToken = retrieve() else { return true } return savedToken != newToken } } ``` Token'ı yerel olarak saklamak, token değişmediğinde gereksiz ağ çağrılarını engeller. ## Sonuç iOS Push Notifications'a hâkim olmak Apple ekosistemine ve istemci-sunucu etkileşimine derinlemesine hâkimiyetin kanıtıdır. Mülakatlarda akılda tutulması gereken anahtar noktalar: ✅ APNs mimarisi: kayıttan teslimata uzanan tam akışı kavramak ✅ Device token'lar: yaşam döngüsü ve token değişimlerinin yönetimi ✅ Notification Service Extension: 30 saniyelik sınırla içerik özelleştirme ✅ Sorun giderme: yaygın hataları ve çözümlerini bilmek ✅ Silent notifications: background fetch için `content-available` ✅ En iyi uygulamalar: yeniden deneme mantığı, yerel kalıcılık, hata yönetimi --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/tr/blog/ios/ios-push-notifications-apns-interview