如何将数据从自定义网址方案传递到SwiftUI中的视图?

时间:2019-09-24 09:25:08

标签: ios xcode swiftui

在iOS中不乏有关处理自定义URL方案的提示和教程。 ALL所做的全部实际上是向您展示了如何将这些URL解析的数据传递给您的应用程序/视图。是的,我可以使用全局变量,但这不是“正确”的方法,而且,如果您希望Swift视图对该全局变量的更改做出反应,则不能。

例如,我有

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>){
    let urlContext = URLContexts.first // Because I don't know how to properly deal with Sets
    if let url = urlContext?.url{
        guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
            let params = components.queryItems else {
                print("Invalid URL or album path missing")
                return
        }
        if let token = params.first(where: { $0.name == "token" })?.value {
            print("Token: \(token)")
            MyGlobalToken = token
        }
    }        
}

您将在其中看到MyGlobalToken选项,该选项有效,但是我无法响应该变量的更改。我需要对self.window?.rootViewController做些什么,但是找不到有关该怎么做的任何文档。还是您设置了“通知”,以便您查看响应?还是在SwiftUI中尚未实现?

FWIW我是iOS开发的新手。

2 个答案:

答案 0 :(得分:1)

我在这个问题上有很多麻烦。 我对IOS并不了解很多。 但是没有答案。我写 如果不使用sceneDelegate,则可以使用全局变量。 (我不知道为什么它不起作用)

为此,我喜欢以下内容。

  1. 删除scenedelegate.swift。
  2. 删除sceneDelegate Info.plist中的内容
  3. initialLize检查变量

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            // Override point for customization after application launch.
            UserDefaults.check = ""
            return true
        }
    
  4. 在Appdelegate中添加用于设置全局变量的行。

    open func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { 
        //set Global variable 
        // ... You should add check url for your application ...
        UserDefaults.check = "checked"
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
             if let uservc = self.storyboard?.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController
             {
                 if #available(iOS 13.0, *) {
                    uservc.isModalInPresentation = true
                 }
                 uservc.debugText.text = "This is openUrl State"
                 self.present(uservc, animated: false) {
    
              }      
          }
    }
    
  5. 制作IntroViewController和MainViewController

    IntroViewController是rootviewcontroller。

    和MainViewController是第二个视图控制器。

    如果check变量为“ checked”,则不会执行IntroView中的Viewdidload。

    这次是应用程序公开,使用野生动物园或Chrome浏览器。

    //IntroViewController
    class IntroViewController: UIViewController {
      override func viewDidLoad() {
      super.viewDidLoad()
      DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
        if UserDefaults.check.elementsEqual("") {
           if let uservc = 
              self.storyboard?.instantiateViewController(withIdentifier: "MainViewController") as? MainViewController
            {
                if #available(iOS 13.0, *) {
                    uservc.isModalInPresentation = true
                }
                uservc.debugText.text = "This is normal State"
                self.present(uservc, animated: false) {
                }
            }
        }
      }
    

6。全局变量

    //UserDefaults.swift
    import Foundation
    fileprivate let keyCheck = "keyCheck"

    extension UserDefaults {
       static var check: String {
         get {
            return UserDefaults.standard.string(forKey: keyCheck) ?? ""
         }
         set(value) {
            UserDefaults.standard.set(value, forKey: keyCheck)
            UserDefaults.standard.synchronize()
         }
      }
    }

当我在scenedelegate中使用此逻辑时,它不能很好地工作。(我无法检查“检查变量”。)

答案 1 :(得分:0)

这里很棒blog,用于了解iOS 13中的SceneDelegate。

第一个答案不是一个好答案。

如果您从完全不活动的状态运行应用程序(即从XCode aka重新启动或不在后台运行时运行),则应用程序将调用func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)方法来初始化场景基础结构。

如果您在Safari中指向URL时在后台运行应用程序,则该应用程序将调用func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)方法。

为了更全面,您将不得不尝试在两种方法中获取url参数。您也可以通过两种方法将此查询传递给AppDelegate,以供ViewControllers将来使用。

注意:如果应用打开的第一个ViewController需要URL查询信息,则您需要执行一些额外的步骤。要使ViewController实际更新这些信息,您需要使用sceneDidBecomeActive()方法,用于从非活动状态/在后台运行应用程序的时间。此方法将必须在ViewController中调用一个方法,以便在用户进入您的应用程序时从应用程序委托中提取变量。在这种情况下,我使用了viewDidLoad()方法来从AppDelegate中提取更新的变量。

下面是完整的代码供参考:

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    let appDelegate = UIApplication.shared.delegate as! AppDelegate


    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        appDelegate.query = connectionOptions.urlContexts.first?.url.query ?? "No query"
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
        appDelegate.query = URLContexts.first?.url.query
    }

    func sceneDidDisconnect(_ scene: UIScene) {}

    // Only needed if first ViewController needs updated AppDelegate Variable
    func sceneDidBecomeActive(_ scene: UIScene) {
        self.window?.rootViewController?.viewDidLoad()
    }

    func sceneWillResignActive(_ scene: UIScene) {}

    func sceneWillEnterForeground(_ scene: UIScene) {}

    func sceneDidEnterBackground(_ scene: UIScene) {
        (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
    }

}