如何在 SwiftUI 中从通知深层链接到屏幕?
Posted
技术标签:
【中文标题】如何在 SwiftUI 中从通知深层链接到屏幕?【英文标题】:How can I deep link from a notification to a screen in SwiftUI? 【发布时间】:2021-06-26 17:21:32 【问题描述】:我正在尝试在我的应用中设置深层链接。我已经设置了应用程序以及推送通知。但是,我无法完成 AppDelegate 接收用户点击通知的最终链接,该链接指向我想要深度链接到的屏幕。我基本上想从 AppDelegate 调用 viewRouter.goToFred() 。我在这里设置了一个 git repo (https://github.com/cameronhenige/SwiftUITestDeepLink),其中有一个应用程序,除了最后一块之外,所有的东西都设置好了。有人可以帮我解决这个问题吗?以下是相关的代码片段。谢谢!
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()
【问题讨论】:
【参考方案1】:我尝试了这种方法,它很有效。诚然,我不知道这是正确的还是建议的方式。
appDelegate
必须引用 MainView 正在使用的同一 ViewRouter
实例,并且 ContentView
必须将 appDelegate
与 ViewRouter
实例挂钩。
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()
【讨论】:
谢谢!我猜这可能是推荐的这样做方式,因为它看起来很优雅。我希望 Apple 能够提供更多 SwiftUI 示例,展示此类事物的最佳实践。【参考方案2】:Apple's documentation里写的很详细
您所要做的就是在AppDelegate中点击userNotificationCenter(_:didReceive:withCompletionHandler:)
中的通知时调用您要运行的方法
【讨论】:
我得到了那个部分。但是,如果我将“@EnvironmentObject var viewRouter: ViewRouter”放在 AppDelegate 中,XCode 会抛出错误“未知属性 'EnvironmentObject'”。所以,问题是如果我不能在 AppDelegate 中实例化我想要调用的方法,我该如何调用它?以上是关于如何在 SwiftUI 中从通知深层链接到屏幕?的主要内容,如果未能解决你的问题,请参考以下文章