如何在 SwiftUI 中将通知深度链接到屏幕?

时间:2021-06-26 17:21:32

标签: swift swiftui apple-push-notifications appdelegate

我正在尝试在我的应用中设置深层链接。我已经设置了应用程序以及推送通知。但是,我无法从 AppDelegate 接收用户单击通知到我想要深层链接到的屏幕的位置完成最终链接。我基本上想从 AppDelegate 调用 viewRouter.goToFred()。我在此处 (https://github.com/cameronhenige/SwiftUITestDeepLink) 设置了一个 git 存储库,其中包含一个应用程序,该应用程序设置了除最后一部分之外的所有内容。有人可以帮我解决这个问题吗?这是相关的代码片段。谢谢!



import SwiftUI

struct MainView: View {
    
    @EnvironmentObject var viewRouter: ViewRouter

    var body: some View {
        NavigationView {

            List {

            ForEach(viewRouter.pets) { pet in
                NavigationLink(
                    destination: PetView(),
                    tag: pet,
                    selection: $viewRouter.selectedPet,
                    label: {
                        Text(pet.name)
                    }
                )
            }
                Button("Send Notification to Fred") {
                    viewRouter.sendNotification()
                }
                
                Button("Manually go to Fred") {
                    viewRouter.goToFred()
                }
            }
            

        }
    }
}

struct MainView_Previews: PreviewProvider {
    static var previews: some View {
        MainView()
    }
}



import SwiftUI

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

    var body: some Scene {
        WindowGroup {
            MainView().environmentObject(ViewRouter())

        }

}
    
}


import Foundation
import UserNotifications

class ViewRouter: ObservableObject {
    @Published var selectedPet: Pet? = nil
    @Published var pets: [Pet] = [Pet(name: "Louie"), Pet(name: "Fred"), Pet(name: "Stanley")]
    
    
    func goToFred() {
        self.selectedPet = pets[1]
    }
    
    func sendNotification() {
        let content = UNMutableNotificationContent()
        let categoryIdentifire = "Notification Type"
        
        content.title = "Go To Fred"
        content.body = "Click me to go to Fred."
        content.sound = UNNotificationSound.default
        content.badge = 1
        content.categoryIdentifier = categoryIdentifire
        
        let request = UNNotificationRequest(identifier: "identifier", content: content, trigger: nil)
        UNUserNotificationCenter.current().add(request) { (error) in
            if let error = error {
                print("Error \(error.localizedDescription)")
            }
        }
        
    }
    
}



import SwiftUI

struct PetView: View {
    
    @EnvironmentObject var viewRouter: ViewRouter

    var body: some View {
        
        if let pet = viewRouter.selectedPet {
            Text(pet.name)
        } else {
            EmptyView()
        }
    }
}

struct PetView_Previews: PreviewProvider {
    static var previews: some View {
        PetView()
    }
}



import Foundation

struct Pet: Identifiable, Hashable {
    var name: String
    var id: String { name }

}



import Foundation
import UIKit

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    let notificationCenter = UNUserNotificationCenter.current()

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
    
        if #available(iOS 10.0, *) {
          // For iOS 10 display notification (sent via APNS)
          UNUserNotificationCenter.current().delegate = self

          let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
          UNUserNotificationCenter.current().requestAuthorization(
            options: authOptions,
            completionHandler: {_, _ in })
        } else {
          let settings: UIUserNotificationSettings =
          UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
          application.registerUserNotificationSettings(settings)
        }

        application.registerForRemoteNotifications()
        
        return true
    }

}

extension AppDelegate: UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
      withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
      let userInfo = notification.request.content.userInfo
        print("Notification created")

      // Change this to your preferred presentation option
      completionHandler([[.alert, .sound]])
    }

    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                didReceive response: UNNotificationResponse,
                                withCompletionHandler completionHandler: @escaping () -> Void) {
      let userInfo = response.notification.request.content.userInfo
        
        print("user clicked on notification. Now take them to Fred.")
        //todo Somehow I want to call viewRouter.goToFred(), but I don't have access to that object in AppDelegate
        
      completionHandler()
    }

}

2 个答案:

答案 0 :(得分:1)

我尝试了这种方法并且它有效。诚然,我不知道这是正确的还是建议的方法。

appDelegate 必须获得对 MainView 正在使用的同一个 ViewRouter 实例的引用,并且 ContentView 必须将 appDelegateViewRouter 挂钩实例。

ContentView.swift:

@main
struct ContentView: App {
    
    let router = ViewRouter()
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
  
    var body: some Scene {
        WindowGroup {
            MainView()
                .environmentObject(router)
                .onAppear(perform:setUpAppDelegate)
        }
    }
    
    func setUpAppDelegate(){
        appDelegate.router = router
    }
}

AppDelegate.swift:

weak var router: ViewRouter?
func userNotificationCenter(_ center: UNUserNotificationCenter,
                            didReceive response: UNNotificationResponse,
                            withCompletionHandler completionHandler: @escaping () -> Void) {
  let userInfo = response.notification.request.content.userInfo
    
    print("user clicked on notification. Now take them to Fred.")
    //todo Update the ViewRouter to
    router?.goToFred()
    
    completionHandler()
}

答案 1 :(得分:0)

Apple's documentation

中非常详细

您只需在 AppDelegate 的 userNotificationCenter(_:didReceive:withCompletionHandler:) 中点击通知时调用您想要运行的方法