如何从AppDelegate推送SwiftUI页面 接收通知跳转指定Tab栏
实现方案
核心思路
通过回调闭包建立AppDelegate和MainApp的关联,直接复用MainApp中已初始化的rootViewModel实例,通过修改rootViewModel的状态驱动SwiftUI页面跳转和Tab切换。
代码修改
1. 改造AppDelegate
新增rootViewModel引用和通知点击回调闭包,同时实现用户点击通知的代理方法:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { // 持有MainApp初始化的rootViewModel实例 var rootViewModel: MainViewModel? // 通知点击回调,参数为通知携带的userInfo var onNotificationTap: (([AnyHashable: Any]) -> Void)? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // 必须设置通知中心代理,否则通知回调不生效 UNUserNotificationCenter.current().delegate = self return true } func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) { print("willPresent notification") let info = notification.request.content.userInfo completionHandler([.badge, .sound, .banner]) } // 处理用户点击通知的逻辑 func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo onNotificationTap?(userInfo) completionHandler() } }
2. 改造MainViewModel
新增控制Tab选中和登录状态的响应式属性:
class MainViewModel: ObservableObject { // 控制Tab选中索引,通知tab的tag可根据实际业务调整 @Published var selectedTab: Int = 0 // 登录状态,替换原MainApp中的本地变量 @Published var authenticated: Bool = false // 其他原有业务逻辑保留 }
3. 改造MainApp
在初始化时给AppDelegate注入rootViewModel和通知点击的处理逻辑:
@main struct MainApp: App { @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate private var rootViewModel: MainViewModel init() { let vm = MainViewModel() self.rootViewModel = vm // 给AppDelegate注入依赖 appDelegate.rootViewModel = vm appDelegate.onNotificationTap = { userInfo in // 直接修改rootViewModel状态,驱动切换到通知tab // 假设通知tab对应的tag为2,按需修改为你的实际值 vm.selectedTab = 2 // 可在此处处理额外业务逻辑,比如根据userInfo存目标页面ID,后续跳转到对应详情页 // 示例:vm.targetNotificationId = userInfo["notification_id"] as? String } } var body: some Scene { WindowGroup { if rootViewModel.authenticated { Tabbar() .environmentObject(rootViewModel) } else { SecondScreen() .environmentObject(rootViewModel) } } } }
4. 改造Tabbar视图
绑定rootViewModel的selectedTab属性实现受控切换:
struct Tabbar: View { @EnvironmentObject var rootViewModel: MainViewModel var body: some View { TabView(selection: $rootViewModel.selectedTab) { // 首页tab示例 HomeView() .tabItem { Label("首页", systemImage: "house") } .tag(0) // 其他tab示例 MessageView() .tabItem { Label("消息", systemImage: "message") } .tag(1) // 通知tab NotificationView() .tabItem { Label("通知", systemImage: "bell") } .tag(2) } } }
注意事项
- 通知tab的
tag值要和onNotificationTap中设置的selectedTab值保持一致 - 如果需要点击通知直接跳转到通知详情页,只需在
MainViewModel新增对应的@Published属性,在NotificationView中监听属性触发路由跳转即可 - 该方案全程复用同一个
rootViewModel实例,所有原有业务逻辑可直接调用,无需额外初始化
内容的提问来源于stack exchange,提问作者Muli
相关产品推荐
相关产品推荐

