1

I created a quick sample app that is just a page with a button in it that when clicked launches SFSafariViewController with a URL pointing at my localhost page that I created. The localhost page just has a single link on it pointing at mytestapp://hello. I registered the mytestapp url scheme in my app settings in Xcode by adding it to the "URL Types" section. The plan was to make sure the URL scheme is working before implementing it into my main app that I am building, but nothing is happening when I click the link in the localhost page. The SFSafariViewController loads perfectly, the localhost page loads properly, I click the link and nothing happens.

I have added a simple print statement in the application(:url:options) method in app delegate, but that never gets run.

Here is the ViewController code...

import UIKit
import SafariServices

class ViewController: UIViewController, SFSafariViewControllerDelegate {

    @IBOutlet weak var launchButton: UIButton!


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func launchTap(_ sender: UIButton) {
        guard let url = URL(string: "http://localhost.dcom/test/proof.php") else {
            print("Unable to create the URL")
            return
        }
        let authorizationController = SFSafariViewController(url: url)
        authorizationController.delegate = self
        present(authorizationController, animated: true, completion: nil)
    }



    func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
        print("safari completed")
    }
}

and the app delegate method here...

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        print("app received url: \(url)")
        guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true), let message = components.path else {
            print("Invalid URL")
            return false
        }
        print("The message received was \(message)")
        return true
    }

I can't figure out why this isn't working, seems like I did everything I was supposed to, but the print lines in app delegate never get called.

Not sure if you need it or not, but just in case, my localhost page is literally just...

<?php
    echo '<a href="mytestapp://hello">Here goes nothing</a>';

Is there something that might not be working in an emulator in xcode and it has to be on an actual device for URL schemes to work? Did I miss a step somewhere? somethings else I have no idea? Any help would be really appreciated. Thank you

Neglected Sanity
  • 1,770
  • 6
  • 23
  • 46
  • 2
    Is this iOS 13 and are you using scenes? If so, you'll need to implement [scene(_:openURLContexts:)](https://developer.apple.com/documentation/uikit/uiscenedelegate/3238059-scene) in your scene delegate. I believe if you're using scenes then `application(_:open:options:)` will not be called. – TylerP Dec 10 '19 at 21:54
  • I don't believe so. I see there is a scene delegate, but the link comes from a webpage, so I am not sure how I would implement the open function since I am not opening the link, per se, I am just responding to a weblink. I could be wrong, I am definitely no expert here. – Neglected Sanity Dec 10 '19 at 22:11
  • 1
    If you have a scene delegate then you are using scenes unless you've taken measures to opt out of using them. Try implementing the scene delegate method I mentioned, put a breakpoint or print statement in it, and see if it gets called when you tap your link. – TylerP Dec 10 '19 at 22:16
  • Does this answer your question? [Method 'application:openURL:options:' is not called](https://stackoverflow.com/questions/58624786/method-applicationopenurloptions-is-not-called) – Hejazi Dec 17 '19 at 11:37

2 Answers2

0

Here is a test project

Only change I have done is update webpage to following. Nothing wrong with PHP you have it's because I don't have PHP setup.

Also, you get callbacks in Scene Delegate's

func scene(_ scene: UIScene, openURLContexts URLContexts: Set)

<html>
<body>
    <a href="mytestapp://hello">Here goes nothing</a>
</body>
</html>
k-thorat
  • 4,873
  • 1
  • 27
  • 36
  • Adding the print code to the scene method worked. Is there any trick to making this work on iOS12.0 without scenes? I have pretty much the same setup in my actual app, just without scenes and I am not getting the print messages – Neglected Sanity Dec 10 '19 at 23:50
  • Use AppDelegate's openURL delegate in that case. Rest should be the same – k-thorat Dec 11 '19 at 01:08
0

I have nowhere seen summary on the internet that you must handle deep link in four places. Here you are correct way to handle deep links considering both AppDelegate (iOS < 13 e.g. nowadays still supported iOS v12.x) and SceneDelegate (iOS >= 13)...

AppDelegate.swift (iOS < 13 e.g. nowadays still supported iOS v12.x)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // In case app is not running
    if let launchOptions = launchOptions, let url = launchOptions[.url] as? URL {
        deepLinkHandler(url: url);
    }

    return true;
}
    
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool {
    // In case app is running
    deepLinkHandler(url: url);

    return true;
}

SceneDelegate.swift (iOS >= 13)

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    // In case app is not running
    if let urlContext = connectionOptions.urlContexts.first {
        deepLinkHandler(url: urlContext.url);
    }
}

func scene(_ scene: UIScene, openURLContexts: Set<UIOpenURLContext>) {
    // In case app is running
    if let urlContext = openURLContexts.first {
        deepLinkHandler(url: urlContext.url);
    }
}

Extensions.swift

func deepLinkHandler(url: URL) {
    // TODO: process deep link here
}
mikep
  • 5,880
  • 2
  • 30
  • 37