SwiftUI - 当用户打开推送通知时打开特定视图

Posted

技术标签:

【中文标题】SwiftUI - 当用户打开推送通知时打开特定视图【英文标题】:SwiftUI - Open a specific View when user opens a Push Notification 【发布时间】:2021-02-19 19:36:44 【问题描述】:

有一个用 SwiftUI 制作的应用,Parse 用于 DB。 我在应用程序的某些部分集成了一些发送通知的云功能(例如:当有人向您发送消息时,您将收到由该云功能触发的推送通知)。 在过去的日子里,当您按下通知打开应用程序时,我一直在努力寻找如何打开特定视图。 我找到了一些解决方案,但无法让它们发挥作用。

这是我到目前为止的代码:

class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate 
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool 
        
        //Parse Intialization
        ...
        //notifications
        registerForPushNotifications()
        //Notification Badge
        UIApplication.shared.applicationIconBadgeNumber = 0
        // start notification while app is in Foreground
        UNUserNotificationCenter.current().delegate = self
        return true
    
    
    // This function will be called right after user tap on the notification
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) 
        print("app opened from PushNotification tap")
        UIApplication.shared.applicationIconBadgeNumber = 0
      completionHandler()
    


@main
struct MyApp: App 
    
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    
    var body: some Scene 
        WindowGroup 
            ContentView(currentTab: Tab.home)
        
    

应用程序打印“从 PushNotification 点击​​打开应用程序”,但如果我在 AppDelegate 中放置一个变量,并使用 .onReceive 或 .onChange 监听 Co​​ntentView 中的变化,则什么都不会发生

struct ContentView: View 
    @ObservedObject var appState = AppState()
    @State var currentTab : Tab
    @State var noReloadAddItemView = false
    var body: some View 
        TabView(selection: $appState.currentTab) 
            
            NavigationView 
                HomeView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
                
            
            .tabItem 
                if appState.currentTab == .home 
                    Image(systemName: "house.fill")
                 else 
                    Image(systemName: "house")
                
                
                Text(LocalizedStringKey("HomeTabMenu"))
                
            .tag(Tab.home)
            
            NavigationView 
                SearchView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
            
            .tabItem 
                if appState.currentTab == .search 
                    Image(systemName: "magnifyingglass.circle.fill")
                 else 
                    Image(systemName: "magnifyingglass")
                
                Text(LocalizedStringKey("SearchTabMenu"))
            .tag(Tab.search)
            
            NavigationView 
                AddItemView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
            
            .tabItem 
                if appState.currentTab == .add 
                    Image(systemName: "plus.circle.fill")
                 else 
                    Image(systemName: "plus.circle")
                
                Text(LocalizedStringKey("SellTabMenu"))
            .tag(Tab.add)
            
            NavigationView 
                ShoppingCartFavoritesView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
            
            .tabItem 
                if appState.currentTab == .favorites 
                    Image(systemName: "cart.fill")
                 else 
                    Image(systemName: "cart")
                
                Text(LocalizedStringKey("CartTabMenu"))
            .tag(Tab.favorites)
            
            NavigationView 
                ProfileView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
            
            .tabItem 
                if appState.currentTab == .profile 
                    Image(systemName: "person.fill")
                 else 
                    Image(systemName: "person")
                
                Text(LocalizedStringKey("ProfileTabMenu"))
            .tag(Tab.profile)
        
        .accentColor(Color("ColorMainDark"))
    


struct ContentView_Previews: PreviewProvider 
    static var previews: some View 
        ContentView(currentTab: Tab.home)
    


class AppState: ObservableObject 
    @Published var currentTab : Tab = .home


enum Tab 
    case home, search, add, favorites, profile

【问题讨论】:

【参考方案1】:

您需要某种可以修改的共享状态,SwiftUI 知道它会做出反应。 ObservableObject 非常适合:

class AppState: ObservableObject 
    static let shared = AppState()
    @Published var pageToNavigationTo : String?

然后,要收听并响应它,您可以在主视图中执行几种不同的方法。

选项 1——基于 ObservedObject 值的 NavigationLink 绑定:

struct ContentView : View 
    @ObservedObject var appState = AppState.shared //<-- note this
    @State var navigate = false
    
    var pushNavigationBinding : Binding<Bool> 
        .init  () -> Bool in
            appState.pageToNavigationTo != nil
         set:  (newValue) in
            if !newValue  appState.pageToNavigationTo = nil 
        
    
    
    var body: some View 
        NavigationView 
            Text("My content")
                .overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
                                        isActive: pushNavigationBinding) 
                    EmptyView()
                )
        
    


struct Dest : View 
    var message : String
    var body: some View 
        Text("\(message)")
    

或者,您可以使用onReceive

struct ContentView : View 
    @ObservedObject var appState = AppState.shared
    @State var navigate = false
    
    var body: some View 
        NavigationView 
            VStack 
                if navigate 
                    NavigationLink(destination: Text("Test"), isActive: $navigate ) 
                        EmptyView()
                    
                
                Text("My content")
                    .onReceive(appState.$pageToNavigationTo)  (nav) in
                        if nav != nil  navigate = true 
                    
            
        
    

我会将您的特定 NavigationView、NavigationLink、TabView 等的实现细节留给您,但这应该可以帮助您入门。

最后,一个模拟通知并展示导航视图的全功能最小示例:


class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate 
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool 
     
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) 
            print("Dispatch")
            AppState.shared.pageToNavigationTo = "test"
        
        
        return true
    


class AppState: ObservableObject 
    static let shared = AppState()
    @Published var pageToNavigationTo : String?


@main
struct MultiWindowApp: App 
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    
    var body: some Scene 
        WindowGroup 
            ContentView()
        
    


struct ContentView : View 
    @ObservedObject var appState = AppState.shared
    @State var navigate = false
    
    var pushNavigationBinding : Binding<Bool> 
        .init  () -> Bool in
            appState.pageToNavigationTo != nil
         set:  (newValue) in
            if !newValue  appState.pageToNavigationTo = nil 
        
    
    
    var body: some View 
        NavigationView 
            Text("My content")
                .overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
                                        isActive: pushNavigationBinding) 
                    EmptyView()
                )
        
    



struct Dest : View 
    var message : String
    var body: some View 
        Text("\(message)")
    

【讨论】:

我没有意识到你可以在 Swift 中拥有一个 Observable 单例......但我想它检查出来了 您也可以在应用程序委托和视图之间显式传递引用 - 但是,这可能最终需要可选。

以上是关于SwiftUI - 当用户打开推送通知时打开特定视图的主要内容,如果未能解决你的问题,请参考以下文章

当用户使用 iOS 13 Swift 5 点击推送通知时,在特定视图中打开应用程序

单击 Ionic 中的推送通知时如何打开特定页面?

当汽车到达特定半径时如何发送推送通知

从 SwiftUI 应用程序中更改推送通知授权

当点击 FCM 推送通知时,如何在选项卡栏中打开特定的视图控制器?

单击推送通知时对特定活动的意图。