181

I am currently opening the link in my app in a WebView, but I'm looking for an option to open the link in Safari instead.

Jack
  • 13,571
  • 6
  • 76
  • 98
Fabian Boulegue
  • 6,476
  • 14
  • 47
  • 72

11 Answers11

412

It's not "baked in to Swift", but you can use standard UIKit methods to do it. Take a look at UIApplication's openUrl(_:) (deprecated) and open(_:options:completionHandler:).

Swift 4 + Swift 5 (iOS 10 and above)

guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.shared.open(url)

Swift 3 (iOS 9 and below)

guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.shared.openURL(url)

Swift 2.2

guard let url = URL(string: "https://stackoverflow.com") else { return }
UIApplication.sharedApplication().openURL(url)    
Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Mike S
  • 41,895
  • 11
  • 89
  • 84
  • Is there any chance from app store if we add some purchasing URL like this? – Jan Sep 16 '16 at 06:23
  • 9
    In iOS 10.0 you must now add options and handler: UIApplication.shared.open(URL(string:"http://www.google.com")!, options: [:], completionHandler: nil) – gabicuesta Apr 04 '17 at 13:46
  • 1
    @gabicuesta You actually don't have to provide options and completionHandler, they default to [:] and nil, respectively – Jeremy Jul 12 '17 at 13:17
  • 1
    iOS14 not open link in Safari if setting "Default Browser" set to other like Google Chrome etc. – Anonimys Dec 03 '20 at 08:42
94

New with iOS 9 and higher you can present the user with a SFSafariViewController (see documentation here). Basically you get all the benefits of sending the user to Safari without making them leave your app. To use the new SFSafariViewController just:

import SafariServices

and somewhere in an event handler present the user with the safari view controller like this:

let svc = SFSafariViewController(url: url)
present(svc, animated: true, completion: nil)

The safari view will look something like this:

enter image description here

manncito
  • 3,814
  • 1
  • 17
  • 16
  • 4
    This is awesome. Thanks! Everyone who wants to show the Safari browser in an app extension should use this code. Accessing the `sharedApplication` property in app extension is forbidden. For more: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/ExtensionOverview.html#//apple_ref/doc/uid/TP40014214-CH2-SW2 – Baran Jul 12 '18 at 14:20
  • 1
    outstanding solution – Mutawe Jul 09 '19 at 20:35
  • 2
    Apple is sometimes rejecting apps from the store for using the old openURL method. This should now be the preferred solution. – disconnectionist Aug 15 '19 at 08:03
21

UPDATED for Swift 4: (credit to Marco Weber)

if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") {
     UIApplication.shared.openURL(requestUrl as URL) 
}

OR go with more of swift style using guard:

guard let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") else {
    return
}

UIApplication.shared.openURL(requestUrl as URL) 

Swift 3:

You can check NSURL as optional implicitly by:

if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") {
     UIApplication.sharedApplication().openURL(requestUrl)
}
CodeOverRide
  • 4,431
  • 43
  • 36
  • It should be (requestUrl!) – Amit Kalra Jun 17 '15 at 23:58
  • 4
    Amit, No, because it's done explicitly as I have explained it is guarantee that requestUrl exist if let requestUrl = ... – CodeOverRide Jun 18 '15 at 21:54
  • Actually, it is. In Swift 2. – Amit Kalra Jun 19 '15 at 18:09
  • Amit, here is code directly from apple https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html: You can also use an implicitly unwrapped optional with optional binding, to check and unwrap its value in a single statement: if let definiteString = assumedString { print(definiteString) } // prints "An implicitly unwrapped optional string." – CodeOverRide Jun 19 '15 at 18:48
  • My way works perfectly fine for me, and this is for Swift 2, remember that. – Amit Kalra Jun 26 '15 at 02:23
  • 2
    yes, there are many way to do things. Learn the reason why you should use certain code in a situation instead of being a stubborn brat saying, "I'm right, therefore your wrong" mentality. Seems like you are new to programming this is my advise to you kid. – CodeOverRide Jun 26 '15 at 23:20
  • 3
    Amit: No, it doesn't work, you are simply wrong. In Swift 2 or 1.2. And no wonder, requestUrl is not an optional so you can't unwrap it with !. – Gusutafu Sep 15 '15 at 13:40
  • 2
    I like this method better than the one from Mike S, because you do the nil check before sending the request. – Nikolaj Simonsen Dec 15 '15 at 15:00
  • 1
    updated for Swift4: `if let requestUrl = NSURL(string: "http://www.iSecurityPlus.com") { UIApplication.shared.openURL(requestUrl as URL) }` – Marco Weber May 03 '18 at 21:01
  • @CodeOverRide , agreed with this method cover all aspect, optional binding is a safe way to implement anything in swift as it prevents from unwanted crashes – Kandhal Bhutiya Oct 19 '20 at 07:25
21

Swift 5

Swift 5: Check using canOpneURL if valid then it's open.

guard let url = URL(string: "https://iosdevcenters.blogspot.com/") else {
     return
}

if UIApplication.shared.canOpenURL(url) {
     UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Kirit Modi
  • 23,155
  • 15
  • 89
  • 112
  • How to verfiy and avoid reopening app Safari if it has been already opened. When lauching I got a warning/error ```LAUNCH: Launch failure with -10652/ { isDir = y, path = '/Applications/Safari.app' } ``` – JeanNicolas Dec 17 '21 at 17:37
12

Swift 3 & IOS 10.2

UIApplication.shared.open(URL(string: "http://www.stackoverflow.com")!, options: [:], completionHandler: nil)

Swift 3 & IOS 10.2

ramchandra n
  • 1,957
  • 1
  • 15
  • 15
  • But note that using this version will stop your app running on iOS 9 and previous unless you version check it – CupawnTae May 10 '17 at 09:04
11

since iOS 10 you should use:

guard let url = URL(string: linkUrlString) else {
    return
}
    
if #available(iOS 10.0, *) {
    UIApplication.shared.open(url, options: [:], completionHandler: nil)
} else {
    UIApplication.shared.openURL(url)
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112
Samira
  • 844
  • 13
  • 17
2

In Swift 1.2:

@IBAction func openLink {    
    let pth = "http://www.google.com"
    if let url = NSURL(string: pth){
        UIApplication.sharedApplication().openURL(url)
}
Chris K
  • 11,622
  • 1
  • 36
  • 49
Amit Kalra
  • 4,085
  • 6
  • 28
  • 44
1

In Swift 2.0:

UIApplication.sharedApplication().openURL(NSURL(string: "http://stackoverflow.com")!)
Kaptain
  • 1,358
  • 12
  • 20
1

Swift 5

if let url = URL(string: "https://www.google.com") {
    UIApplication.shared.open(url)
}
sohil
  • 818
  • 2
  • 15
  • 38
1

if your using SwiftUI:

Link("Stack Overflow", destination: URL(string: "https://www.stackoverflow.com/")!)
dqualias
  • 348
  • 1
  • 3
  • 12
0

IOS 11.2 Swift 3.1- 4

let webView = WKWebView()

override func viewDidLoad() {
    super.viewDidLoad()
    guard let url = URL(string: "https://www.google.com") else { return }
    webView.frame = view.bounds
    webView.navigationDelegate = self
    webView.load(URLRequest(url: url))
    webView.autoresizingMask = [.flexibleWidth,.flexibleHeight]
    view.addSubview(webView)
}

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    if navigationAction.navigationType == .linkActivated  {
        if let url = navigationAction.request.url,
            let host = url.host, !host.hasPrefix("www.google.com"),
            UIApplication.shared.canOpenURL(url) {
            UIApplication.shared.open(url)
            print(url)
            print("Redirected to browser. No need to open it locally")
            decisionHandler(.cancel)
        } else {
            print("Open it locally")
            decisionHandler(.allow)
        }
    } else {
        print("not a user click")
        decisionHandler(.allow)
    }
}
Olcay Ertaş
  • 5,987
  • 8
  • 76
  • 112