SwiftUI - 当用户打开推送通知时打开特定视图
Posted
技术标签:
【中文标题】SwiftUI - 当用户打开推送通知时打开特定视图【英文标题】:SwiftUI - Open a specific View when user opens a Push Notification 【发布时间】:2021-02-19 19:36:44 【问题描述】:有一个用 SwiftUI 制作的应用,Parse 用于 DB。 我在应用程序的某些部分集成了一些发送通知的云功能(例如:当有人向您发送消息时,您将收到由该云功能触发的推送通知)。 在过去的日子里,当您按下通知打开应用程序时,我一直在努力寻找如何打开特定视图。 我找到了一些解决方案,但无法让它们发挥作用。
这是我到目前为止的代码:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
//Parse Intialization
...
//notifications
registerForPushNotifications()
//Notification Badge
UIApplication.shared.applicationIconBadgeNumber = 0
// start notification while app is in Foreground
UNUserNotificationCenter.current().delegate = self
return true
// This function will be called right after user tap on the notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
print("app opened from PushNotification tap")
UIApplication.shared.applicationIconBadgeNumber = 0
completionHandler()
@main
struct MyApp: App
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene
WindowGroup
ContentView(currentTab: Tab.home)
应用程序打印“从 PushNotification 点击打开应用程序”,但如果我在 AppDelegate 中放置一个变量,并使用 .onReceive 或 .onChange 监听 ContentView 中的变化,则什么都不会发生
struct ContentView: View
@ObservedObject var appState = AppState()
@State var currentTab : Tab
@State var noReloadAddItemView = false
var body: some View
TabView(selection: $appState.currentTab)
NavigationView
HomeView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
.tabItem
if appState.currentTab == .home
Image(systemName: "house.fill")
else
Image(systemName: "house")
Text(LocalizedStringKey("HomeTabMenu"))
.tag(Tab.home)
NavigationView
SearchView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
.tabItem
if appState.currentTab == .search
Image(systemName: "magnifyingglass.circle.fill")
else
Image(systemName: "magnifyingglass")
Text(LocalizedStringKey("SearchTabMenu"))
.tag(Tab.search)
NavigationView
AddItemView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
.tabItem
if appState.currentTab == .add
Image(systemName: "plus.circle.fill")
else
Image(systemName: "plus.circle")
Text(LocalizedStringKey("SellTabMenu"))
.tag(Tab.add)
NavigationView
ShoppingCartFavoritesView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
.tabItem
if appState.currentTab == .favorites
Image(systemName: "cart.fill")
else
Image(systemName: "cart")
Text(LocalizedStringKey("CartTabMenu"))
.tag(Tab.favorites)
NavigationView
ProfileView(appState: appState, noReloadAddItemView: $noReloadAddItemView)
.tabItem
if appState.currentTab == .profile
Image(systemName: "person.fill")
else
Image(systemName: "person")
Text(LocalizedStringKey("ProfileTabMenu"))
.tag(Tab.profile)
.accentColor(Color("ColorMainDark"))
struct ContentView_Previews: PreviewProvider
static var previews: some View
ContentView(currentTab: Tab.home)
class AppState: ObservableObject
@Published var currentTab : Tab = .home
enum Tab
case home, search, add, favorites, profile
【问题讨论】:
【参考方案1】:您需要某种可以修改的共享状态,SwiftUI 知道它会做出反应。 ObservableObject
非常适合:
class AppState: ObservableObject
static let shared = AppState()
@Published var pageToNavigationTo : String?
然后,要收听并响应它,您可以在主视图中执行几种不同的方法。
选项 1——基于 ObservedObject 值的 NavigationLink 绑定:
struct ContentView : View
@ObservedObject var appState = AppState.shared //<-- note this
@State var navigate = false
var pushNavigationBinding : Binding<Bool>
.init () -> Bool in
appState.pageToNavigationTo != nil
set: (newValue) in
if !newValue appState.pageToNavigationTo = nil
var body: some View
NavigationView
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding)
EmptyView()
)
struct Dest : View
var message : String
var body: some View
Text("\(message)")
或者,您可以使用onReceive
:
struct ContentView : View
@ObservedObject var appState = AppState.shared
@State var navigate = false
var body: some View
NavigationView
VStack
if navigate
NavigationLink(destination: Text("Test"), isActive: $navigate )
EmptyView()
Text("My content")
.onReceive(appState.$pageToNavigationTo) (nav) in
if nav != nil navigate = true
我会将您的特定 NavigationView、NavigationLink、TabView 等的实现细节留给您,但这应该可以帮助您入门。
最后,一个模拟通知并展示导航视图的全功能最小示例:
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool
DispatchQueue.main.asyncAfter(deadline: .now() + 2)
print("Dispatch")
AppState.shared.pageToNavigationTo = "test"
return true
class AppState: ObservableObject
static let shared = AppState()
@Published var pageToNavigationTo : String?
@main
struct MultiWindowApp: App
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene
WindowGroup
ContentView()
struct ContentView : View
@ObservedObject var appState = AppState.shared
@State var navigate = false
var pushNavigationBinding : Binding<Bool>
.init () -> Bool in
appState.pageToNavigationTo != nil
set: (newValue) in
if !newValue appState.pageToNavigationTo = nil
var body: some View
NavigationView
Text("My content")
.overlay(NavigationLink(destination: Dest(message: appState.pageToNavigationTo ?? ""),
isActive: pushNavigationBinding)
EmptyView()
)
struct Dest : View
var message : String
var body: some View
Text("\(message)")
【讨论】:
我没有意识到你可以在 Swift 中拥有一个 Observable 单例......但我想它检查出来了 您也可以在应用程序委托和视图之间显式传递引用 - 但是,这可能最终需要可选。以上是关于SwiftUI - 当用户打开推送通知时打开特定视图的主要内容,如果未能解决你的问题,请参考以下文章
当用户使用 iOS 13 Swift 5 点击推送通知时,在特定视图中打开应用程序