Уведомления в фоне, оптимизация FPS чата, release notes, read receipts паритет с Android

This commit is contained in:
2026-03-18 20:10:20 +05:00
parent 1f442e1298
commit 422b20702e
42 changed files with 2459 additions and 656 deletions

View File

@@ -0,0 +1,54 @@
import UserNotifications
/// Notification Service Extension runs as a separate process even when the main app
/// is terminated. Intercepts push notifications with `mutable-content: 1` and:
/// 1. Adds `.default` sound for vibration (server payload has no sound)
/// 2. Increments the app icon badge from shared App Group storage
final class NotificationService: UNNotificationServiceExtension {
private static let appGroupID = "group.com.rosetta.dev"
private static let badgeKey = "app_badge_count"
private var contentHandler: ((UNNotificationContent) -> Void)?
private var bestAttemptContent: UNMutableNotificationContent?
override func didReceive(
_ request: UNNotificationRequest,
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void
) {
self.contentHandler = contentHandler
bestAttemptContent = request.content.mutableCopy() as? UNMutableNotificationContent
guard let content = bestAttemptContent else {
contentHandler(request.content)
return
}
// 1. Add sound for vibration server APNs payload has no sound field.
content.sound = .default
// 2. Increment badge count from shared App Group storage.
if let shared = UserDefaults(suiteName: Self.appGroupID) {
let current = shared.integer(forKey: Self.badgeKey)
let newBadge = current + 1
shared.set(newBadge, forKey: Self.badgeKey)
content.badge = NSNumber(value: newBadge)
}
// 3. Ensure notification category for CarPlay parity.
if content.categoryIdentifier.isEmpty {
content.categoryIdentifier = "message"
}
contentHandler(content)
}
/// Called if the extension takes too long (30s limit).
/// Deliver the best attempt content with at least the sound set.
override func serviceExtensionTimeWillExpire() {
if let handler = contentHandler, let content = bestAttemptContent {
content.sound = .default
handler(content)
}
}
}