Today’s goal is to create a basic browser.
To get started, we choose a Single View app template, we name is Easy Browser (or Project4, as you prefer), save it to a sensible location and hit Create. We then switch to Main.storyboard and, with our ViewController selected, we go on to Editor > Embed In > Navigation Controller.
Creating a basic browser
This changed in iOS 12 as the previous framework for creating web content was deprecated; we now have WebKit, which is an amazingly powerful framework!
We import it via the
import statement at the top of our ViewController class and then set up a property where to store the WebKit View.
viewDidLoad() method we add a call to one of WebKit’s own methods,
loadView. This introduces the concepts of delegation, where we import functionalities from a protocol and promise to use them in our own class.
We instantiate a
WKWebView, assign its
self (i.e.: the view controller where we are now) and then we assign it (the webView) to the
view property of our view controller (that is, the whole view!).
viewDidLoad(), after the
super call, we store a web
URL containing a web address, we attach that url (shorthand for uniform resource locator) to a call to
webView.load(URLRequest(url: )) and then we allow the swiping back and forward of the pages in the browser with the call to the
For some reason, not all the websites I tried were successfully built in the Simulator.
Choosing a website
We now want to give the user a chance to choose among a few websites and to this we are going to use the
.actionSheet style for the alert.
viewDidLoad we add
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Open", style: .plain, target: self, action #selector(openTapped)), bearing with Xcode’s complaints for a bit more if we can.
We then write the
openTapped function which looks something like this:
addAction call allows us to have an extra button on the action sheet.
We then write the
openPage method, which is just there to set the URL to
https:// plus one of our action titles and to load the
Finally, we call the
webView(didFinish:) method and set the title of our view controller to the webView’s title when the loading of the page has finished.
Monitoring page loads
We are going to meet some important friends here, first of all the
UIToolbar that sits invisible at the bottom of all our view controllers until we call it! It contains an array of
UIBarButtonItems for us to fill with what we want.
We will create a
spacer, which is a system button of type
.flexibleSpace that acts like a spring between all other buttons in the array to space them evenly out and a refresh button, which will call the
webView.reload method automatically.
We also create a
progressButton which is always a
UIBarButtonItem but this time with a
customView which we create as a
UIProgressView with a
.default style. We ask it to size itself to fit and then we populate our array.
From what I could understand, this array’s order reflects the left-to-right disposition of the elements.
Finally, we ask for the toolbar to be shown by setting its
.isToolbarHidden property to false.
Just adding a progress bar is not enough tough because nothing will fill it. We dive now into the realms of
observers and of
keyPath, a subject I feel will take its due time to sink in.
webView.addObserver(self, forKeyPath: #keuPath(WKWebView.estimatedProgress), options: .new, context: nil
Please refer to Paul’s article for the explanation on all what this does, I am pretty sure I could not use clearer words.
We finally call the
observeValue method that will manipulate the
progress property of the
progressView according to the
Clear? Let’s say yes… Easy to reproduce for a novice like me? Nope… but such is life! One step at a time!
Our app has a fatal flaw in security, that is it lets the user navigate away to any link without checking if they should be allowed or not.
To solve this we need to refactor our code, that is rewriting it so that it is clearer and safer.
As a first step we add an array of strings to the top of our class to contain the allowed domains for our browser.
We then change our
url constant in
viewDidLoad to read
URL(string: "https://" + websites)! so that it reads from the first element of the array instead of hard-coding it.
The next step is to modify the
openTapped method with the addition of a loop so that our action sheet is automatically populated with how many websites we want to allow.
Finally, the hard bit: we need to decide if the navigation is allowed or not. This is done via a
webView(_: decidePolicyFor: decisionHandler:) method, which contains a new beast, an
@escaping closure (that means it can escape our code, that is it can be called now or later on). In summary, this function is to check if the website or the link clicked upon has or doesn’t have a host, a verified domain. And here is the code:
As always, here is the code for this project on GitHub and I would appreciate your opinion on my writing here.
Also, don’t forget to connect with me on Twitter and to say hello and thank you to Paul there as well!
If you like what I’m doing here please consider liking this article and sharing it with some of your peers. If you are feeling like being really awesome, please consider making a small donation to support my studies and my writing (please appreciate that I am not using advertisement on my articles).
If you are interested in my music engraving and my publications don’t forget visit my Facebook page and the pages where I publish my scores (Gumroad, SheetMusicPlus, ScoreExchange and on Apple Books).
You can also support me by buying Paul Hudson’s books from this Affiliate Link.
Anyways, thank you so much for reading!
Till the next one!