[Updated to Swift2.0/iOS9 — 10/17/15 SJL]
There are times we need formatted content. There are also times we need to access content on the web. The UIWebView
is a very useful view for both. In this week’s lesson we’ll explore how to use this view in a variety of applications.
One warning: Since this is about web browsers. I will be using HTML/CSS. Since this lesson is about Swift and Xcode and not a web design I’ll present this code as-is. If you do not know any HTML there are more than a few courses available to you to get you up to speed.
Set Up the Scene
Open a new single view project called SwiftWebView. Make this project Universal instead of our usual iPhone. This project will work on both iPads and iPhones. Go to the storyboard. Drag a Web View and a Tool Bar onto the storyboard. This application will use auto layout. Start by aligning the toolbar with the blue lines on the storyboard at the top, then align the web view underneath it to take up the rest of the space on the view. Add four bar buttons the the toolbar and label them as below. Use a few bar spacers to space them out. When done it should look something like this:
Now click the toolbar and the pin button on the storyboard. Click on the top left and right i-beams and then set the pop up to this, ignoring the bottom constraint:
Do the same for the web view and set it to this:
Once done, you may get warnings from Xcode that the frames will not be the same a run time. If so, first click one of the objects on the story board, then click the and select Update Frames to refresh the frame. Doe the same for the other object if there are still warnings.
Wire Up the Project
Open the assistant editor, and control drag the web view into the ViewController
class. Name the outlet myWebview.
Add four actions, one for each of the bar buttons as helloPizza, makeAppPie, back and forward . When done, your code should look like this:
class ViewController: UIViewController { @IBOutlet weak var myWebView: UIWebView! //Navigation in a web view @IBAction func back(sender: AnyObject) { } @IBAction func forward(sender: AnyObject) { } // Go to a internal or external html page @IBAction func makeAppPie(sender: AnyObject) { } @IBAction func helloPizza(sender: UIBarButtonItem) { } override func viewDidLoad() { } }
A Web View From a String
There are several ways to use a web view. Before attributed strings, this was the only way to get formatted text. The developer would write a string of text in HTML and send it to a UIWebview
using the method loadHTMLString
. Change the viewDidLoad
method to this:
overridefuncviewDidLoad() { super.viewDidLoad() letmyHTMLString:String! = " <h1>Hello Pizza!</h1> " myWebView.loadHTMLString(myHTMLString, baseURL: nil) }
Line 3 makes a optional string, since the loadHTMString
method requires one. Line 4 loads the string, and has a second parameter baseURL
, which sets the base URL path for the HTML. Usually we set this to nil
but if you had files you wanted to load like images or a style sheet, this would give the default path for the files.
Build and run:
That was pretty boring, so let’s add some more HTML code, replace the string with this, all without a line break.
letmyHTMLString:String! = " <h1 style=\"font-family: Helvetica\">Hello Pizza</h1> Tap the buttons above to see <strong>some cool stuff</strong> with <code>UIWebView</code> <img src=\"https://apppie.files.wordpress.com/2014/09/photo-sep-14-7-40-59-pm_small1.jpg\">"
You’ll notice a few places where we used the Quote escape sequence \"
. We need to add quotes in a few places and a backslash followed by a quote allows us to do so within a string. Build and Run. That is a little better:
A Web View and CSS From Files
Trying to make something formatted from a string is not easy. Our work would be easier if we had the HTML in a separate file. Even better would be an external style sheet. Tap Command-N on the keyboard or File>New>File… from the drop-down menu to make a new file. Make a blank file by going to Other under iOS and Empty.
Click next and then name the file myHTML.html. Save the file. In the blank file add the following code:
<!DOCTYPE html> <html> <head> <title>Hello Pizza! Home</title> <link rel="stylesheet" href="myCSS.css" type="text/css"> </head> <body> <!-- Site navigation menu --> <div class="navbar"> <a href="index.html">Home</a> <a href="musings.html">Toppings</a> <a href="town.html">Crust</a> <a href="links.html">Ovens</a> </div> <div class="content"> <!-- Main content --> <h1>Hello Pizza!</h1> This is a site for the love of all things pizza! But we are not just pizza, we are with anything on a flatbread. So look around and you will find naan, flatbreads, pitas and tortilla related stuff too!!! If that is not enough, check our sister site <a href="pie">Hello Pie</a> <img src="https://apppie.files.wordpress.com/2014/09/photo-sep-14-7-40-59-pm_small1.jpg" alt="" /> <!-- Sign and date the page, it's only polite! --> </div> <address>Made 16 October 2015 by makeapppie.com.</address> </body>
Back in the ViewController.swift file change the helloPizza
method to this:
@IBAction func helloPizza(sender: UIBarButtonItem) { let myURL = NSBundle.mainBundle().URLForResource("myHtml", withExtension: "html") let requestObj = NSURLRequest(URL: myURL!) myWebView.loadRequest(requestObj) }
Line 2 creates a url for myHTML.html
from what is called the main bundle. The main bundle is the directory we place all of our code files in XCode for a specific project. The main bundle changes location depending on the device. Instead of giving a literal path, we use this relative indicator. Line 3 creates an NSURLRequest
, an object we feed into the loadRequest
method in line 4. The loadRequest
loads the HTML code into the UIWebView
. Build and run this. Click the Pizza button and you get this:
This view is not that pretty, but we can add some CSS to clean it up a bit. Create another blank file as you did before, named myCSS.css and add the following to the new file:
body { color: #eeeeee; background: #a0a088; font-family:Helvetica} h1 { color: #dd1111; font-family:Chalkduster; font-size: 18pt} a{ font-family:Helvetica; font-weight: bold; color: #ffffaa; text-decoration:none; padding-left: 5px; } img{ padding-left:0; max-width: 90%; max-height: 90%; box-shadow: 3px 3px 3px 0px #202020 } .navbar { background-color: #000000; color: white; position: absolute; top: 0em; left: 0em; width: 100% } .content{ padding-left: 1em; padding-top: 1em; }
The HTML code in myHtml.Html
<link rel="stylesheet" href="myCss.css" type="text/css">
assumes that the baseURL
is the bundle. Build and run and we get a better formatted web view:
A Web View From a Website
Many times we will want to pull something directly from the web. Instead of getting our url from a bundle, we just type it explicitly to a web address. For example, change the makeAppPie
code to this:
@IBAction func makeAppPie(sender: AnyObject) { let url = NSURL(string: "http://makeapppie.com") let requestObj = NSURLRequest(URL: url!) myWebView.loadRequest(requestObj) }
Build and run, and tap the AppPie button. You will get an error in the error console, and no web page.
2015-10-17 12:57:28.540 SwiftWebView[22360:1181188] App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
Starting in iOS9 Apple added extra security to NSURLRequest
. In another post I’ll describe this in detail. We can shut down this security with a entry in the plist.info file. IN the Navigator, right-click on plist.info. Select Open As > Source Code.
In the XML code that appears add this just under the first tag:
<key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict>
Build and run again. Press AppPie. Now we get the web page.
It may take a while, particularly if using the simulator for the web page to display. This is one of those places where you might want to avoid any other processing while running your webview.
Web View Navigation
A problem with what we’ve got so far is navigation. I can go to links on MakeAppPie, and dive into an article, but I can t go backwards. UIWebview
has methods to handle that. Change the back and forward button actions to this:
//code to do navigation in the web view @IBAction func back(sender: AnyObject) { if myWebView.canGoBack{ myWebView.goBack() } } @IBAction func forward(sender: AnyObject) { if myWebView.canGoForward{ myWebView.goForward() } }
In each case we check the property canGoForward
or canGoBack
. If we can go forward or back, we then use the method to do so. Build and run we can now use the back and forward buttons to navigate the web browser when there is a page to go forward or backward to.
The Whole Code
// // ViewController.swift // SwiftWebView // // Created by Steven Lipton on 10/16/15. // Copyright © 2015 Steven Lipton. All rights reserved. // import UIKit class ViewController:UIViewController { @IBOutlet weak var busyindicator:UIActivityIndicatorView! @IBOutlet weak var myWebView: UIWebView! //code to do navigation in the web view @IBAction func back(sender:AnyObject) { if myWebView.canGoBack{ myWebView.goBack() } } @IBAction func forward(sender:AnyObject) { if myWebView.canGoForward{ myWebView.goForward() } } // go to a internal or external html page /* be sure to add this to the info.plist <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key><true/> </dict> */ @IBAction func makeAppPie(sender:AnyObject) { let url = NSURL(string: "https://makeapppie.com/2014/10/28/swift-swift-using-uiwebviews-in-swift/) let requestObj = NSURLRequest(URL:url!) myWebView.loadRequest(requestObj) } @IBAction func helloPizza(sender:UIBarButtonItem) { let myURL = NSBundle.mainBundle().URLForResource("myHtml",withExtension: "html") let requestObj = NSURLRequest(URL:myURL!) myWebView.loadRequest(requestObj) } override func viewDidLoad() { super.viewDidLoad() //let myHTMLString:String! = "</pre> <h1>Hello Pizza!</h1> <pre>" let myHTMLString : String! = " <h1 style=\"font-family: Helvetica\">Hello Pizza</h1> Tap the buttons above to see <strong>some cool stuff</strong> with <code>UIWebView</code> <img src=\"https://apppie.files.wordpress.com/2014/09/photo-sep-14-7-40-59-pm_small1.jpg\">" myWebView.loadHTMLString(myHTMLString, baseURL: nil) } }
myHtml.html
<!DOCTYPE html> <html> <head> <title>Hello Pizza! Home</title> <link rel="stylesheet" href="myCSS.css" type="text/css"> </head> <body> <!-- Site navigation menu --> <div class="navbar"> <a href="index.html">Home</a> <a href="musings.html">Toppings</a> <a href="town.html">Crust</a> <a href="links.html">Ovens</a> </div> <div class="content"> <!-- Main content --> <h1>Hello Pizza!</h1> This is a site for the love of all things pizza! But we are not just pizza, we are with anything on a flatbread. So look around and you will find naan, flatbreads, pitas and tortilla related stuff too!!! If that is not enough, check our sister site <a href="pie">Hello Pie</a> <img src="https://apppie.files.wordpress.com/2014/09/photo-sep-14-7-40-59-pm_small1.jpg" alt="" /> <!-- Sign and date the page, it's only polite! --> </div> <address>Made 16 October 2015 by makeapppie.com.</address> </body>
myCSS.css
body { color: #eeeeee; background: #a0a088; font-family:Helvetica} h1 { color: #dd1111; font-family:Chalkduster; font-size: 18pt} a{ font-family:Helvetica; font-weight: bold; color: #ffffaa; text-decoration:none; padding-left: 5px; } img{ padding-left:0; max-width: 90%; max-height: 90%; box-shadow: 3px 3px 3px 0px #202020 } .navbar { background-color: #000000; color: white; position: absolute; top: 0em; left: 0em; width: 100% } .content{ padding-left: 1em; padding-top: 1em; }
Leave a Reply