Use single VC with WebView to access multiple URLs

I have various view controllers that contain several buttons, and each button when pressed presents a view controller with a web view that displays the website. The full code I'm using, which work fine, for each is below.


import UIKit
import WebKit

class WebViewController: UIViewController , WKNavigationDelegate, WKUIDelegate, UITextFieldDelegate {
    
    
    @IBOutlet weak var urlTextField: UITextField!
    @IBOutlet weak var himedWebView: WKWebView!
    
    @IBOutlet weak var actIndicator: UIActivityIndicatorView!
    
    @IBOutlet weak var webpageBack: UIButton!
    
    @IBOutlet weak var webpageForward: UIButton!
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        urlTextField.delegate = self
        himedWebView.navigationDelegate = self
        
    }

    // Do any additional setup after loading the view.
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear( animated )
        
        let urlString:String = "http://www.google.com"
        let url:URL = URL(string: urlString)!
        let urlRequest:URLRequest = URLRequest(url: url)
        himedWebView.load(urlRequest)
        actIndicator.startAnimating()
        urlTextField.text = urlString
    }
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        actIndicator.startAnimating()
    }

    
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        
        let urlString:String = urlTextField.text!
        let url:URL = URL(string: urlString)!
        let urlRequest:URLRequest = URLRequest(url: url)
        
        himedWebView.load(urlRequest)
        
        urlTextField.resignFirstResponder()
        
        return true
        
        
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    
    /*
     // MARK: - Navigation
     
     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destinationViewController.
     // Pass the selected object to the new view controller.
     }
     */
    
    
    @IBAction func fwdButtonTapped(_ sender: Any) {
        
        if himedWebView.canGoForward {
            himedWebView.goForward()
        }
    }
    
    @IBAction func backButtonTapped(_ sender: Any) {
        
        if himedWebView.canGoBack {
            himedWebView.goBack()
        }
    }
    
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        webpageBack.isEnabled = himedWebView.canGoBack
        webpageForward.isEnabled = himedWebView.canGoForward
        
        urlTextField.text = himedWebView.url?.absoluteString
        actIndicator.stopAnimating()
        actIndicator.hidesWhenStopped = true
    }

    @IBAction func webviewDone(_ sender: Any) {
        self.dismiss(animated: true, completion: nil)
    }
}


I want to significantly reduce the number of these individual view controllers by using a performSegue function that will access the various URLs through a single view controller w/web view using a segue identifier. I found an older post elsewhere online that asked a similar question, but I'm not sure how to integrate or replace my code with it.


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let websiteController = segue.destinationViewController as YourVCName
  if segue.identifier == "website1" {
  websiteController.urlWebsite = "google.com"
  } else if segue.identifier == "website2" {
  websiteController.urlWebsite = "stackoverflow.com"
  }
}


Help would be greatly appreciated!

Thanks,

Accepted Reply

Do you mean you have many webviewcontrollers only different with `urlString`?


If so, you can make it a parameter of the view controller.

You need to add a varible to recieve the parameter to your WebViewController:

class WebViewController: UIViewController , WKNavigationDelegate, WKUIDelegate, UITextFieldDelegate {

    //...

    var urlWebsite: String?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear( animated )
        
        guard
            let urlString = urlWebsite,
            let url = URL(string: urlString) else {
                return
        }
        let urlRequest:URLRequest = URLRequest(url: url)
        himedWebView.load(urlRequest)
        actIndicator.startAnimating()
        urlTextField.text = urlString
    }

    //...
}

And `prepareForSegue` for the latest Swift would be:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let websiteController = segue.destination as! WebViewController
        if segue.identifier == "website1" {
            websiteController.urlWebsite = "google.com"
        } else if segue.identifier == "website2" {
            websiteController.urlWebsite = "stackoverflow.com"
        }
    }


But watching the functionality of your WebViewController, you should better consider using SFSafariViewController.

Replies

Do you mean you have many webviewcontrollers only different with `urlString`?


If so, you can make it a parameter of the view controller.

You need to add a varible to recieve the parameter to your WebViewController:

class WebViewController: UIViewController , WKNavigationDelegate, WKUIDelegate, UITextFieldDelegate {

    //...

    var urlWebsite: String?
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear( animated )
        
        guard
            let urlString = urlWebsite,
            let url = URL(string: urlString) else {
                return
        }
        let urlRequest:URLRequest = URLRequest(url: url)
        himedWebView.load(urlRequest)
        actIndicator.startAnimating()
        urlTextField.text = urlString
    }

    //...
}

And `prepareForSegue` for the latest Swift would be:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let websiteController = segue.destination as! WebViewController
        if segue.identifier == "website1" {
            websiteController.urlWebsite = "google.com"
        } else if segue.identifier == "website2" {
            websiteController.urlWebsite = "stackoverflow.com"
        }
    }


But watching the functionality of your WebViewController, you should better consider using SFSafariViewController.

Thank you for your help! I actually ended up goign with the SFSafariViewController suggestion. I just created an action for each button and used the following code:


@IBAction func exampleSFWebView(_ sender: Any) {
        
        guard let url = URL(string: "https://www.google.com")
            else {return}
        let safariViewController = SFSafariViewController (url: url)
        self.present(safariViewController, animated: true, completion: nil)
    }


I think it should work for me! This is so much easier than the custom WKWebView that I was using before. Haven't implemented it throughout my app yet, but I'll follow up if I end up with any issues.


Thanks Again,