Reputation: 1773
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()
}
... }
Upvotes: 11
Views: 2926
Reputation: 92409
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)
}
}
Upvotes: 1
Reputation: 5220
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.
Upvotes: 0