Hacking with Swift – Learning Project 4

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.

Before the 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 navigationDelegate to 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!).

Then, inside 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 towebView.load(URLRequest(url: )) and then we allow the swiping back and forward of the pages in the browser with the call to the allowsBackForwardNavigationGestures property.

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.

Inside 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:Screen Shot 2019-02-25 at 18.58.00

Each 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 webView.

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.

Key-value-observers

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 webView‘s estimatedProgress.

Clear? Let’s say yes… Easy to reproduce for a novice like me? Nope… but such is life! One step at a time!


Refactoring

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.

Screen Shot 2019-02-25 at 23.46.55

We then change our url constant in viewDidLoad to read URL(string: "https://" + websites[0])! 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:

Screen Shot 2019-02-25 at 23.52.23

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!

Published by Michele Galvagno

Professional Musical Scores Designer and Engraver Graduated Classical Musician (cello) and Teacher Tech Enthusiast and Apprentice iOS / macOS Developer Grafico di Partiture Musicali Professionista Musicista classico diplomato (violoncello) ed insegnante Appassionato di tecnologia ed apprendista Sviluppatore iOS / macOS

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: