Day 24 - 100 Days of Swift

4 minute read

Project 4 (part 1)

Day 24 is the beginning of the fourth project, which is to build a simple web browser on top of Apple’s WebKit. You configure the view controller to have a WKWebView as its main view. You load a default web page when the app is launched. You present the user a couple of options in an action sheet of websites that they can navigate to. And finally, you use a WKNavigationDelegate method to set the title in the navigation bar to the current page’s title.

The first thing you do is make a new project and embed the view controller it comes with into a navigation controller. After that, you override loadView() to set the view controller’s view to be a newly instantiated WKWebView:

1
2
3
4
5
6
7
var webView: WKWebView!

override func loadView() {
    webView = WKWebView()
    webView.navigationDelegate = self
    view = webView
}

This leads the compiler to complain because we haven’t adopted the WKNavigationDelegate protocol yet, so it doesn’t know that this view controller can be treated as one. Fortunately, adopting it is easy:

1
class ViewController: UIViewController, WKNavigationDelegate {

Next, in viewDidLoad, you load a default web page, once the view is loaded:

1
2
3
let url = URL(string: "https://dillon-mce.com")!
webView.load(URLRequest(url: url))
webView.allowsBackForwardNavigationGestures = true

The first line builds a URL object from the string. The second line has the webView load the URLRequest that is initialized from the URL object we just built. The third line enables the ability to swipe backward and forward in the webView itself, like you can in Safari.

After that, you add a bar button item to the navigation bar in viewDidLoad:

1
2
3
4
5
navigationItem.rightBarButtonItem =
    UIBarButtonItem(title: "Open",
                    style: .plain,
                    target: self,
                    action: #selector(openTapped))

This again causes the compiler to complain because there is no function called openTapped, so we need to add that. This function presents an action sheet to the user with a list of web pages that they can load:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@objc func openTapped() {
    // Make the controller
    let ac = UIAlertController(title: "Open page...",
                               message: nil,
                               preferredStyle: .actionSheet)

    // Make the actions
    let appleAction = UIAlertAction(title: "apple.com",
                                    style: .default,
                                    handler: openPage)

    let blogAction = UIAlertAction(title: "dillon-mce.com",
                                   style: .default,
                                   handler: openPage)

    let cancelAction = UIAlertAction(title: "Cancel",
                                     style: .cancel)

    // Configure the controller
    ac.addAction(appleAction)
    ac.addAction(blogAction)
    ac.addAction(cancelAction)
    ac.popoverPresentationController?.barButtonItem =
        self.navigationItem.rightBarButtonItem

    // Present it
    present(ac, animated: true)
}

This causes yet another error from the compiler because we don’t have an openPage method, so we’ll add that next. This function takes in a UIAlertAction and uses it’s title to decide what webpage to load:

1
2
3
4
func openPage(action: UIAlertAction) {
    let url = URL(string: "https://" + action.title!)!
    webView.load(URLRequest(url: url))
}

The app works at this point, but you add one final touch to make it feel a little nicer. You use webView(_:didFinish:) to change the title in the navigation bar to the title of the newly loaded webpage:

1
2
3
4
func webView(_ webView: WKWebView,
             didFinish navigation: WKNavigation!) {
    title = webView.title
}

When it’s all said and done it looks like this:

Screenshots of working app.

You can find my version of this project at the end of day 24 on Github here.

Reflections

I had a lot of fun with this project. I’ve never used WebKit before, but it seems like it brings a lot of power with not all that much work, so that’s cool. It was pretty short and simple (not complaining), but I can load whatever webpage I want my app to load after those few simple steps. I’m looking forward to seeing where we take this in the next few days.