SwiftUI Загрузить представление из SceneDelegate sceneDidBecomeActive - PullRequest
1 голос
/ 22 января 2020

Я пытаюсь понять, как загрузить представление SwiftUI из кода функции Swift. В данном случае, в частности, я хочу загрузить представление при возврате из фонового состояния для покрытия конфиденциальных данных. Я создал вход в систему biometri c, и он отлично работает - чистые представления SwiftUI для приложения. Когда я помещаю приложение в фоновый режим и возвращаюсь, FaceID работает как положено, но основной экран виден. Это также обобщенный вопрос - как вы можете загрузить любое представление SwiftUI из любой функции Swift.

func sceneDidBecomeActive(_ scene: UIScene) {

    if userDefaultsManager.wentToBackground {
        if userDefaultsManager.enableBiometrics {
            BiometricsLogin(userDefaultsManager: userDefaultsManager).authenticate()
            //what I want is something like:
            //BiometricsLogin(userDefaultsManager: userDefaultsManager)
            //kinda like you would do in a TabView
            //that would run the authentication just like starting the app
            userDefaultsManager.wentToBackground = false
        }
    }
}

И код входа в систему довольно обобщенный c:

struct BiometricsLogin: View {
    @ObservedObject var userDefaultsManager: UserDefaultsManager

    var body: some View {
        NavigationView {
            VStack {
                Image("CoifMeCrop180")
                .onAppear {
                    self.authenticate()
                }
            }//vstack
        }//nav
    }

    func authenticate() {
        let context = LAContext()
        var error: NSError?

        if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
            let reason = "The app uses Biometrics to unlock you data"
            context.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reason) { (success, authenticationError)
                in
                DispatchQueue.main.async {
                    if success {
                        self.userDefaultsManager.isAuthenticated = true
                        self.userDefaultsManager.selectedTab = 1
                    } else {
                        if self.userDefaultsManager.enableBiometrics {
                            self.userDefaultsManager.isAuthenticated = false
                            self.userDefaultsManager.selectedTab = 3
                        } else {
                            self.userDefaultsManager.isAuthenticated = false
                            self.userDefaultsManager.selectedTab = 1
                        }
                    }
                }
            }
        } else {
            //no biometrics - deal with this elsewhere
            //consider an alert here
        }
    }//authenticate
}

Я также попытался использовать контроллер хостинга, как это, но он также не работал. Та же проблема, аутентификация работала, но данные были видны.

    //this does not work
    let controller = UIHostingController(rootView: BiometricsLogin(userDefaultsManager: userDefaultsManager))
    self.window!.addSubview(controller.view)
    self.window?.makeKeyAndVisible()

Любое руководство будет оценено. Xcode 11.3.1 (11C504)

1 Ответ

1 голос
/ 22 января 2020

Здесь возможен подход

В sceneDidBecomeActive добавлено представление нового контроллера с аутентификацией в полноэкранном режиме, чтобы скрыть конфиденциальный контент

    func sceneDidBecomeActive(_ scene: UIScene) {
        let controller = UIHostingController(rootView: BiometricsLogin(userDefaultsManager: userDefaultsManager))
        controller.modalPresentationStyle = .fullScreen

        self.window?.rootViewController?.present(controller, animated: false)
    }

теперь необходимо отменить его, когда аутентификация будет выполнена поэтому добавьте уведомление для этой цели ...

extension SceneDelegate {
    static let didAuthenticate = Notification.Name(rawValue: "didAuthenticate")
}

... и подписчик для него в SceneDelegate

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    private var authenticateObserver: AnyCancellable?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            self.authenticateObserver = NotificationCenter.default.publisher(for: SceneDelegate.didAuthenticate)
                .sink { _ in
                    self.window?.rootViewController?.dismiss(animated: true)
                }

            let window = UIWindow(windowScene: windowScene)
            ...

, когда аутентификация выполнена, просто отправьте didAuthenticate уведомление в распустить верхний контроллер

   DispatchQueue.main.async {
        if success {
            self.userDefaultsManager.isAuthenticated = true
            self.userDefaultsManager.selectedTab = 1
        } else {
            if self.userDefaultsManager.enableBiometrics {
                self.userDefaultsManager.isAuthenticated = false
                self.userDefaultsManager.selectedTab = 3
            } else {
                self.userDefaultsManager.isAuthenticated = false
                self.userDefaultsManager.selectedTab = 1
            }
        }
        NotificationCenter.default.post(name: SceneDelegate.didAuthenticate, object: nil)
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...