9

How can I set a rule such that when my user clicks any web link within my app, it opens in the in-app browser instead of Safari?

Context: I'm building an app that has several places where links are either embedded by me or are loaded through various user interactions, e.g. a link leading to a page that houses another link. I want to ensure that the user seldom leaves my app and hence want to open all external web links in an in-app browser that has already been developed

Target Build: iOS 11. Environment/ Language: Swift 4

zaam
  • 287
  • 1
  • 2
  • 14

2 Answers2

14

Simple solution using SFSafariViewController which available in a separate package

import SafariServices

Swift 4, iOS 9.0+

let url = URL(string: "your URL here")
let vc = SFSafariViewController(url: url)
present(vc, animated: true)

If you need more control - use Configuration parameter (Swift 4, iOS 11.0+):

Example:

let config = SFSafariViewController.Configuration()
config.entersReaderIfAvailable = true

let url = URL(string: "your URL here")
let vc = SFSafariViewController(url: url, configuration: config)
present(vc, animated: true)
Petr Lazarev
  • 3,102
  • 1
  • 21
  • 20
3

...it opens in the in-app browser instead of Safari?

In that case, you would need your own WebView. Here's a quick snippet of a simple webView inside a controller:

import UIKit
import WebKit

/// The controller for handling webviews.
class WebViewController: UIViewController {

    // MARK: - Properties
    internal lazy var button_Close: UIButton = {
        let button = UIButton(type: .custom)
        button.setImage(.close, for: .normal)
        button.imageEdgeInsets = UIEdgeInsets.init(top: 0, left: -30, bottom: 0, right: 0)
        button.addTarget(self, action: #selector(back(_:)), for: .touchUpInside)
        return button
    }()

    public var urlString: String! {
        didSet {
            if let url = URL(string: urlString) {
                let urlRequest = URLRequest(url:url)
                self.webView.load(urlRequest)
            }
        }
    }

    private lazy var webView: WKWebView = {
        let webView = WKWebView()
        webView.navigationDelegate = self
        return webView
    }()

    // MARK: - Functions
    // MARK: Overrides

    override func viewDidLoad() {
        super.viewDidLoad()

        let barButton = UIBarButtonItem(customView: self.button_Close)
        self.button_Close.frame = CGRect(x: 0, y: 0, width: 55.0, height: 44.0)
        let negativeSpacer = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.fixedSpace, target: nil, action: nil)
        if #available(iOS 11.0, *) {
            negativeSpacer.width = -30
        }
        self.navigationItem.leftBarButtonItems = [negativeSpacer, barButton]

        self.view.addSubview(self.webView)
        self.webView.snp.makeConstraints {
            $0.edges.equalToSuperview()
        }
    }

    @objc func back(_ sender: Any) {
        self.dismiss()
    }
}

extension WebViewController: WKNavigationDelegate {
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        // Show here a HUD or any loader
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        // Dismiss your HUD
    }
}

and presenting such webViewController, like so (passing a URLString):

let webViewVC = WebViewController()
webViewVC.urlString = "https://www.glennvon.com/"
let navCon = UINavigationController(rootViewController: webViewVC)
self.navigationController?.present(navCon, animated: true, completion: nil)

If you're using storyboard, then simply drag a webview in your controller and setup the delegate. This should help you out :)

Glenn Posadas
  • 12,555
  • 6
  • 54
  • 95
  • Thank you for your reply, something I didn't understand is how would I then be able to open links that are generated through some user interaction or links from another class. For e.g., I do have a fully functional webView where I'm opening certain links. However, in another View managed by another viewController, I have some text with several links embedded - you mean for each link I have to keep presenting the in-app browser? I was thinking more of something like a setting in AppDelegate that prevails throughout the app - does anything like that exist? If not, how can I open these many URLs? – zaam Oct 17 '18 at 01:05
  • That's simple. Just remember that you can only open links one at a time. So whatever kinds of links you have in your project, be it dynamic or static, and you need to visit it, just pass the url string to your webViewVC. I hope this helps. – Glenn Posadas Oct 17 '18 at 03:26
  • The issue is that I have nearly 100 links throughout the app that are embedded in texts. For e.g. imagine a static blog that has several links embedded on some pages while none in others. Is there a smarter way to ensure all these links (even if one at a time) can be opened in the in-app browser that has already been built? Keeping in mind that the text of this blog is dynamically generated in the app. – zaam Oct 17 '18 at 17:10
  • The count does not matter, it's not an issue! This answer should've answered your question since yesterday. Now if you want to embed links into some strings in a whole string, then you can use attributed string or a library such as ActiveLabel, and then, again, just pass the url string to your webview. That's it! – Glenn Posadas Oct 18 '18 at 03:27
  • Thanks. That sort of does give me some direction. – zaam Oct 18 '18 at 22:02