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

RxSwift扩展UNUserNotificationCenter遇类型转换崩溃,求前台本地通知方案

解决RxSwift扩展UNUserNotificationCenter时的闭包类型转换崩溃问题

这个问题我之前踩过一模一样的坑!本质是Objective-C Block和Swift闭包之间的桥接类型不匹配导致的——你看到的NSStackBlock转(__C.UNNotificationPresentationOptions) -> ()失败,就是因为代理方法里的completion handler在ObjC里是block类型,直接强制转换时签名没对齐。

要实现前台显示本地通知的需求,我们需要正确处理userNotificationCenter(_:willPresent:withCompletionHandler:)这个代理方法的响应式包装,下面是完整的解决方案:

1. 正确扩展UNUserNotificationCenter的Rx响应式接口

首先我们给UNUserNotificationCenter添加Rx扩展,通过methodInvoked监听代理方法,并且正确转换completion handler的类型:

import RxSwift
import RxCocoa
import UserNotifications

extension Reactive where Base: UNUserNotificationCenter {
    /// 监听前台收到通知的事件,返回通知对象和completion闭包
    var willPresentNotification: Observable<(UNNotification, (UNNotificationPresentationOptions) -> Void)> {
        return methodInvoked(#selector(UNUserNotificationCenterDelegate.userNotificationCenter(_:willPresent:withCompletionHandler:)))
            .map { parameters in
                // 确保参数类型转换完全匹配
                let notification = parameters[1] as! UNNotification
                // 这里的类型转换必须严格对应ObjC block的签名
                let completionHandler = parameters[2] as! (UNNotificationPresentationOptions) -> Void
                return (notification, completionHandler)
            }
    }
}

2. 订阅事件并处理前台通知展示

接下来在你的业务代码里订阅这个Observable,调用completion闭包并传入需要的展示选项(比如.alert、.sound,这样通知就能在App前台显示了):

// 假设你有一个全局的disposeBag
let disposeBag = DisposeBag()

// 订阅前台通知事件
UNUserNotificationCenter.current().rx.willPresentNotification
    .subscribe(onNext: { notification, completion in
        // 这里可以自定义处理通知内容,比如打印日志、更新UI
        print("前台收到通知:\(notification.request.content.title)")
        
        // 传入展示选项,让通知在前台显示
        completion([.alert, .sound, .badge])
    })
    .disposed(by: disposeBag)

3. 别忘了设置代理

RxSwift的响应式扩展依赖于代理的转发,所以需要确保UNUserNotificationCenter的delegate被正确设置。你可以直接使用RxCocoa提供的RxUserNotificationCenterDelegateProxy:

let delegateProxy = RxUserNotificationCenterDelegateProxy()
UNUserNotificationCenter.current().delegate = delegateProxy

如果是自定义代理类,也要确保它能把代理方法调用转发到Rx的流中。

为什么之前会崩溃?

你遇到的崩溃是因为直接把ObjC的NSStackBlock强制转换成了不匹配的Swift闭包类型。userNotificationCenter(_:willPresent:withCompletionHandler:)的completion handler在ObjC中的签名是void (^)(UNNotificationPresentationOptions options),对应的Swift类型必须严格是(UNNotificationPresentationOptions) -> Void,不能有任何参数或返回值的差异——一旦类型不匹配,就会出现转换失败的崩溃。上面的代码通过methodInvoked拿到参数后,做了严格的类型转换,就避免了这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:13:45