Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: tech-talks-2009-9
$eventId
ID of event: tech-talks
$eventContentId
ID of session without event part: 2009-9
$eventShortId
Shortened ID of event: tech-talks
$year
Year of session: 2009
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Tech Talk World Tour] In...

iPhone Tech Talk World Tour #9

Integrating Web Content into iPhone Apps

2009 • 53:41

The iPhone SDK makes the WebKit engine that powers Safari available to every iPhone application. See how to use UIWebView to display web content in your iPhone application, and learn how to communicate between JavaScript and Objective-C code. Learn to optimize web content for native iPhone applications and see how to leverage the latest web standards such as CSS 3 and HTML 5 to add hardware-accelerated graphics and local data storage to your application.

Speaker: Vicki Murley

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Hi, I'm Vicki Murley, the Safari Technologies Evangelist. In this video, you'll learn how to integrate web content into your native iPhone application using UIWebView. And I'll show you how to optimize that web content to fine-tune your web-based animations, improve responsiveness, and reduce the total memory footprint for your application. So let's get started. So we're talking today about how to integrate web content into a native iPhone application. Many people call this type of application a hybrid application, one that combines native APIs from the iPhone SDK with HTML, CSS, and JavaScript.

So there are quite a few advantages to developing a hybrid application. And the first comes if web is sort of your primary business. If you are an Amazon.com, a Fandango.com, or a Yelp.com, you can leverage the existing assets that you use to develop your website in your iPhone application. And by assets, I mean the code that you use for your website, the images, and also the skills that people have used to develop your website.

With a hybrid application, you can also update the user interface remotely. The iTunes Music Store is a great example of this. The iTunes Music Store uses WebKit, and we update the user interface here multiple times each day without having to ship a new version of iTunes. GarageBand is another example of this. We sell these lessons in line in the application, again updating the content remotely.

The final advantage of a hybrid application is being able to list your application on the App Store. You may have a great web application out there, but currently the App Store is native iPhone SDK applications only. So if you want to list your application on the App Store, you have to move to a native app.

So the primary class that hybrid applications are built around on iPhone SDK is UIWebView. Now UIWebView is just a simple class intended to display web content. I want to take this opportunity to point out that UIWebView and Safari on iPhone are not designed to be equivalent. While UIWebView is a simple class, Safari on iPhone is an application that includes a lot of extra functionality to handle multiple windows, multiple tabs, authentication, etc. So these two are not designed to be equal.

For today's discussion, we're going to split our lecture into two parts. For the first part of the talk, we're going to focus on how to use UIWebView within the iPhone SDK. Since it's a relatively small class with not a lot of methods, I'm going to cover some of the most commonly asked questions about UIWebView. For the second half of the talk, we're going to talk about the content inside the view, namely how to optimize that content for a reduced memory footprint and optimal performance. So let's get started addressing some of the most commonly asked questions about UIWebView in the iPhone SDK.

So the first most commonly asked question I hear about UIWebView is how to load resources from the application bundle. We all know that you can load a URL into UIWebView, but sometimes you want to load a file locally to avoid having to fetch resources over the network. So this is really easy to do. Basically, in the load view method, you just want to create a path based off the main bundle of NSBundle. And here I'm looking for a file named index with the extension HTML.

We're going to create an NSData object with the contents of that file path. And then finally, we're going to load that data into the WebView, and here we have a MIME type of text HTML set. The encoding is UTF-8, and we've set a base URL that is equal to our initial path. This base URL is very important to ensure that any locally stored images or other resources also load along with your local index.html file.

So we just talked about how to load a local index.html file from our application bundle into UIWebView. But you can actually load a mixture of local and remote resources. So for example, you could use local or remote images in local HTML, CSS, and JavaScript. Just use either a relative URL to reference local images or a absolute URL to reference remote images.

However, you can only use remote images from remote HTML, CSS, and JavaScript. In other words, remote resources cannot load files from the application bundle. So here's an example. I've loaded my index.html file, and that file links to this external style sheet, main.css. And in main.css, I have a style declaration for a title box. In this declaration, I'm referencing an image here, background.jpg.

Now since main.css is a remote file, background.jpg has to be stored on the remote server. What if I want to load background.jpg from the application bundle? Well, this is possible if I move the background image style into an inline style in my index.html file. I can leave the height, width, and border properties in the remote file, but by moving the background image property to a local inline style within my HTML, this background.jpg will now load from the application bundle.

The second set of questions that I commonly hear about UIWebView center around memory use. The first is, how can I decrease overall memory usage in my hybrid application that uses UIWebView? The first thing that you can do is a design decision made up front, and that's minimizing the total number of UIWebViews. Instead of having multiple UIWebViews on a screen, you can have a single UIWebView and then use XMLHttpRequest to update parts of that page.

Another technique is to build views off-screen and then animate them in. We see this everywhere on iPhone and many popular applications where a panel slides in to replace the current panel. You can use the same technique in your web code to minimize the total number of UIWebViews. Dashcode has some really great built-in templates if you're looking to explore this technique.

The next memory-centric question that I typically hear is what can I do when I get a low memory notification? So as you may have noticed, UI WebView does not have any methods that enable sort of fine-grained cache control. But there is one thing that you can do in your web code when you get a low memory notification, and that is set your JavaScript objects to null. Of course, structure your code so that these can be reinitialized, and what's going to happen when you do this is the garbage collector will come along, clean up all of these nulled objects, and free up some memory for your application.

question that I commonly hear about UI WebView is what to do about authentication. So there's two ways to handle authentication scenarios. The first is to embed the authorization information in the URL that you fetch and load into the UI WebView. And here we're loading a URL. It has an HTTPS prefix. We're setting a username and a password separated by a colon, and we're loading the web page myprotectedsite.com. So this will just load the web page into the UIWebView without prompting the user for any credentials.

If you do want to present a UI for authentication, what you're going to do is open a separate URL connection using the NSURL APIs. This is separate from the load that you would do into the UIWebView. When your delegate is notified "Connection did receive authentication challenge," you're going to store the credentials using NSURLCredential Persistence for Session. And this is going to store your credentials for the lifetime of your application.

So the next set of questions focuses on cross-code communication, namely how to execute JavaScript from Objective-C and how to execute Objective-C from JavaScript. So let's take a look at the first direction, executing JavaScript from Objective-C. This is really simple to do. It's just a method on UIWebView, string by evaluating JavaScript from string. And here I'm passing in a function name, myJSFunction.

This is actually a great best practice to pass in a function name instead of a very long, hard-to-maintain string of JavaScript. Also, you should always put your JavaScript in a separate file. Now when you're doing that, make sure that the JavaScript files in your application are copied, not compiled. This is just a matter of taking a look at your application target and dragging the appropriate resources from compile sources up to copy bundle resources.

Lastly, don't try to execute JavaScript before the view has loaded. Your delegate will receive a callback once the view has loaded and it's safe to execute JavaScript, "WebView did finish load." The next scenario involves executing Objective-C from JavaScript, essentially hooking into native functionality from a web user interface. Now there's a couple parts of this scenario. You basically want to use JavaScript to change the current location to a custom URL, use a delegate method to intercept the page request and execute native code, and then finally return no to abandon the page request.

So let's take a look at this in more detail. The first step is to define a sort of custom URL, and here the URL is http://vicki.com/capturephoto. The next step is to use JavaScript to initiate a page load. Here in our Capture Photo function, we're setting window.location to our custom URL, vickizap/capturephoto.

The final piece comes with the UIWebView delegate should start load with request. In this method, we're going to look at the request that has been passed in, and if host is equal to our string "vickeysApp", we're going to look at the last path component for that request, and if it's equal to capturePhoto, I'm going to execute native code to initiate that sequence capturing a photo. And then finally, we're going to return no from this method because we don't want to actually load anything from this method.

So that covers the first half of our talk: Integrating Web Content into Your Hybrid Application Using UIWebView in the iPhone SDK. Now let's move on to the second part of our talk, optimizing the web content inside of that view. So in this section, we're primarily going to focus on how to decrease memory footprint and increase performance of the web content inside of UIWebView.

To do that, we're going to focus on three areas: reducing the total number of images, using CSS transforms, transitions, and animations, and finally, we're going to talk about caching data locally to improve responsiveness in your application. So let's get started talking about how to decrease the memory footprint in your application by reducing the total number of images.

So you might be thinking, what's so bad about images in an iPhone application that uses UIWebView? Well, if we look at this image here, we can see that its size on disk is 53K. But that's actually the encoded size on disk. Once this image is decoded and loaded into memory, it becomes much bigger.

If we take the height, which is 320, by the width, which is 480, multiply it by 4 because this image has RGB components, this image is now taking up over 600K in memory. So this is pretty significant. Anything that we can do to reduce the total number of images in our hybrid application is going to reduce the overall memory footprint.

So one way to cut back on images in your web interfaces is to use what's called a generated image. A generated image is one where you specify the appearance in CSS, and then WebKit, the framework that does all the layout and rendering for Safari on iPhone and for UIWebView, generates an image for you. The result is seamlessly displayed in the web page, and by that I mean no additional elements are added to the DOM, and the computed style is what you would expect.

So the first type of generated image that I'd like to describe is a CSS gradient. So we see gradients in multiple places both on web pages and in user interfaces in native applications on iPhone. So here on the left we have the main web page for the WebKit open source project, and there's a gradient background on this page. And on the right we have the stopwatch application. And you can see gradients on each of the buttons, on each of the rows, and on the main background area that shows the time.

So to achieve a gradient in a web interface, what people typically do is use the background property, specify a background image, and then repeat it in the X direction to achieve a tiling effect across the background. If we use a CSS gradient instead, the syntax looks like this. We set the background to a WebKit gradient. The first parameter is the type of gradient that this is. We can have either a linear or a radial gradient.

The next two parameters specify where the gradient begins and where it ends. So this gradient begins in the upper left-hand corner and goes down about 45% down the page, almost halfway down the page. And the last two parameters tell us what color values we interpolate between for the gradient. So here we're starting with a kind of green color and we're fading our gradient out to white. So here we've eliminated an image in our web interface that we're loading into UIWebView.

Here's one more example of a radial gradient. We see radial gradients in lots of places in native iPhone applications. So here on the startup screen for E-Trade Mobile Pro, we have this sort of spotlight effect. And also for the Things application, when items move to the logbook, we see a similar spotlight effect behind the prompt that comes up. So now you can achieve the same sort of effects in your web-based interfaces.

So you might be thinking, well, just one small background image on a gradient, you know, how much can that really reduce my overall memory footprint? Well, CSS gradients can actually be used in a number of places. They can be used for background images, border images, list style images, for the content property, and as you're going to see over the next few slides, CSS gradients can be used in conjunction with many other types of CSS effects.

So one more note about gradients. Sometimes it can be difficult to imagine exactly what a gradient is going to look like just by writing the code, and sometimes the syntax can be difficult to remember. There's a great GUI tool online at wessiv.com that you can use to configure your gradients and generate the code for you.

The next type of generated image that I want to describe is a CSS mask. Now, a mask allows you to overlay the content with a pattern, and then basically that content is only going to show through the opaque parts of that pattern. So here I have this flower image, and I could overlay it with a pattern of an opaque circle. And once that content is masked, it's going to look like this. The flower image is only going to show through the opaque parts of the circle.

CSS masks have quite an involved syntax, but the basic idea is that CSS mask properties are analogous to CSS background properties. So where you have a background origin, you could also have a WebKit mask origin. Where you have a background image, you could also have a WebKit mask image.

So let's take a look at some specific syntax for our earlier example. To add a mask to this image programmatically, we would just specify WebKitMaskBoxImage. We have a URL that points to our circleMask.png, and then we have an X and Y coordinate that tells us how to position that circle. And that's going to give us an effect such as this.

Now this section is all about reducing images in your web content within UIWebView for your iPhone application, but here we're still using an image, circleMask.png. Well we can eliminate that image in one of two ways. We can either use a WebKit gradient as our mask image, or we can use an SVG image.

The last type of generated image is a CSS reflection. And of course, a reflection is just a replica of the original object with its own specific transform and mask. A CSS reflection is specified through the WebKit box reflect property. The first parameter is the direction of the reflection, the second parameter is an offset, and the third parameter is optional. It's the mask box image. So if we wanted to reflect this image of the bumblebee below the image and offset by 5 pixels, we would just specify WebKit box reflect below 5 pixels.

Now what we have here is a full reflection of the original image. And when people typically add reflection to an object, they want it to kind of fade out to the background color, or fade out in transparency. So to do that, we're going to use that last optional parameter, WebKit Mask Box Image. And for that parameter, we're going to specify a gradient.

So here we have WebKit Box Reflect below 5 pixels. And then our final parameter is a gradient, a linear gradient, that goes from the left top to the left bottom. And we fade from transparent to white. So since this gradient is reflected, it's going to be flipped and then applied to the reflection to give you exactly the effect that you're looking for.

So let's take a look at the real-world impact of using generated images instead of static images in our application. So let's say I have a slideshow application, and in one mode I show this sort of grid of images, but in the slideshow mode I want to show an image with a reflection. One option is to create each image with a reflection in an image editor, and another is to use CSS Reflections.

Now if I have a grid of let's say 12 images, I did this test myself in a real world scenario, and if I generated an additional image in an image editor that showed a reflection for a slideshow mode, each additional image generated about 300K of additional memory. So if I eliminate those extra images and use CSS Reflections instead, that will save over 3.5 megabytes in my application memory footprint.

So another place where people typically use an image when they don't have to is for drawing buttons. Let's take a look at what it takes to build a really great button in HTML and CSS. There are two classes of CSS properties that we're going to look at for building this button. The first has to do with appearance, and the second deals with behavior.

So I decided that the button that I wanted to create today was this Delete Note button inside the Notes application. And this is just a screenshot of that application with the Delete Note button showing. I started out by mocking this up inside of Safari on iPhone. And I started with all of the CSS properties that you would typically associate with a button.

We have the color and the background color, which is red, a border and a border color. We have the button sizing. We've centered the text both horizontally and vertically. And also we've set some text attributes here. The font size, the font family on iPhone is Helvetica Noi, and the font weight is bold.

So how do we take this button from a plain looking button to a button that looks really great and native on iPhone? The first thing that we're going to do is round the corners on this button. And we do that using a CSS property, WebKitBorderRadius. Here we're specifying a border radius of 10 pixels to round the corners on our button.

The next two properties have to do with shadow. These are a little bit subtle, but if you look closely, you can see a slight shadow behind the text on the button, and then also you see a gray shadow beneath the button. So the first shadow, the one beneath the button, is specified with WebKit box shadow.

The first two parameters are an X and Y offset. We want this shadow offset zero pixels in the X direction and two pixels in the Y direction. And we want the color of this shadow to be a solid gray. So that gives us that kind of gray line beneath the button.

To add the shading behind the text, we use the text shadow property. Again, the first two parameters are an X and Y offset, and I've set both of those to zero here because I want just a general shadow behind all of the text. I'm setting a blur radius of 8 pixels, and I'm setting the color of this text shadow to black.

The last step is to add a gradient to this button. So here we're specifying a white gradient that changes transparency as it interpolates from the top of the button down to the bottom of the button. So this is a linear gradient that travels the height of the button, and it goes from 50% transparency to 30% transparency, and then from full transparency to 20% transparency. So this gives us a white overlay on the button that allows the red color beneath to show through.

And this is the final result. Again, mocked up in Safari on iPhone. So this is a really great looking button, but we also want it to behave like a button on iPhone. To do that, we're going to set a few additional properties. If you touch this button, the first thing that you're going to see is this sort of background color on the text. And we want to get rid of that. And we can do that by setting WebKit tap highlight color to transparent.

That will make that gray background color around the text disappear. The next thing that you'll see if you continue touching and holding on this button is the open copy panel. And we want to disable this as well. So we're going to set WebKit touch call out to none.

Once you disable the touch callout, the last thing that you're going to see is the copy/paste bubble. And we want to disable that for our button as well, because we don't want people to be able to copy the text off of this button. To do that, we're going to set WebKit user select to none to disable the cut/copy/paste dialog.

The last thing that we want to do to this button is give it an enabled and disabled state. Typically, when you touch a button on iPhone, they change color. So here, we're going to listen for two events, onTouchStart and onTouchEnd, and we're going to call two functions, enable or disable, for the button.

The enable and disable functions are really simple. We're just going to change the background color of the button when those functions are called. So here I'm setting the background color to blue so that you can see the difference very clearly. So when I touch this button, it's going to look like this. And when I lift my finger off this button, the color will return to red.

So what's the real-world impact of getting rid of images for your buttons and replacing them with CSS-based buttons? Well, I did some measurements, and if I had 10 buttons in my application, and I had two versions of each of those buttons, an enabled version and a disabled version, that added up to about 100K per button. Replacing these images with buttons that are made of HTML and CSS saves me almost 2 megabytes in the overall memory footprint for my application.

We went over the HTML and CSS that you would use to generate a delete note button in the Notes application, but Dashcode also has some built-in templates that show some great examples of how to make additional HTML and CSS buttons. So you could just load one of these up in Safari on the desktop and inspect the element to see what CSS is used for a particular button in one of these built-in templates.

So far we've talked primarily about reducing the number of images in your web content to decrease the overall memory footprint for your application. But I want to point out that reducing the number of images in your app will also improve responsiveness. So when images are fetched over the network, there's very high latency involved when your device is fetching data over the cellular network. Latency on a cellular network is much higher than Wi-Fi. It's about 500 milliseconds as opposed to 100 milliseconds. So as you fetch more and more additional resources, these little snippets of latency can really add up and add to the overall page load time.

We did a real-world example where we loaded two websites in Safari on iPhone. We looked at Apple.com versus Microsoft.com. Now, Apple.com had an overall larger sort of memory footprint, 610K versus 494K for Microsoft.com. However, Apple.com had a smaller number of resources, 31 versus 55 for Microsoft.com. So this meant that Apple.com had fewer, larger resources.

When we loaded these two pages over Edge on iPhone and over 3G on iPhone, we found that Apple.com, with a smaller number of resources but higher overall memory footprint, actually loaded two to three times faster than Microsoft.com. So as you can see, reducing the number of images in your application not only will have a positive impact on memory footprint, but also on page load time.

Now let's talk about using CSS transforms, transitions, and animations for decreasing the memory footprint in your application and increasing performance. So if you're a website developer, your website has to work and be compatible with a number of different web browsers. Your website has to work with Safari, Safari on iPhone, Firefox, and maybe even Internet Explorer 6.

So the way that many web developers deal with compatibility issues is to use a JavaScript framework. Frameworks often kind of abstract away browser incompatibilities and allow you to focus on development. However, if you're developing content for UIWebView, the only browser that you really need to be compatible with is Safari, and the only layout engine that you need to be compatible with is WebKit.

Again, the iTunes Music Store is a great example of a native application that uses WebKit to layout most of its content. Here in this main view, we're using many advanced techniques to optimize this content for WebKit. So if you're developing content for UIWebView, you can do the same thing. Since you don't have to be compatible with other browser engines, you can use whatever tools are at your disposal to deliver the best experience possible to your users.

So one way that you can do this is to use CSS transitions and animations. So let's benchmark the performance of a JavaScript library versus a CSS transition. So the animation that we're going to look at is basically clicking on this paragraph and watching the text just fade away. So something like this.

Now the JavaScript library that we used to achieve this animation was jQuery. And there's nothing at all inherently wrong with jQuery. In fact, it's a very useful tool for many web developers. The high memory overhead comes in loading and parsing this file, which is 120K. Reading and parsing and building the function map for this file all takes memory. If we use a CSS transition instead, we're basically adding one line of CSS and one line of JavaScript. And this is going to save us over 3 megabytes. So let's take a look at what it takes to build some of these animations with CSS transitions and animations.

So one of the building blocks for CSS transitions and animations is CSS transforms. And CSS transforms allow us to translate, rotate, scale, or skew any HTML element. So if I wanted to take this photo and flip it, I would apply the CSS property WebKitTransform with the value rotate of 180 degrees.

I could also scale this photograph up by 25% and move it 100 pixels in the X direction by adding two additional values to WebKit Transform: scale by 1.25 and translate X by 100 pixels. So this is a basic example of 2D transforms, but there's also 3D transforms available. We use the same property, WebKit Transform, but there are additional values: Translate 3D, Rotate X, Rotate Y, and Rotate 3D, Scale 3D, or Matrix 3D, which allows you to define your own 3D matrix for transformation.

We're not going to go too in-depth on CSS 3D transforms, but you can find some great examples at the Safari Dev Center. The first is called Poster Circle, and it's sort of three rings of rotating posters stacked one on top of another. And the second is called Fingertips, which provides a sort of wheel navigation for looking at different videos. As I said, both of these are available as sample code at the Safari Dev Center, which is developer.apple.com/safari. The first example is called Poster Circle, and the second one is called Fingertips.

So let's move on to CSS transitions. CSS transitions are sort of an automatic animation, meaning that you specify the initial and final value of the animation, and WebKit takes care of rendering all of the frames between that initial and final value. The animation executes when the values change, and the way that you change those values is through JavaScript. So let's take a look at an example.

So here we have our mini image again, and we have some CSS properties defined for this image. We're starting with a border of 6 pixels, solid white. And for the WebKit transform property, we're specifying an initial state where the scale is 1.0 and the rotation is 0 degrees.

So if we want to scale this image up by 25% and rotate it by 180 degrees showing an animation, our final state is going to be WebKit transform scale 1.25 and rotate 180 degrees. So here we're going from an initial state to a final state. Also in the mini class declaration, you'll notice that we have WebKitTransitionProperty equal to WebKitTransform. This tells WebKit that WebKitTransform is the property that you want to animate. We also have WebKit transition duration to tell WebKit that we want the animation to take place over a period of two seconds.

So to trigger this animation from the beginning state to the final state, we're going to use JavaScript. And basically, all we're going to do is get the element, look at the class name, and if it's equal to "mini", we're going to change it to "mini move". If it's equal to "mini move", we're going to change it back to "mini". Doing so is going to trigger an animation that looks something like this.

So here we're just kind of flipping the image and scaling it up by 25%, but we can make this a little more complicated. Here in our mini class declaration, again we have the border, and here we've added opacity of 0.0. So this image is going to start out invisible.

Our initial value for WebKit transform is scaled down by 50% and again rotated by 0 degrees. And here for WebKit transition property, we're telling WebKit that we want to animate two properties. We want to animate opacity and also the WebKit transform property. For the duration, we want the opacity animation to happen over 1.3 seconds, and we want the animation of the WebKit transform property to happen over 1.5 seconds.

In our Move class, we're setting the opacity to 1.0, and our WebKit transform value scales the image up by 25% and rotates it by 360 degrees. Again, we're going to interpolate between these two states and trigger the animation through JavaScript. And this animation is going to look something like this.

So I mentioned that you specify an initial state and a final state, and WebKit takes care of rendering all of the frames in between. But you do have some control over the acceleration curve for your animation via the CSS property WebKitTransitionTimingFunction. So there are several values that you can supply to this property. They're basically ease, linear, ease in, ease out, ease in out, or you can supply your own cubic Bezier curve.

Finally, if you want to delay the start of a CSS transition, you can use the WebKitTransitionDelay property. If you specify one second, for example, for this property, you'll have a delay of one second after you change the values using JavaScript. So just to circle back to our original example where we looked at the real-world impact of using a CSS transition versus a JavaScript library, here was the code that we used in JavaScript to trigger this animation.

And here is the code for the CSS transition. We're basically setting the WebKit transition property we're using shorthand here. We're saying that opacity is the property that we want to animate over 600 milliseconds with a linear acceleration curve. Then our JavaScript just sets the opacity of the paragraph to zero, triggering the animation.

CSS keyframe animations give you all of the advantages of CSS transitions and they give you fine-grained control over the keyframes, control over the repeat count and behavior, and also there are DOM events associated with CSS animations. So let's dive right into an example. If we pretend that the entire screen here is a web page, and we have a leaf kind of falling down the right-hand side of this web page, how would we define this using a CSS animation? Well, the first thing that we would do is define the animation using the @WebKitKeyframes rule.

Here we've named our animation "fall," and we're saying that the animation starts 50 pixels off-screen in the Y direction. and goes all the way down to 600 pixels down the screen in the Y direction. So we're starting off screen and moving the leaf down the right-hand side of the page.

To apply this animation, we just set fall as the value for the CSS property WebKitAnimationName on our leaf class here. We're going to specify an animation duration of 10 seconds. We want this animation to iterate forever, so we're going to set WebKitAnimationIterationCount to infinite. And finally, we want this animation to follow a linear timing function. So we're going to set WebKitAnimationTimingFunction to linear. And here we have the leaf kind of falling down the right side of the screen and disappearing at the end of its path.

So what if we want to add an animation here so that instead of disappearing, the leaf kind of fades out as it nears the end of its path? Well, we can do this by defining an additional animation, again using the @WebKitKeyframes rule. This animation is named Fade, and we're saying that we want the opacity to be 1 for the first 75% of the animation. And then for the last 25% of the animation, we want the opacity to fade from 1 to 0, so we want the leaf to disappear.

Again on our Leaf class, we're going to specify two animations here for WebKit animation name, Fall and Fade. We want them both to take 10 seconds and iterate forever. And we want the Fall animation to follow a linear timing function where we want the Fade animation to kind of ease in. So as you can see, the leaf kind of falls down the right side of the page, and for the last 25% of its path, the opacity fades from 1 to 0, and the leaf disappears.

I mentioned that there were DOM events associated with CSS animations, and these are WebKitAnimationStart, WebKitAnimationIteration, and WebKitAnimationEnd. And these allow you to know when an animation starts, iterates, or ended. You can listen for these events just like you would any other DOM event. Here we're listening for an animation end event directly on the element. And when that animation ends, we're going to set the display to none.

There's one more important thing to note about CSS transitions and animations, and that is that they are hardware-accelerated. Since they're hardware-accelerated, you will never, ever, ever achieve the same performance with a JavaScript animation that you could achieve with a CSS transition or animation. I actually have a demo to show you the difference in the performance of JavaScript animation versus a CSS animation. Let's take a look at the differences between these two approaches. Let's take a look at a leaf animation in a web page. In the first case, we'll be using JavaScript to animate the leaves, and in the second case, we'll be using CSS animations.

So here's the first case, animating with JavaScript. This is the best performance that we could get animating with JavaScript, but if you look closely, you can see that the leaves are kind of falling down the page with a little bit of a jagged motion. Also, the leaf animation that we see here is really simple. The leaves are just appearing at the top of the page and falling straight down, disappearing off the bottom edge of the screen. Now let's take a look at the CSS animation example.

Here we see we have a number of leaves on screen at once and the animation is totally smooth. Also, the animation on each leaf is much more complicated than the animation we were able to achieve with JavaScript. Each leaf as it falls kind of arcs back and forth, and as each leaf approaches the bottom of the screen, the opacity fades out and each leaf disappears. So as you can see, the performance and functionality that we were able to achieve using CSS animations was far superior to what we were able to do animating these leaves conventionally with JavaScript.

So let's take a look at one final piece of functionality, how to improve responsiveness in your application by caching data locally. So often I've used web applications, for instance, a to-do list application. And when I commit that to-do item, it takes several seconds for the data to be stored up in the cloud, and then for the packet to make the round trip and for the user interface to be updated. That user interface could be much more responsive if we eliminated the network and stored that data locally.

So you can enable this functionality using the HTML 5 database storage feature. Now this is a standards-based approach to local database storage, meaning that it's part of HTML 5 and will probably be adopted by other browsers in the future. It's based off of real-world SQL, so all of the SQL conventions that you're used to are here and part of this API.

This API is asynchronous and callback-based, meaning that your UI will never be locked up, waiting for a transition to complete. And finally, HTML 5 database storage operates on origin-based security, meaning that other websites cannot access your website's data, and your website cannot access the data of a different website.

Other advantages are reduced complexity. You can store your data directly in the database instead of having to sync it to the cloud. We've already talked about improved performance, but reducing the number of network operations on iPhone improves overall battery life, and of course, improves responsiveness. And finally, if you're storing the data locally, you can have access to that data even if there's no network connection available. We're going to discuss three aspects of the HTML5 SQL API for client-side databases. First, we're going to talk about what it takes to create a database. After that, we'll talk about executing transactions and finally, handling callbacks.

So creating or opening a database is actually very simple. The first thing that you're going to do is test to see if the current browser supports database functionality. And we do this by checking window.opendatabase. If this functionality exists, we're going to go ahead and set up a few variables. So here we've passed a name, a version, a display name, and an expected size to the Open Database method. But really the only parameter that is strictly required is the name. You can just set the other parameters to null.

So once you have opened a database, the next thing that you're going to want to do is execute transactions on this database. For those of you familiar with database programming, this is probably very familiar to you. But for those of you who aren't, a transaction is basically an atomic unit of work that cannot partially succeed.

Basically, any changes made during a transaction are rolled back if any part of that transaction fails. When you start to think about deeply rooted relational databases, this model makes a lot of sense. You wouldn't want half of your data to be modified. All queries that are part of the HTML5 SQL API must be part of a transaction. So here's what a transaction looks like. I basically create a string of SQL and then pass that string of SQL to the execute SQL method on the transaction.

There are two types of callbacks that are part of this API: transaction callbacks and query callbacks. Transaction callbacks are related to the entire transaction. There are two types of transaction callbacks: completion callbacks and error callbacks. Completion callbacks allow you to detect when a transaction has completed, and the error callbacks allow you to handle error messages and codes that you might want to display to the user.

The second type of callback is a query callback. A query callback is related to the individual queries within the transaction. There are two types of query callbacks: data callbacks, which allow you to manipulate the data that was returned from a query, and error callbacks, which allow for optional queries within a transaction. Basically, if a query within a transaction fails, you can choose to proceed with the transaction anyway. If no error callback is specified for each query, all errors are assumed fatal and the entire transaction is rolled back to the beginning.

So there's a great example available online at webkit.org that you can take a look at to get started with the HTML5 SQL API. This is a basic sticky notes application. When you click the New Note button, a new sticky note appears, and then you can edit the contents of that note or move it around on screen. The contents and the position of the note are stored in a local database. Here we've opened up the Web Inspector in Safari on the Desktop to examine the contents of this database. Here we see the content of each note, a timestamp, and its position on screen.

The integrated tools in Safari on the Desktop provide a great environment for building and debugging your application. So if I select the database name in the left-hand panel, this prompt appears. From here, I can execute arbitrary SQL statements on the selected database to build or even debug my application. This view also includes tab completion, which is useful in any debugging or development scenario.

So that covers the second half of our presentation: Optimizing the Web Content Inside of UIWebView for a Reduced Memory Footprint and Improved Performance. To recap what we've covered today, we started out by talking about some of the advantages of hybrid applications. After that, we addressed some of the commonly asked questions around UIWebView.

And finally, we went in-depth on optimizing the content inside of UIWebView, using CSS to decrease the overall image count in our web interfaces, replacing JavaScript animations with CSS transforms, transitions, and animations, and using local data storage to improve responsiveness in the UI of your web interface. You can find documentation and sample code for Safari at the Safari Dev Center at developer.apple.com/safari.

And of course, documentation for the iPhone SDK, including UIWebView, is available at the iPhone Dev Center, developer.apple.com/iphone. If you have any additional questions, feel free to email me directly at [email protected]. Thanks for watching today, and I can't wait to see how you integrate web content into your iPhone application.