I want to tap a push notification to open a specific screen in SwiftUI
Asked Answered
T

2

11

I am using SwiftUI.

I want to open a specific screen other than Root View by clicking the push notification. There are several ways to open it using StoryBoard, but not without StoryBoard.

How can I achieve it without using StoryBoard?

I tried this, but I'm a beginner, so I don't know.

class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    var window: UIWindow?

    func userNotificationCenter(
        _ center: UNUserNotificationCenter,
        willPresent notification: UNNotification,
        withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions)
        -> Void) {
        completionHandler([.alert, .badge, .sound])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: () -> Void) {
        // I want to open a screen other than Root View here.
        completionHandler()
    }
    ... }
Tolmann answered 15/4, 2020 at 4:6 Comment(3)
Have you found an answer yet?Pless
The question does not have much sense because userNotificationCenter(_ center: UNUserNotificationCenter, didReceive... is called while application is in background, so no UI is present then, and you just need to store somewhere notification response data to show user later, when user opens an app, but then app just behaves as in regular flow (eg. read records from database, defaults, etc.)Golly
Here is a similar question to yours, maybe the answer will help: #60491360Minus
F
0

The idea is you set a variable when the user is coming from a notification and check that variable when you want to present the UI.

here is a sample:

// assume that AppDelegate is also our UNNotificationCenterDelegate 
// I'm using a bool variable to check if user is coming from the notification
var isFromNotif: Bool = false
extension AppDelegate: UNUserNotificationCenterDelegate {
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        
        isFromNotif = true
        // ...
    
}

now in my View, I check the flag.

struct ContentView1: View {
    
    var body: some View {
        return Group {
            if isFromNotif {
                Text("coming from notification")
            } else {
                Text("not coming from notification")
            }
        }
    }
    
}

I hope this sample could help you.

Foucquet answered 13/9, 2020 at 11:56 Comment(0)
H
0

In a SwiftUI app, in order to communicate with the AppDelegate, you need to use UIApplicationDelegateAdaptor. With it, you will be able to pass your AppDelegate to your views using the environmentObject modifier.

In your AppDelegate's userNotificationCenter(_:didReceive:) method, you will need to extract info from your notification in order to create an object that will be used to navigate to a specific view in your app.

Using Combine, you will then be able to publish this object and observe it in your root view in order to drive your navigation.


The following iOS 17 implementation shows how to navigate to a specific view in a SwiftUI app when a notification is received and tapped by the user.

AppDelegate.swift:

import UIKit
import Combine

final class AppDelegate: NSObject, ObservableObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    let newOfferSubject = PassthroughSubject<Offer, Never>()

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
    ) -> Bool {
        UNUserNotificationCenter.current().delegate = self
        return true
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
        if let offer = Offer(rawValue: response.notification.request.content.categoryIdentifier) {
            newOfferSubject.send(offer)
        }
    }

    func userNotificationCenter(
        _ center: UNUserNotificationCenter, 
        willPresent notification: UNNotification
    ) async -> UNNotificationPresentationOptions {
        return [.banner, .list]
    }
}

MyDemoApp.swift:

import SwiftUI

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

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

Offer.swift:

enum Offer: String, Identifiable {
    case special = "offer.special"
    case tenPercent = "offer.ten_percent"

    var id: Self {
        self
    }
}

ContentView.swift:

import SwiftUI

struct ContentView: View {
    @EnvironmentObject var appDelegate: AppDelegate
    @State var offer: Offer?

    var body: some View {
        List {
            Button("Request authorization") {
                Task {
                    await requestAuthorization()
                }
            }
            Button(#"Send "Special offer" notification"#) {
                sendOfferNotification(withIdentifier: "offer.special")
            }
            Button(#"Send "10% offer" notification"#) {
                sendOfferNotification(withIdentifier: "offer.ten_percent")
            }
        }
        .onReceive(appDelegate.newOfferSubject) { newOffer in
            self.offer = newOffer
        }
        .sheet(item: $offer) { offer in
            switch offer {
            case .special:
                Text("Special offer")
            case .tenPercent:
                Text("10% offer")
            }
        }
    }
}
extension ContentView {
    private func requestAuthorization() async {
        do {
            let granted = try await UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound])
            print("Request authorization for notifications granted: \(granted).")
        } catch {
            print("Error while requesting authorization for notifications: \(error).")
        }
    }

    private func sendOfferNotification(withIdentifier identifier: String) {
        let content = UNMutableNotificationContent()
        content.title = "New offer"
        content.body = "We have an offer for you."
        content.categoryIdentifier = identifier
        let notificationRequest = UNNotificationRequest(identifier: "OfferIdentifier", content: content, trigger: nil)
        UNUserNotificationCenter.current().add(notificationRequest, withCompletionHandler: nil)
    }
}
Hellfire answered 15/8, 2024 at 17:34 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.