ios 与AppDelegate和SceneDelegate的深层链接

mwyxok5s  于 2022-12-01  发布在  iOS
关注(0)|答案(4)|浏览(270)

我正在尝试实现深层链接来导航到一个应用程序上的帖子,这是一个旧的项目,所以我不得不添加SceneDelegate类。深层链接的实现只有在应用程序处于活动状态或后台时才能工作。如果应用程序尚未加载,深层链接将无法工作。我看过很多关于这方面的帖子和教程,但还没有找到原因,有人遇到过类似的问题吗?
AppDelegate类中,我添加了实现来处理以下函数的链接:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {}

func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {}

SceneDelegate中,我在以下函数中实现了对链接的处理:

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

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {}

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {}

这些函数的实现如下所示:

let navigator = Navigator()
navigator.getDesination(for: url)

func getDesination(for url: URL){
    let destination = Destination(for: url)
    let ivc = InstantiateViewController()
    switch destination {
    case .post(let postID):
        ivc.openPostVC(id: postID, showComment: true, commentID: nil)
    case .user(let userID):
        ivc.openProfileVC(userID: userID)
    default:
        break
    }
}

enum Destination {
    case post(Int)
        
    case user(Int)
            
    case feed(String)
            
    case store
            
    case safari
            
    init(for url: URL){
        if(url.pathComponents[1] == "p"){
            self = .post(Int(url.pathComponents[2])!)
        } else if(url.pathComponents[1] == "user") {
            self = .user(Int(url.pathComponents[2])!)
        } else if(url.pathComponents[1] == "store") {
            self = .store
        } else if(url.pathComponents[1] == "s") {
            self = .feed(url.pathComponents[2])
        } else {
            self = .safari
        }
    }
}

func openProfileVC(userID: Int){
    let service = UserPool.shared.request(for: userID)
                    
    let storyboard = UIStoryboard(name: "Profile", bundle: nil)
    let profileVC = storyboard.instantiateViewController(withIdentifier: "ProfileView") as! ProfileViewController
    profileVC.userService = service
    profileVC.shouldNavigateToHome = true
    profileVC.shouldNavigateToHomeAction = {
        self.loadMainStoryboard()
    }
        
    let navigationVC = UINavigationController(rootViewController: profileVC)
    navigationVC.view.backgroundColor = .white
    
    if #available(iOS 13.0, *) {
        guard let sceneDelegate = UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate else {return}
        sceneDelegate.window?.rootViewController = navigationVC
        sceneDelegate.window?.makeKeyAndVisible()
    } else {
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
        appDelegate.window?.rootViewController = navigationVC
        appDelegate.window?.makeKeyAndVisible()
    }
}

网站的app-site-assocation文件如下所示,并已在Xcode中添加了关联的域:

{"applinks":{"apps":[],"details":[{"appID":"{my ID}","paths":["*"]}]},"webcredentials":{"apps":["{my ID}"]}}
9q78igpj

9q78igpj1#

在iOS 13及更高版本中,通过场景代理,您的应用可以在启动时观察传入的通用链接事件,如下所示:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    if let url = connectionOptions.userActivities.first?.webpageURL {
       // ... or might have to cycle thru multiple activities
    }
}

如果应用程序已在运行,请使用以下命令:

func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
    if let url = userActivity.webpageURL {
        // ...
    }
}

(我有一个非常简单的downloadable demo app,它证明了它确实有效。我不理解它不起作用的说法;也许问题在于不了解如何测试。)

o8x7eapl

o8x7eapl2#

我没有找到答案,所以我决定解决这个问题。我只恢复到AppDelegate,在这种情况下,只有当应用程序处于活动状态或后台时,深层链接才能工作。为了解决这个问题,我决定将URL存储在UserDefaults中。因此,我在didFinishLaunchingWithOptions函数中添加了以下内容:

if let url = launchOptions?[UIApplication.LaunchOptionsKey.url] as? URL {
            UserDefaults.setURLToContinue(urlString: url.absoluteString)
        } else if let activityDictionary = launchOptions?[UIApplication.LaunchOptionsKey.userActivityDictionary] as? [AnyHashable: Any] {
            for key in activityDictionary.keys {
                if let userActivity = activityDictionary[key] as? NSUserActivity {
                       if let url = userActivity.webpageURL {
                        UserDefaults.setURLToContinue(urlString: url.absoluteString)
                    }
                }
            }
        }

下面是我创建的UserDefaults扩展:

extension UserDefaults {
    
    class func setURLToContinue(urlString: String){
        UserDefaults.standard.set(urlString, forKey: "continueURL")
    }
    
    class func getURLToContinue() -> String? {
        return UserDefaults.standard.string(forKey: "continueURL")
    }
    
    class func removeURLToContinue(){
        UserDefaults.standard.removeObject(forKey: "continueURL")
    }
    
}

最后,在初始视图控制器的viewDidLoad函数中,我处理链接:

if let urlString = UserDefaults.standard.string(forKey: "continueURL") {
            let url = URL(string: urlString)!
            let navigator = Navigator()
            navigator.getDesination(for: url)
            UserDefaults.removeURLToContinue()
        }

其中Navigator类决定将哪个视图控制器压入导航堆栈
在这之后一切都很完美

tp5buhyn

tp5buhyn3#

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

//---------
//-------

 func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
  for context in URLContexts {
    print("url: \(context.url.absoluteURL)")
    print("scheme: \(context.url.scheme)")
    print("host: \(context.url.host)")
    print("path: \(context.url.path)")
    print("components: \(context.url.pathComponents)")
  }
 }

}
epfja78i

epfja78i4#

来自苹果文档:
如果您的应用已选择进入Scenes,并且您的应用未运行,则系统会在启动后将URL传递给scene(:willConnectTo:options:)委托方法,并在应用运行或挂起在内存中时打开URL时将URL传递给scene(:openURLContexts:)。
完整示例:
应用程序终止时在场景代理中:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    let url = connectionOptions.urlContexts.first?.url
}

以及当应用程序是后台或前台时:

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

相关问题