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.

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çı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:
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.
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, 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.
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.
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.
iOS mülakatlarında başarılı olmaya hazır mısın?
İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.
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
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
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
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:
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
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ığı
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
Pratik yapmaya başla!
Mülakat simülatörleri ve teknik testlerle bilgini test et.
Etiketler
Paylaş
İlgili makaleler

StoreKit 2 Mülakatı: Abonelik Yönetimi ve Makbuz Doğrulama
StoreKit 2, abonelik yönetimi, makbuz doğrulama ve uygulama içi satın alma uygulaması hakkında iOS mülakat sorularında pratik Swift kod örnekleriyle uzmanlaşın.

Swift Testing Framework Mülakat 2026: #expect ve #require Makroları XCTest Karşısında
iOS mülakatları için yeni Swift Testing Framework'ünde uzmanlaş: #expect ve #require makroları, XCTest geçişi, ileri seviye desenler ve sık yapılan hatalar.

iOS Geliştiricileri İçin En Önemli 25 Swift Mülakat Sorusu
iOS mülakatlarına hazırlık: En sık sorulan 25 Swift sorusu — optionals, closures, ARC, protokoller, async/await ve ileri düzey kalıplar detaylı açıklamalarla.