You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI应用已推送本地通知未在通知中心显示的解决方法

问题描述

我开发了一款SwiftUI应用,创建了一个NotificationCenter结构体用于推送本地通知,核心函数代码如下:

@MainActor
struct NotificationCenter {
    // 从通知中心移除已删除的项目
    // 推送所有新增和修改的项目到通知中心
    // 让通知中心更新已修改的项目
    static func pushNotifications(_ items: [Item]) async throws {
        let center = UNUserNotificationCenter.current()
        let items = Set(items)
        
        let pending: Set<Item> = Set((await center.pendingNotificationRequests()).map{
            Item(identifier: $0.identifier, notificationContent: $0.content)
        })
        let toBeRemovedPendingItems = pending.filter{ !items.map{ $0.id }.contains($0.id) }
        
        let pushed: Set<Item> = Set((await center.deliveredNotifications()).map{
            Item(identifier: $0.request.identifier, notificationContent: $0.request.content)
        })
        let toBeRemovedPushedItems = pushed.filter{ !items.map{ $0.id }.contains($0.id) }
        
        let toBePushedItems = items
            .subtracting(toBeRemovedPendingItems)
            .subtracting((pushed.subtracting(toBeRemovedPushedItems)))
        print(pushed)
        print(toBePushedItems)
        
        center.removePendingNotificationRequests(withIdentifiers: toBeRemovedPendingItems.map{ $0.id.uuidString })
        center.removeDeliveredNotifications(withIdentifiers: toBeRemovedPushedItems.map{ $0.id.uuidString })
        for item in toBePushedItems {
            try await center.add(item.notificationRequest)
        }
        
        UIApplication.shared.applicationIconBadgeNumber = (await center.deliveredNotifications()).count
    }
}

pushNotifications函数会在应用scenePhase变为.inactive时被调用。

我在主SwiftUI App结构体中使用@UIApplicationDelegateAdaptor(AppDelegate.self)记录通知到达情况,并在应用打开时显示通知。目前通知到达日志记录正常,print(pushed)输出和应用图标角标设置都显示推送的通知已存在于通知中心,但通知并未在系统通知中心显示。模拟器和iPhone真机测试均出现该异常。

相关补充代码:

extension Item {
    var notificationRequest: UNNotificationRequest {
        let content = UNMutableNotificationContent()
        content.title = "\(name ?? "(nil)") (\(type ?? "(nil)"))"
        content.body = "Expiring on \(dateFormatter.string(from: date))"
            
        // 试过用和不用trigger两种情况
        return UNNotificationRequest(identifier: id.uuidString, content: content, trigger: nil)
    }
}
解决方法

1. 确认通知权限已正确获取

确保应用已获得用户授予的通知显示权限,仅请求权限不够,必须用户明确允许。可以在App启动时添加权限请求代码:

func requestNotificationPermissions() async {
    let center = UNUserNotificationCenter.current()
    let isGranted = await center.requestAuthorization(options: [.alert, .badge, .sound])
    guard isGranted else {
        print("用户未授予通知权限")
        return
    }
}

可将该方法放在@main结构体的init或视图的onAppear中调用。

2. 修正trigger的错误用法

当创建UNNotificationRequest时传入trigger: nil,通知会直接被标记为已送达(进入deliveredNotifications),但系统不会弹出通知提示。如果需要立即显示通知,应使用UNTimeIntervalNotificationTrigger设置一个极短延迟(比如0.1秒),触发系统展示通知:

extension Item {
    var notificationRequest: UNNotificationRequest {
        let content = UNMutableNotificationContent()
        content.title = "\(name ?? "(nil)") (\(type ?? "(nil)"))"
        content.body = "Expiring on \(dateFormatter.string(from: date))"
        // 添加短延迟触发器,确保系统弹出通知
        let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 0.1, repeats: false)
        return UNNotificationRequest(identifier: id.uuidString, content: content, trigger: trigger)
    }
}

3. 确保Item正确实现Hashable协议

当前代码中Set的比较逻辑依赖Item的Hashable实现,如果协议实现不正确,会导致subtracting等操作失效,出现重复添加或错误过滤通知的情况。示例实现如下:

struct Item: Hashable {
    let id: UUID
    var name: String?
    var type: String?
    var date: Date
    
    // 仅以唯一标识id作为哈希和相等判断依据
    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
    }
    
    static func == (lhs: Item, rhs: Item) -> Bool {
        return lhs.id == rhs.id
    }
}

4. 调整通知推送的时机

当应用从活跃状态转为.inactive时,系统可能限制通知的即时展示。可以尝试将推送逻辑延迟到应用进入.background状态时执行,或者提前在应用活跃阶段完成通知调度。

5. 检查设备通知设置

在设备的「设置-通知-你的应用」中,确认以下选项已开启:

  • 允许通知
  • 已勾选通知样式(横幅/提醒)
  • 已开启锁定屏幕/通知中心/横幅的显示权限

内容的提问来源于stack exchange,提问作者Austin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 11:17:52