← Назад к вопросам

Что нужно реализовать в коде, чтобы приложение могло обрабатывать push-уведомления?

2.2 Middle🔥 121 комментариев
#Архитектура и паттерны#Работа с сетью

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Полная реализация обработки Push-уведомлений в iOS

Чтобы приложение могло обрабатывать push-уведомления, необходимо реализовать многоуровневую настройку, включающую регистрацию устройства, конфигурацию проекта, обработку токенов и логику для различных состояний приложения. Вот пошаговая реализация:

1. Настройка Capabilities и сертификатов

Capabilities в Xcode:

// В Xcode:
// 1. Targets → Signing & Capabilities
// 2. Добавить capability "Push Notifications"
// 3. Добавить capability "Background Modes"
// 4. В Background Modes включить "Remote notifications"

Конфигурация сервера APNs:

  • Создать сертификат/ключ в Apple Developer Portal
  • Для разработки: Apple Push Notification service SSL (Sandbox)
  • Для продакшена: Apple Push Notification service SSL (Production)

2. Регистрация устройства для получения токена

Базовая регистрация в AppDelegate:

import UIKit
import UserNotifications

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
    
    func application(_ application: UIApplication, 
                    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
        // Запрос разрешения на уведомления
        let center = UNUserNotificationCenter.current()
        center.delegate = self
        
        let options: UNAuthorizationOptions = [.alert, .sound, .badge]
        center.requestAuthorization(options: options) { granted, error in
            if let error = error {
                print("Ошибка запроса разрешения: \(error.localizedDescription)")
            }
            
            if granted {
                print("Разрешение получено")
                DispatchQueue.main.async {
                    // Регистрация для удаленных уведомлений
                    application.registerForRemoteNotifications()
                }
            } else {
                print("Разрешение отклонено пользователем")
            }
        }
        
        return true
    }
}

3. Обработка токена устройства

Получение и отправка токена на сервер:

extension AppDelegate {
    
    // Успешная регистрация - получение device token
    func application(_ application: UIApplication, 
                    didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        
        // Преобразование Data в строку
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()
        print("Device Token: \(token)")
        
        // Отправка токена на ваш сервер
        sendTokenToServer(token)
    }
    
    // Ошибка регистрации
    func application(_ application: UIApplication, 
                    didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("Не удалось зарегистрироваться: \(error.localizedDescription)")
    }
    
    private func sendTokenToServer(_ token: String) {
        guard let url = URL(string: "https://ваш-сервер.com/register-device") else { return }
        
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        
        let body: [String: Any] = [
            "deviceToken": token,
            "platform": "ios",
            "appVersion": Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? ""
        ]
        
        request.httpBody = try? JSONSerialization.data(withJSONObject: body)
        
        URLSession.shared.dataTask(with: request) { data, response, error in
            // Обработка ответа сервера
        }.resume()
    }
}

4. Обработка входящих уведомлений

Обработка в UNUserNotificationCenterDelegate:

extension AppDelegate: UNUserNotificationCenterDelegate {
    
    // Уведомление получено, когда приложение активно
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                               willPresent notification: UNNotification,
                               withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        
        let userInfo = notification.request.content.userInfo
        
        // Извлечение данных из уведомления
        if let aps = userInfo["aps"] as? [String: Any],
           let alert = aps["alert"] as? [String: String] {
            print("Заголовок: \(alert["title"] ?? "")")
            print("Текст: \(alert["body"] ?? "")")
        }
        
        // Отображение уведомления даже когда приложение активно
        completionHandler([.banner, .sound, .badge])
    }
    
    // Пользователь тапнул по уведомлению
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                               didReceive response: UNNotificationResponse,
                               withCompletionHandler completionHandler: @escaping () -> Void) {
        
        let userInfo = response.notification.request.content.userInfo
        
        // Глубокая навигация
        handleNotificationNavigation(with: userInfo)
        
        // Очистка бейджа
        UIApplication.shared.applicationIconBadgeNumber = 0
        
        completionHandler()
    }
    
    private func handleNotificationNavigation(with userInfo: [AnyHashable: Any]) {
        // Пример обработки deep link
        if let screenType = userInfo["screenType"] as? String {
            NotificationCenter.default.post(name: NSNotification.Name("NavigateToScreen"),
                                          object: nil,
                                          userInfo: ["screen": screenType])
        }
    }
}

5. Обработка фоновых обновлений (iOS 7+)

Для silent push notifications:

extension AppDelegate {
    
    func application(_ application: UIApplication,
                    didReceiveRemoteNotification userInfo: [AnyHashable: Any],
                    fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        
        // Проверка на silent notification
        if let aps = userInfo["aps"] as? [String: Any],
           aps["content-available"] as? Int == 1 {
            
            // Фоновая обработка данных
            processBackgroundData(userInfo)
            
            // Обновление интерфейса через NotificationCenter
            NotificationCenter.default.post(name: NSNotification.Name("DataUpdated"),
                                          object: nil,
                                          userInfo: userInfo)
            
            completionHandler(.newData)
        } else {
            completionHandler(.noData)
        }
    }
    
    private func processBackgroundData(_ userInfo: [AnyHashable: Any]) {
        // Логика обработки данных в фоне
        print("Фоновая обработка данных: \(userInfo)")
    }
}

6. Современный подход с AppDelegate и SceneDelegate

Для приложений с поддержкой сцен:

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    
    func scene(_ scene: UIScene, 
               willConnectTo session: UISceneSession, 
               options connectionOptions: UIScene.ConnectionOptions) {
        
        // Обработка уведомления при запуске
        if let notificationResponse = connectionOptions.notificationResponse {
            handleNotification(response: notificationResponse)
        }
    }
    
    func sceneDidBecomeActive(_ scene: UIScene) {
        // Очистка бейджа при активации сцены
        UIApplication.shared.applicationIconBadgeNumber = 0
    }
    
    private func handleNotification(response: UNNotificationResponse) {
        // Навигация по deep link из уведомления
    }
}

7. Дополнительные настройки для расширенных функций

Notification Service Extension (для модификации уведомлений):

// Создать новый target: Notification Service Extension
import UserNotifications

class NotificationService: UNNotificationServiceExtension {
    
    override func didReceive(_ request: UNNotificationRequest, 
                            withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        
        // Модификация контента уведомления
        let bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            // Добавление медиа или изменение текста
            bestAttemptContent.title = "\(bestAttemptContent.title) [Модифицировано]"
            bestAttemptContent.sound = UNNotificationSound.default
            
            contentHandler(bestAttemptContent)
        }
    }
}

Ключевые моменты для корректной работы:

  1. Разрешения пользователя — всегда запрашивать авторизацию асинхронно
  2. Проверка токена — устройство может менять токен после переустановки приложения
  3. Фоновая обработка — использовать content-available: 1 для silent push
  4. Тестирование — использовать такие инструменты как Pusher или собственный сервер для отладки
  5. Обработка состояний — учитывать, что приложение может быть в фоне, свернуто или закрыто

Пример полезной утилиты для работы с уведомлениями:

class NotificationManager {
    static let shared = NotificationManager()
    
    func checkNotificationSettings(completion: @escaping (Bool) -> Void) {
        UNUserNotificationCenter.current().getNotificationSettings { settings in
            DispatchQueue.main.async {
                let isAuthorized = settings.authorizationStatus == .authorized
                completion(isAuthorized)
            }
        }
    }
    
    func updateBadge(count: Int) {
        UIApplication.shared.applicationIconBadgeNumber = count
    }
    
    func removeAllDeliveredNotifications() {
        UNUserNotificationCenter.current().removeAllDeliveredNotifications()
    }
}

Этот комплексный подход обеспечивает полную поддержку push-уведомлений с учетом всех современных требований iOS и лучших практик разработки.

Что нужно реализовать в коде, чтобы приложение могло обрабатывать push-уведомления? | PrepBro