SwiftUI notification click go to a specific view
Asked Answered
R

2

5

I am using SwiftUI 2.0 and I am trying to implement firebase push notifications. In new SwiftUI app structure, there's no AppDelegate and SceneDelegate, so I created AppDelegate class. I managed receiving notifications but I cant go to a specific view on notification click. Here is my code:

@main
struct swiftUiApp: App {


@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate


var body: some Scene {
    WindowGroup {
       
            ContentView() 
         
    }
  } 
}

And AppDelegate extension:

func userNotificationCenter(_ center: UNUserNotificationCenter,
                          didReceive response: UNNotificationResponse,
                          withCompletionHandler completionHandler: @escaping () -> Void) {

let  orders =  Orders()

let userInfo = response.notification.request.content.userInfo
// Print message ID.
if let messageID = userInfo[gcmMessageIDKey] {
  print("Message ID: \(messageID)")
}

if(userInfo["gcm.notification.type"] != nil){
    if(userInfo["gcm.notification.type"] as! String == "order"){
  
          //here I need to navigate to OrderView

        }
    

    }

}
Roadblock answered 29/1, 2021 at 20:59 Comment(0)
W
8

I was facing the exact same problem and solved it this way:

I have my AppDelegate class conform to ObservableObject and added a published property that controls whether I need to show the notification-specific view: @Published var openedFromNotification: Bool = false

In the AppDelegate, I set this property to true inside the userNotificationCenter( ... willPresent ...) (notification when app is active) or userNotificationCenter( ... didReceive ...) (notification when app is in background) functions.

Since AppDelegate is an ObservableObject, it can be set as an environmentObject for ContentView:

@main
struct swiftUiApp: App {

@UIApplicationDelegateAdaptor(AppDelegate.self) var delegate

var body: some Scene {
     
     WindowGroup {
        
        ContentView().environmentObject(delegate)
     
     }
  } 
}

This gives me access to the published property inside my ContentView().

Inside ContentView I simply display the notification-specific view or the standard view for when the app is opened normally based on the delegate.openedFromNotification property:

struct ContentView: View {
    
    @EnvironmentObject private var delegate: AppDelegate
    
    var body: some View {

       if (delegate.openedFromNotification) {
          SpecialView().environmentObject(delegate)
       } else {
           HomeView()
       }

    }

}

I pass the EnvironmentObject delegate on to the SpecialView() so that I can set the openedFromNotification property back to false once I need to show the standard HomeView() again.

This can be expanded by adding more published properties if you want to have different Views to be shown for e.g. certain notification payloads.

In my case I have two such published properties, and based on a JSON value in the push notification data I can navigate the user to different parts of my app.

Whitethorn answered 16/1, 2022 at 16:15 Comment(4)
This can be done in watchOS extension as well, just add WKExtensionDelegate instead of AppDelegate and add UNUserNotificationCenter.current().delegate = self into applicationDidFinishLaunching inside.Adrenal
Thank you. I implemented this in github.com/binwiederhier/ntfy-ios/commit/… and it works like a charm.Priestly
After struggling so much I found this gem. Worked for me! Thank youTedtedd
Bonus info: since the published properties of AppDelegate are @State objects you can use them as bindings for e.g. sheet modifiers - that way you can show the notification-specific view as a popover instead of a fullscreen view. Simply set the property back to false in the onDismiss modifier of the View in the popover sheet to complete the cycle so that the next push notification can trigger the sheet anew.Whitethorn
T
0

Is this what you're looking for?

@main
struct swiftUiApp: App {

    
    @AppStorage("ViewSelection") var ViewSelection = "SetupView" // Can be another type

    var body: some Scene {

        WindowGroup {
            TabView(selection: $ViewSelection) {

                SetupView().tag("SetupView")
                ContentView().tag("ContentView")

            }
        .tabViewStyle(PageTabViewStyle())
        .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))

        }

    }

}

Just make sure to change the view names to your own

The ViewSelection is a binding so just something like

ViewSelection = "ContentView"

will change it

Thoughtout answered 26/2, 2021 at 6:27 Comment(1)
i need to change view from app delegate because I need to pass parameters, this will not workRoadblock

© 2022 - 2024 — McMap. All rights reserved.