authentication - SwiftUI 确定初始视图
问题描述
我试图弄清楚我在 SwiftUI 生命周期中制作的应用程序开始时的导航。根据启动时确定的设置,用户可以从三个视图之一开始。如果用户通过推送通知打开应用程序,他们应该会看到视频视图 (WrappedVideoViewController)。否则,如果他们已经登录,他们应该看到 Home 视图,如果没有,他们应该看到 Login 视图。我使用 ContentView 作为父级:
import SwiftUI
struct ContentView: View {
@EnvironmentObject var notifService: NotificationService
@EnvironmentObject var authState: AuthenticationState
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
@ObservedObject var viewRouter: ViewRouter
init() {
self.viewRouter = ViewRouter.shared
}
var body: some View {
print("in ContentView body")
switch viewRouter.currentScreen {
case .home:
print("home")
return AnyView(Home(innerGradientColor: Color.homeActiveInner, outerGradientColor: Color.homeActiveOuter))
case .login:
print("login")
return
AnyView(Login()
.environmentObject(AuthenticationState.shared))
case .video:
print("video")
return AnyView(WrappedVideoViewController())
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(AuthenticationState.shared)
.environmentObject(NotificationService())
}
}
我的 ViewRouter 类是一个 ObservableObject,用于控制显示哪个屏幕。目前,我有这个:
//
// NavigationState.swift
// BumpCall-SwiftUI
//
// Created by Ben on 1/22/21.
//
import Foundation
import SwiftUI
enum Screen {
case home
case video
case login
}
class ViewRouter: ObservableObject {
var authState: AuthenticationState
var notifService: NotificationService
static var shared = ViewRouter(authState: AuthenticationState.shared, notifService: NotificationService.shared)
init(authState: AuthenticationState, notifService: NotificationService) {
self.authState = authState
self.notifService = notifService
if notifService.dumbData != nil {
currentScreen = .video
} else if (notifService.dumbData == nil && authState.isLoggedIn()) {
currentScreen = .home
} else {
currentScreen = .login
}
}
@Published var currentScreen: Screen
}
这很棘手,因为 ViewRouter 依赖于另外两个 ObservableObjects,我在这里尝试使用 init() 来处理它们。AuthenticationState 类似乎工作正常,因为在打开应用程序时,如果您已登录,它确实会将您发送到主屏幕。但是,从通知中打开也会将我发送到主屏幕。NotificationService 更改 didReceive 响应中的 ViewRouter 单例:方法:
class NotificationService: NSObject, ObservableObject {
@Published var dumbData: UNNotificationResponse?
static var shared = NotificationService()
override init() {
super.init()
UNUserNotificationCenter.current().delegate = self
}
}
extension NotificationService: UNUserNotificationCenterDelegate {
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
print("presenting notification")
}
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
ViewRouter.shared.notifService.dumbData = response
print("Notification service didReceive response")
completionHandler()
}
func userNotificationCenter(_ center: UNUserNotificationCenter, openSettingsFor notification: UNNotification?) { }
}
但是单例不能更新 ContentView 以引起注意。这非常令人费解,这几天让我感到困惑,任何帮助将不胜感激。
解决方案
问题是它ViewRouter
init()
会被调用一次。正如您所提到的,当用户登录时,currentScreen
将被初始化为.home
. 但是,此变量之后将永远不会更改。
您基本上想要的是设置在通知委托内部currentScreen
。.video
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
ViewRouter.shared.currentScreen = .video //<< here set video
print("Notification service didReceive response")
completionHandler()
}
推荐阅读
- python - 如何创建字典值是字典列表的字典?
- twilio - 如何设置与多对人的 Twilio SMS 对话
- testing - symfony 4 - 针对不同数据测试命令
- java - 无法弄清楚为什么 java 在 if else 语句之后忽略了我的 print 语句
- sqlite - 无法在 SQLite 中创建新表,在表名附近出现错误
- git - 恢复推送的合并以删除错误推送的本地不需要的更改
- netlogo - 为什么 NetLogo 中的邻居补丁不以海龟位置为中心?另外,在邻居处设置“目标”时,为什么不互惠?
- docker - Docker Build 抛出错误-“Docker 输出被剪裁,日志限制达到 1MiB”
- grid-search - 为什么 GridSearchCV 中每个任务的时间在估计期间会增加?
- python - 在python 3中猜数字游戏