25

My code:

if let url = NSURL(string: "www.google.com") {
    let safariViewController = SFSafariViewController(URL: url)
    safariViewController.view.tintColor = UIColor.primaryOrangeColor()
    presentViewController(safariViewController, animated: true, completion: nil)
}

This crashes on initialization only with exception:

The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported

When I use url = NSURL(string: "http://www.google.com"), everything is fine. I am actually loading URL's from API and hence, I can't be sure that they will be prefixed with http(s)://.

How to tackle this problem? Should I check and prefix http:// always, or there's a workaround?

Sahil Kapoor
  • 11,183
  • 13
  • 64
  • 87
  • see this link may be help you http://stackoverflow.com/questions/32577727/uiwebview-does-not-show-images-on-ios-9-and-safariviewcontroller-does-not-load – Anbu.Karthik Sep 30 '15 at 11:02
  • I checked that out, it isn't related. I am already allowing arbitrary loading. That issue is not allowing connection and not loading local html by SFSafariController. – Sahil Kapoor Sep 30 '15 at 11:06
  • 4
    Kind of makes you wish there were a `SFSafariViewController.canOpen(url:)`-ish way of checking supported urls. – Jonny Dec 05 '17 at 07:37

5 Answers5

43

Try checking scheme of URL before making an instance of SFSafariViewController.

Swift 3:

func openURL(_ urlString: String) {
    guard let url = URL(string: urlString) else {
        // not a valid URL
        return
    }

    if ["http", "https"].contains(url.scheme?.lowercased() ?? "") {
        // Can open with SFSafariViewController
        let safariViewController = SFSafariViewController(url: url)
        self.present(safariViewController, animated: true, completion: nil)
    } else {
        // Scheme is not supported or no scheme is given, use openURL
        UIApplication.shared.open(url, options: [:], completionHandler: nil)
    }
}

Swift 2:

func openURL(urlString: String) {
    guard let url = NSURL(string: urlString) else {
        // not a valid URL
        return
    }

    if ["http", "https"].contains(url.scheme.lowercaseString) {
        // Can open with SFSafariViewController
        let safariViewController = SFSafariViewController(URL: url)
        presentViewController(safariViewController, animated: true, completion: nil)
    } else {
        // Scheme is not supported or no scheme is given, use openURL
        UIApplication.sharedApplication().openURL(url)
    }
}
alanhchoi
  • 1,160
  • 2
  • 11
  • 17
13

You can check for availability of http in your url string before creating NSUrl object.

Put following code before your code and it will solve your problem (you can check for https also in same way)

var strUrl : String = "www.google.com"
if strUrl.lowercaseString.hasPrefix("http://")==false{
     strUrl = "http://".stringByAppendingString(strUrl)
}
Yuvrajsinh
  • 4,536
  • 1
  • 18
  • 32
  • 2
    Yeah, this is a solution I mentioned in the question itself. I want to know if there are some workarounds or better way to tackle this? – Sahil Kapoor Sep 30 '15 at 12:10
  • @SahilKapoor As of now I can't find any better solution for it, if you could find it then also mention it for future reference – Yuvrajsinh Sep 30 '15 at 12:56
  • I recommend avoiding parsing the string by hand... unless you are working at the RFCs level of the URL formatting. Use -> https://developer.apple.com/documentation/foundation/url/1780352-scheme – benc Dec 07 '22 at 06:19
10

I did a combination of Yuvrajsinh's & hoseokchoi's answers.

func openLinkInSafari(withURLString link: String) {

    guard var url = NSURL(string: link) else {
        print("INVALID URL")
        return
    }

    /// Test for valid scheme & append "http" if needed
    if !(["http", "https"].contains(url.scheme.lowercaseString)) {
        let appendedLink = "http://".stringByAppendingString(link)

        url = NSURL(string: appendedLink)!
    }

    let safariViewController = SFSafariViewController(URL: url)
    presentViewController(safariViewController, animated: true, completion: nil)
}
Dylan
  • 545
  • 4
  • 15
  • As sample code, I think adding `http` makes sense, but in the real world, maybe it should be `https`? – benc Dec 23 '22 at 05:48
3

Use WKWebView's method (starting iOS 11),

class func handlesURLScheme(_ urlScheme: String) -> Bool
infiniteLoop
  • 2,135
  • 1
  • 25
  • 29
-1

you can add to

  NSString* webStringURL = [url stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
  NSURL *URL = [NSURL URLWithString: webStringURL];
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 14 '21 at 17:05