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-2008-7
$eventId
ID of event: tech-talks
$eventContentId
ID of session without event part: 2008-7
$eventShortId
Shortened ID of event: tech-talks
$year
Year of session: 2008
$extension
Extension of original filename: m4v
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2009] [Tech Talk World Tour] Us...

iPhone Tech Talk World Tour #7

Using Advanced Web Technologies on iPhone

2008 • 58:23

Safari on iPhone exposes a wealth of functionality to web applications that has - until now - typically only been associated with native applications. In this session you'll learn about the most advanced technologies and sophisticated techniques for taking your iPhone web application to the next level. We'll begin with the basics of making your iPhone web application feel built-in. Learn how to define and customize your web interface for iPhone, create a home screen icon, run your application in full-screen mode, and even detect orientation changes. Next we'll dive into the details of extending and enhancing your user interface by using features such as 3-D hardware accelerated CSS animations and DOM touch events. Afterwards we'll move onto the internal structure, enhancing your iPhone web application to store data locally and even fully function offline. Even with all of this advanced functionality, there may still be a native application feature that your iPhone web application just can't do without. We'll go over the basics of leveraging your existing web content in a native application on iPhone, and we'll cover techniques that will enable you to execute JavaScript from native code.

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.

Okay, so this is the session on using advanced web technologies on iPhone, and my name is Vicki Murley. I'm the Safari Technologies Evangelist at Apple. Okay, so when the SDK was released-- that was obviously a big deal to a lot of native-application developers. But at the same time, a lot of features specific to web applications were released as well. And that is great for you guys, because you're able, now, to develop some really rich and interesting iPhone web applications.

At the same time, you get to leverage your existing skillset, you don't have to go learn Objective-C or anything like that to create a great experience on iPhone. Many of the features and technologies that we're gonna talk about today are based on open web standards. So even if a feature is only implemented in Safari on iPhone right now, it's very likely that it will be implemented in other browsers in the future by virtue of being part of a standard.

And so you're going to be kind of ahead of the curve by adopting early. And also with web technologies and web applications, you have instant deployment. So if you need to make a change to your app or want to put out a new version, that can happen instantly. No third party to go through.

Okay. So let's do a quick comparison of native applications versus web applications in four main categories. So the first one to think about is kind of feeling built-in. And when I think about feeling built-in for native applications, I think about things like launching an app via a home screen icon.

Of course, native apps run in full-screen mode. They don't run within another application. You don't have to type in a URL to get to a native app. And native apps can detect orientation changes as well, so you can do different things in your UI based on that change. Well, all of those features are available in web applications as well.

If I wanted to implement something to do with multi-touch in my native application, like detect a rotation or implement a custom gesture, I would use a class in iPhone SDK called UI touch. Well, for iPhone web applications, you can do the same sort of thing through JavaScript using this technology that we call DOM touch. So that's also possible in web applications.

Advanced graphics. If I were looking to integrate some really cool graphics into my UI on iPhone, I might use something like Core Graphics or Core Animation or OpenGL ES. Well, in web applications now, we have a technology - we call this family of effects CSS visual effects, and this includes CSS transforms, transitions, and animations, and these are really hardware accelerated animations and graphics that you design through CSS.

And lastly, local storage. In native applications, you can store data in an SQLite database or write files to disk. Well, in web applications, you can't write files to disk on the fly. You can store files locally. We're gonna talk about that later on. But you can also store data on the fly in an SQLite database locally for offline access or whatever you like.

So we're gonna talk about those four key areas that we just looked at on the graph there. Feeling built in, making your web app feel integrated, feel like a built-in app on the system. Touch and gesture events, multi-touch through JavaScript, basically. CSS visual effects, which includes those hardware accelerated animations that I talked about. And also, storing data locally.

We're gonna talk about storing data on the fly in an SQLite database, and also how to create a locally cached version of your application, where you can cache all the resource files for your app. Okay, so getting started with feeling built-in. There are three things we're going to cover here: home screen icons, running your web application in full-screen mode, and how to detect orientation changes from within a web application.

So here's a picture of an iPhone. I'm sure that you're all familiar with what an iPhone looks like. And when I want to launch an application, as I mentioned earlier, I just touch one of these icons on the home screen. I don't have to launch another app and then type in a URL or retrieve a URL from my bookmarks or something like that.

I just touch an icon on the home screen. And we want you guys to have that same functionality for web applications. So we've added a way-- or a way has been-- existed for a while now, that you can have an application icon for your site-- or for your web app. Excuse me.

So the way to do this is to just create an image and give it this name-- "AppleTouchIcon.png." And you store this in the root directory of your web server, and then when a user surfs over to your site and they click on the "+" button at the bottom of the Safari screen, they'll see this panel slide up, and this button "Add to Home Screen." And if they touch this button, then the image that you've created then pops up on the home screen, and they can launch your app from this home screen icon from that point forward.

So using this named image is one way to have a home screen icon, and that's using a single image for all of the pages of your web app. If you wanted to have different icons for different pages of your web app, you could do that by adding a link tag to those pages specifically. And the relationship here is AppleTouchIcon, and I'm linking to an image here. In this case, the name of the image doesn't matter. In the first example, it had to be named AppleTouchIcon, but with the link tag you can name it whatever you like.

So there are some guidelines for creating a home screen icon that we advise people on. The first is that your image should be 57 pixels square. We add the rounded corners later on, so a hard 90-degree angle on the corners is the best way to start so that that rounding effect is what you want.

We recommend no shine or gloss on this image because we actually add a shine to the top of the image on the fly, just like we add the rounded corners. And sometimes, if you add shading to your own icon, that can kind of conflict with the shading that we add, and it looks kind of odd.

So it's often best to have just a flat image. So going from the image that I just had on screen with the hard edges and totally flat, in Safari on iPhone, that image gets transformed to what you see here. This icon that has rounded corners and a shine across the top of the icon.

So if you do want to have custom shading on your icon and you don't want to have the shading that we add, there's a way to do that, too. And instead of naming your icon "AppleTouchIcon.png," you would name it "AppleTouchIcon-Precompose.png." And that's a signal to Safari on iPhone and to the home screen to not add any shading to your icon. You'll still get the rounded corners, but no shading. So if I were to name my icon "appletouchicon-precompose.png," I would go from an effect that looks like this, what we see here, to this, just, you know, totally flat, no shading on top, but still having the rounded corners.

Okay, so now you have a home screen icon. Here it is, it's looking pretty great. And your user touches it to launch your application, and now, it's obvious to them again that they are running a web application because you can see the Safari Chrome at the top and bottom of the screen, the URL field and then the Back/Forward buttons and Bookmark buttons, et cetera, at the bottom.

So, you know, step one, we're looking good. But step two here, the user is queued that you're running in a web browser. And that kind of takes away from the built-in, native look and feel of your app. So luckily, in iPhone OS 2.1, which is the release prior to the release that just came out, there's a way to hide the Safari UI components. So we call this "full screen mode," and the Safari UI is hidden when your application is launched from its home screen icon.

So you can imagine, if you enabled this feature and a user were just surfing around in Safari on iPhone and they went to your site, and all of the UI elements disappeared, like no URL field anymore, no Back/Forward buttons, that would be pretty jarring, and users would also be wondering, "Well, how do I get to another site from here "or go backwards or go forward?" So the UI components are only hidden when your app is launched from its home screen icon. So this feature is easy to enable. It's just a meta tag.

Meta name equals "Apple mobile web app capable." Content equals "Yes." The appearance of the status bar when you're in full-screen mode is customizable. So the status bar is just that small bar at the top of every screen that you see that has battery strength, Wi-Fi signal strength, time, et cetera.

That's the status bar. So, just like in native applications, you can customize the way that status bar looks. So gray is the default, and other options are black, and black translucent. An example of black translucent is in the Photos app on iPhone. So you scroll the photos, and you can see them scrolling by underneath the status bar.

So that's an example of black translucent. One important thing to know-- if you use one of the opaque options, gray or black, your content is going to be shifted down by 30 pixels and rendered as such. But if you use black translucent, you're gonna get-- I'm sorry, it's 20 pixels, actually.

You're gonna get that extra 20 pixels of vertical screen space because your content will be displayed behind the status bar. So this customization is easy to enable. It's just another meta tag. Meta name equals Apple mobile web app status bar style, and here I've set the color to black.

The last useful piece of information about full-screen mode is that you can actually query this mode. So, we were talking in an earlier session in the Q&A about maybe you want to lay out your UI differently if the user is running in full-screen mode, or maybe you want to add a note on your-- you know, on the front page of your web app to cue users to launch from the home screen icon, et cetera. You can query this property, just with the line of JavaScript, "window.navigator.standalone," looking at the standalone property.

So this feature is really easy to adopt. And lots of people have picked it up. Here's one example of a cool full-screen web app that I used a lot a couple months ago. Now, this slide is a little out of date, I admit. But this was just an app that showed me some poll data.

And then, when I would click the "i" button in the lower right-hand corner, a panel slid in to show me where the poll data-- about where the poll data was coming from. So this is a pretty simple full-screen application, but if you have a large, you know, complicated, multiple pages, many screens kind of web app, there are a couple tips that you need to keep in mind if you're using this feature.

The first is that any external links are going to open in Safari. So basically, this means that you need to use AJAX to keep your application to a single page. Some great examples of how to do that are built into the Dashcode templates. So there's a template that has a browser view where you have sliding panels of different menus.

And there's another one that has a flip transition to settings on the back. These are great examples of how to have a web application that's one page, updated with AJAX, and a great approach to using full-screen mode. The debugger in Dashcode is a great way to kind of take a look at the code, how the template is achieving a certain effect, and replicate the same piece of functionality in your web app.

So that covers full-screen mode, all that you need to know. Now we're going to talk about detecting orientation changes from within iPhone web apps. So this is just an event on the body. So here I'm listening for the orientation change, and when I receive that event, I'm going to call this function that I've defined "update_orientation." In my updateorientation function, I'm just going to look at the orientation property on the window.

And if the case is zero, I'm in portrait mode. I haven't turned the phone at all. If the case is -90, I have turned the phone clockwise, and I'm in landscape-right mode. And if the orientation value is 90, I've turned the phone counterclockwise, and the phone is in landscape-left orientation.

So that covers, you know, three main points for kind of feeling built-in: home screen icon, full-screen mode, and detecting orientation changes. For the next three sections, we're going to, you know, get into the nuts and bolts of how to make the contents of that application really just super optimized for iPhone, how to take advantage of all of our new features. So getting started with touch and gesture events.

So when we first introduced this feature around the time that iPhone SDK came out, we got some questions from the developer community. You know, "Why can't I just use Mouse Events "to do kind of rotation, scale, et cetera? "I click on-- I touch an element, that's an on-click, right?" Well, this all really boils down to the fact that a mouse is not equivalent to this disembodied hand that you see on the right-hand side of the screen, and that, you know, a mouse, you have continuous input.

On the screen, so, you know, you move your cursor across a web page, on-mouse over events fire, CSS colon hover styles are applied as you move that cursor around the home screen. If you put your finger down on a touch screen, you know, you might receive an on-click mouse event, but then, as you move your finger around, you're really just dragging the screen or panning the screen. The paradigm is totally different on iPhone, so we needed to create something new.

Another great reason why mouse events aren't really appropriate for this sort of thing is that Safari on iPhone is really the first browser to render desktop-quality web content on a mobile device. And so we need to remain compatible with all of that existing web content out there. And mouse events need to fire as expected for those existing sites. But we want to be able to give you guys the opportunity to provide the same kind of rich experience that you see in native applications in your iPhone web applications.

All right, so enough overview. Let's talk about what happens when I put a finger down on the screen in terms of touch events. So when the first finger touches the screen, a touch start event is sent. When that finger moves, touch move events are sent. When that finger is lifted from the screen, a touch-end event is sent, and of course, if I don't move my finger in between, I just get a touch-start event followed by a touch-end event.

If a user clicks the home screen button while a sequence of touch events is happening, then a touch cancel event is sent. So you can handle that case gracefully if a user clicks the home screen button. So you can listen for these events just like you would any other mouse event, either via directly on the element - here I'm listening for touch start on this div - or you can add them to elements via add event listener.

So here, I'm listening for a touch start, and when that event fires, I'm going to call this function that I've defined "track touches." Okay, so I've received an event. Now what can I do with it? Well, the first thing you want to do is prevent the default behavior for that event.

So I mentioned earlier, you know, you put your finger down on the screen and you drag it around while you start panning the content. If you want to work with touch events directly, you want to disable that panning behavior or scrolling behavior or whatever's happening. So you want to prevent the default behavior for that event, first thing.

After that, the important thing to know is that a touch event maintains three lists of touch objects. So the first is all touches on the page, event.touches. The second is all touches for this target, event.target_touches. And the third is any new touches for this event, event.change_touches. So you have these three lists of touch objects, and within each of those lists, each object has certain properties. So the basics of properties of touch objects are the target node of this touch, which is the target, and the identifier property, which is the unique ID for the object.

Just like mouse events, there are also many different coordinates that you can look at for that touch. So we have client X and client Y. Those are coordinates that are relative to the viewport. Screen X, screen Y are relative to the screen. And page X, page Y are relative to the entire page. So the important thing to remember with these properties is that when you receive an event, remember that you are receiving a list of touch objects, so you have to index into that list before you can look at any of these properties.

So here I'm looking at the first touch in my target touches array. I'm looking at the page X value for that touch. So you may be thinking, "Well, touch events sound really cool, "but if I want to do something complicated, "like detect whether a user has zoomed in or rotated "or something like that, that's gonna be a lot to track "in those arrays, and that could get complicated." Well, luckily, there's kind of a high-level way to look at touch events, and these are gesture events. These are kind of multi-touch through JavaScript.

So if we go through this same exercise again, if I put one finger down on the screen, a touch start event is sent. But once I have two fingers down, gesture start events are sent, in addition to the touch events that we've already covered. Just because gesture events are being sent doesn't mean that touch events stop being sent. So now I have two fingers on the screen, and as I move those fingers, gesture change events are sent. And if I lift those two fingers off the screen, a gesture end event is sent.

Of course, if I don't move my two fingers in between, I just go directly from gesture start to gesture end, and if I lift fingers off the-- or I'm sorry, if the user clicks the home screen button in the middle of a gesture sequence, then a touch cancel event is sent. And just like touch elements or any mouse events, for that matter, you can listen for these events directly on the element or add them to elements via add event listener.

So just like touch events, gestures also have properties. The most basic is the target node for the gesture. But then there are some properties that are sort of what makes a gesture a gesture. And when I think about gestures, I think about things like scaling and rotation. So those are two of the kind of definitive properties on a gesture.

So the first one that we'll talk about here is scale. And scale is defined as the distance between two fingers since the start of an event as a multiplier of the initial distance. So that's kind of a mouthful, a lot to remember. A good rule of thumb to keep in mind is that if the scale value is less than one, the user has pinch closed to zoom out, and if the scale value is more than one, the user has pinched open to zoom in.

The second definitive property of gestures is rotation. Rotation is defined as the delta rotation since the start of an event in degrees. Again, a good rule of thumb to keep in mind is if the rotation value is positive, a user has rotated in the clockwise direction, and if the rotation value is negative, they have turned in the counterclockwise direction.

Okay, so that is a quick overview of touch and gesture events. How to implement custom gesture detection or touch detection in your web applications. Now let's move on to this family of technologies that we call CSS visual effects. So on iPhone OS and also on Mac OS X, for that matter, you are used to seeing these kind of innovative pieces of UI. So one example here is the Weather application. To see the settings, you get this kind of 3D flip to the other side.

In Cover Flow mode in the iPod application, you have like a 3D view of your albums here that you can look through all your album covers. And also there's another kind of animation that's directly in the UI, and they're a little more subtle, but this type of animation is really providing kind of a cue to the user as to what's going on.

So I want to move this message to another folder. It doesn't just, you know, disappear. There's this little animation, this little jump down from, you know, the source spot to the destination spot. And now I know exactly what has happened to that message, where it ended up. Another good example-- on Mac OS X is minimizing a window to the dock, you know? It doesn't just disappear and then reappear down in the dock.

There's an animation that is either the scale or the Genie effect that tells the user, "Here was the window. "Here's where it's going. "Here's where you can find it later on." So this kind of subtle animation is really, you know, one of the ways that people are able to learn to use operating systems like Mac OS X and iPhone OS so easily, because they're being cued, as to what is actually going on.

So now, there's a great way to add these kinds of animations and unique kind of positioning to your web applications. And that's this family of technologies that we call "CSS visual effects." So there's three aspects that we're going to talk about today. They are transforms, which are-- which is all about positioning content in unique ways.

Transitions, which are simple animations, sort of a-- you might think of it as a two-keyframe animation, where you specify the first frame and the last frame, and WebKit takes care of rendering all the frames in between. And then, we have keyframe animations, where you have explicit control over the keyframes within an animation, not, you know, WebKit taking care of everything in between.

Okay. Oh, so this is a technology that was pioneered by the engineers at Apple, and we have since submitted this as part of inclusion to CSS3, and we're getting some adoption, so that's great. If you want to see the specs that we have written and submitted, those are available at webkit.org/specs/cssvisualeffects.

So going back to my mail example here, if I-- you know, this is a native app, but if I wanted to do this in a web application, I might, you know, divide up this cell like so. You know, the name is one cell, and the subtitle is another cell, and that envelope is a cell, and maybe I was really lazy in my image editor, and I just made this envelope, and I had a background color on it. So then, when I go to "Animated," it looks really ugly because you can see this background on it.

Well, a great way to position elements like that is to use CSS transforms. So this is a way to translate, rotate, scale, or skew any HTML element. So if we look at this envelope example again, if I want to, you know, turn this a little bit, I can do that in just one line of CSS, and that is "-webkit transform rotate by 20 degrees." So one thing I want to mention, this "-webkit" prefix here, that's a common convention that all web browsers follow for CSS properties that are not yet part of a final specification. So in Mozilla-based browsers, you would see "-moz" at the beginning. So it doesn't mean that this is non-standard and will never be part of a standard. It just means it's kind of pre-standard at the moment.

So anyway, I've rotated my envelope by 20 degrees, and I want to mention here that you can also chain together these transforms. So I rotated by 20 degrees, now I've also scaled up by 25%, and I've translated in the Y direction by 30%. And that 30% is calculated off of the size of the element, so it's 30% of the element size. Here I've translated in the Y direction, but you can really perform any of the transform operations in a single direction. So you can scale only in the X direction or only in the Y direction, or translate only in the X direction, etc.

A piece of additional control that's available with CSS transforms is controlling the transform origin. So I have this example here. It's a, you know, I have this sale banner on my website, and I want to rotate it, you know, by -20 degrees. So when I do that, there's actually an origin in the center of the element by default, and your element is rotated around that origin. So in this case, my banner is kind of, you know, going off the page here.

So I could choose to find some additional CSS to kind of slide that banner down a little bit, use some CSS positioning so that it's not going off the page, but then I've altered my site, and it might not degrade gracefully in other browsers. A better approach is to use WebKit Transform Origin. You know, what I really want is to be able to set the origin in that upper left corner, and then have my rotation applied.

So I can do that with WebKit Transform Origin here I've specified "top left," then my rotation is applied, and my banner is no longer going off the screen. The added bonus here is that any browser that doesn't understand CSS transforms will just ignore both of these properties, and you'll just have the straight banner across the page, but then you haven't modified your existing CSS in a way that your site would not degrade gracefully in other browsers.

WebKit Transform Origin has the same syntax as background position, meaning that you specify just a pair of keywords from top left bottom center right. If you don't specify the second keyword, then center is the default. So if I just said "webkit transform origin top" that would really mean "top center." Okay, so that is a quick overview of CSS transforms. Now let's move on to CSS transitions.

I said in the beginning that a transition is really a kind of simple animation. You specify the beginning state and the end state, and WebKit, the engine that powers Safari, is taking care of rendering all of the frames in between. So you go from one state to another by changing those values through JavaScript. So that's when your animation is going to execute.

So let's take a look at an example. So let's pretend that this slide is also a web browser view, and I have this picture in the bottom left corner. So the CSS that I would define for that picture might look something like this. So for the WebKit transform value, my rotation and scale are 0 and 1 respectively. Those are the default values, but I'm just writing them out here for the purposes of this example. And I've translated in the X direction by 20 pixels and in the Y direction by 300 pixels.

Okay? So the animation that I want to happen is, I want it to kind of flip, rotate up to the upper right-hand corner and scale down a little bit, and land in this upper right-hand corner of my "slide/browser" window. So if I were to write, you know, a CSS declaration that looked like-- for this end state, it might look like this. I rotated by 360 degrees. I've scaled it down by 50%. And now, the element has been translated 600 pixels in the X direction and 50 pixels, let's say, in the Y direction.

So to get from the first state to the end state, I'm really just going to change these values of the style through JavaScript. So I'm going to, you know, get my element by its ID, which is "my_flower," and set the style of "webkit_transform" to rotate 360 degrees, scale by 0.5, which is 50%, and set the translation to 600 by 50 pixels. And when I change those values through JavaScript, That's when the animation is going to fire.

So in this example, the property that I've changed is the WebKit transform CSS property, but really many CSS properties can be animated. The majority of CSS properties can be animated. So things like opacity, color, et cetera, you can alter all of those and animate state changes for all of those properties.

Okay. So, there are, you know, we talked about how you have two keyframes, and WebKit is taking care of rendering all of the frames in between your beginning state and ending state. Well, there-- even though you can't modify those keyframes directly, there is some control that you have over that curve. So you can define the way that curve accelerates using WebKit transition timing function.

So, there are a bunch of different curve definitions that you can specify for this property. "Ease" is one, "linear" for uniform acceleration, "ease in," going slow and speeding up, "ease out," going fast and slowing down, "ease in/out," slow/fast/slow. And you can also specify your own curve definition using this cubic Bezier value and supplying X and Y coordinates.

The last piece of control that you need to know about for CSS transitions is WebKit - that you can delay the start of a transition by specifying a WebKit transition delay. And this is basically, you know, maybe a user clicks on a button or something like that, and you know that a second has to pass before you want your animation to start. Well, you can, you know, have that kind of control by using the WebKit transition delay property.

Okay, so that covers CSS transitions. Let's move on to keyframe animations. So keyframe animations have all of the advantages of CSS transitions. You know, they're easy to define, simple to execute, et cetera, plus a few other key features. First of all, you have fine-grained control over the keyframes, so you can, you know, specify the behavior for the first half of an animation or the first 25% of an animation, et cetera.

You also can control the repeat count and repeat behavior. So with transitions, they happen only once when you change the values of a CSS property through JavaScript, whereas animations, you can set them to iterate forever, for instance. And also, keyframe animations have DOM events associated with them so that you can know when an animation has started, ended, or iterated. So we're gonna cover all of these things by looking at an example.

So CSS animations introduce a new rule, and that is @WebKitKeyframes. And this is the way that you define your animation. So I'm saying, "I want an animation to happen "from WebKit transform in the Y direction, "-50 pixels," so that's gonna be off-screen, "down to 600 pixels," so near the bottom of the screen.

So that's my definition for my animation. My animation is named "Fall." To associate that animation with an element, I'm just going to use a WebKit animation name and then add the name of my animation right there, which in this case is "Fall." I've set the webkit animation duration to be 10 seconds, so the animation is happening over 10 seconds. I've set the iteration count to infinite, so this leaf is going to fall forever. And I've set the timing function to be linear, so it's falling with uniform acceleration throughout the animation.

So, the interesting part comes when you begin to define animations over-- you know, that change over the course of an animation. So, before, our leaf was reaching the bottom of its path there and just kind of disappearing, which looked kind of bad. What we really want is for that leaf to kind of fade out as it reaches the end of its path. So here, I want the opacity to be one for the first 3/4 of the animation, and then, for the last 25%, I want it to fade from 1 to 0.

So here, I've defined a second animation named "fade" using the @WebKitKeyframes rule, and then, down here in my leaf definition, I've just chained together those two animations-- "fall" and "fade" for WebKit animation name. I want them both to take 10 seconds, 'cause I want them to happen concurrently.

I'm going to set the iteration count to infinite for both of them. I want them both to happen forever. And I've set the timing function for fall to linear, but I want the fade animation to kind of ease in. So when we chain these two animations together and set these properties like so, we get this effect where, you know, the leaf is falling down the side of the page, and then for the last 25% of its path, it fades in opacity from 1 to 0.

Perfectly clear. So as I mentioned earlier, there are animation events associated with animations, and these are pretty straightforward. You can listen for when an animation starts, when an animation iterates, or when an animation ends. The WebKit animation start, WebKit animation iteration, and WebKit animation end. And you can listen for these events just like you would listen for any other event. Here I'm listening directly on this element for the animation end event.

A couple more points of need-to-know information-- your animation will run if WebKit animation name specifies a known set of key frames, so be careful when you're defining your animation using the rule that we talked about earlier. Also, the duration for this animation has to be greater than zero. And this is true for transitions, as well. You may have noticed there was a property-- "WebKit transition duration" on our earlier flower site, and that was set to two seconds.

The duration for both animations and transitions has to be greater than zero, because otherwise, you're just going from one state to another with no time in between, and so you don't have time to see the animation. So the duration has to be greater than zero. You can also disable animations with "WebKit animation name = none." So that was an overview of CSS visual effects, a way to add hardware accelerated graphics and animations to your web applications. Now let's talk about storing data locally.

So there are two aspects to local storage in iPhone web applications. The first is the HTML5 SQL API, and this has been around since before 2.2. And this is all about storing structured data of your application on the fly. The second part of this feature is creating an instance of your site where all the resource files are cached locally on the device. so you don't have to load resource files over the wire anymore. So let's get started by talking about the SQL API, which is part of HTML5.

So here's an application that I use from time to time. It's a to-do list app, and it's a web app, and it's really great-- I use it all the time. But when I touch that "+" button there to add a new to-do list item, and then I type in the to-do and I hit "Save," you know, I've noticed that it can take anywhere from two to five seconds after I hit "Save" to the point where my UI is updated again. And that's happening because we're sending that information over the wire and waiting to get a response before we update our UI.

A big issue that people face when creating web applications for mobile devices is network latency. So if you were in this morning session, you're familiar with this slide already. But network latency is defined as the time it takes, the round-trip time that it takes for a packet to go from your device to the server and back. Whereas, bandwidth is defined as the throughput amount. So latency on Wi-Fi networks is pretty low, It's about 100 milliseconds.

Latency on cellular networks is just inherently high. It's about 500 milliseconds. So, you know, that tacks on quite a bit of time to any information that you're, you know, sending over the wire and then waiting for a response to update your UI. You know, if you tapped on a menu item in a native application and the users had to wait two seconds for that UI to update, that would be unacceptable.

So, The application that I was just talking about, that to-do list application, would really benefit from storing that data locally, especially when I first enter it. So this is part of HTML5, as I mentioned. It's HTML5 database storage. And this is great because it's a standards-based approach to local database storage. So part of HTML5 in Safari on iPhone right now and eventually everywhere else by virtue of being part of a standard.

Secondly, you know, we're dealing with real-world SQL here. If you're a big SQL programmer, you're going to see all of the same coding conventions and features that you're used to seeing in SQL. This API is asynchronous and callback-based, meaning that your application is never going to be kind of locked up waiting for a database operation to finish.

You begin a transaction, like a write to the database for instance, and then you're free to go execute other JavaScript in the meantime, and your code gets a callback when that write or transaction or whatever you've executed has finished. And lastly, origin-based security is built-in as part of this API, meaning that your application can only - or I'm sorry, your website can only access the databases that it has created, and no other websites can access your databases.

So when I begin talking about this feature, lots of people who have web applications are just like, oh my gosh, I cannot live without the cloud. All of my data has to be synced to the cloud. I can't live without the cloud. I can't have just this data on this one device.

Well, we're not talking about getting rid of the cloud altogether. We're just talking about cutting down a lot of those network operations. You could just choose to only store your data on the device. But lots of people want to also store their data in the cloud. So using this SQL API is going to give you a way to cut down that number of network operations and even do those network operations during idle time, for instance.

So this is great because it reduces the complexity of your application. You know, you don't have to send up every little piece of data as it's entered or as it changes, and then piece it together on the other side. And also, you're going to have two aspects of improved performance.

The first is battery life. You know, network operations are expensive on iPhone, so if your web app is sending data over the wire frequently, that's gonna drain the battery more quickly than normal. And also, you know, going back to our to-do list application example, your application is going to be, you know, more responsive if you're not waiting for a response over the network to update your UI.

And if this data is stored locally, you're going to be able to access it even if your phone is totally off the network. Okay, so let's get into the details of this API. We're going to go through three main parts of it: creating a database, executing transactions, and handling callbacks.

So the first aspect here, creating a database. So if you try to create - I'm sorry, if you try to open a database and one does not exist, then that database will be created. So the best approach here is to first, you know, test for that database functionality using window.opendatabase.

If the functionality doesn't exist, you can fall back to some other code. Here I'm setting up a few parameters. To do is the name of my database stored on disk. I've set a version number to 1.0. I've set this variable display name to a string that's going to be displayed in any UI prompts.

And also I've set an expected size here in bytes. And I pass all of these parameters to open database, and I'm returned a handle to a new database if one doesn't exist already. One important thing to know is that it's really only the first parameter that's strictly required. So if you know that you're opening a database that already exists, you can just provide the name and pass null for the last three parameters and you'll still get a handle to your database.

Okay, so once you have a handle to your database, you can start doing stuff with it, and the way to do stuff with that database is through transactions. So anyone who isn't familiar with database programming, a transaction is really just an atomic unit of work that cannot partially succeed.

So when you start thinking about relational databases and how that data's integrated, this is really important. Like, you don't want to go halfway through, you know, a transaction and have something fail, and then only half of your tightly integrated relational data is modified. That would be bad. So with transactions, if something fails along the way, the entire transaction is rolled back to the beginning.

So all queries in this HTML5 SQL API have to be part of a transaction. And a transaction looks like this. Here I've opened my Todo database and then I just set a transaction on that Todo database handle and I am creating a string of SQL and I'm passing that string to the execute SQL function on my transaction.

And that executes the SQL. As I mentioned earlier, this API is asynchronous and callback-based. So in order to know when things happen, you have to listen for these callbacks. So there's two types of callbacks. The first is a transaction callback, and this is related to the entire transaction as a whole. And the second type of callback is a query callback, and those types of callbacks are related to the individual queries within the transactions.

So let's talk about transition callbacks first. As I said, these are related to the entire transaction, and there's two types of callbacks. There's the completion callback to detect when a transaction has completed, and there's also an error callback, so if there is an error within your transaction and it's going to be rolled back to the beginning, you can know about that as well.

Query callbacks, as I mentioned earlier, are related to the individual queries within the transaction, okay? So again, there's two types of callbacks here for queries. The first is the data callback, which you can use to manipulate the data that you've received back from a query. And the second is an error callback. So, you know, we mentioned that all queries are part of a transaction. And if a transaction fails in the middle, it is automatically rolled back to the beginning.

Well, there's a callback, a query callback that you can use to say, well, this query that I've executed is actually optional. Please don't let the whole, you know, transaction fail and roll back to the beginning. So you can use this error callback, error query callback, to specify that queries within your transaction are optional. If you haven't specified an error callback for a query, then an error on that query is assumed fatal and your transaction is rolled back to the beginning.

So if you want to get started developing with this feature, it's actually also implemented in Safari on the desktop. And that is really valuable because there's some great tools available in Safari on the desktop that you can use if you're developing. So here's an example. It's at webkit.org, and it's just a set of sticky notes, and it's storing both the position of the notes and the contents of the notes in a database on the back end. So if I open up the web inspector and click on this databases tab at the top, I can actually inspect all of the data that is being stored in this particular table, which is great.

You can inspect your data as you're developing and make sure that you're getting the results that you anticipated. This view is also great because if you click on the database name or this little prompt at the bottom, you get a prompt in the main view. And from here, you can execute arbitrary SQL statements.

Again, a great way to kind of test as you go, to make sure you're getting the results that you want. Also, I love it, there's tab completion in this view, so I can just type the letter s and tab to fill in the word select. And it speeds me up tremendously. And that auto completion is also true for table names, etc.

Okay, so that covers the SQL API storing structured data locally. Now let's talk about a feature. It's called HTML5 Offline Applications, and this is new in iPhone OS 2.2, so the update that just came out. So your web application has many resources that kind of come together to make it a web application. You know, you have CSS files, JavaScript files, you might have some video, HTML, etc. All of these come together to make your web app.

Well, there's a way that you can cache all of those files locally, and there's really three aspects that you need to know about to sort of make this work. The first aspect of this feature is the cache manifest. This is just a text file of URLs that specify which resources you want to store locally.

The next thing you need to know about is the update mechanism. How do new files get into the cache and old files are kicked out? And lastly, what events can you listen for to know what kind of state your app or the cache is in? Okay, so let's take a closer look at the cache manifest.

So as I mentioned earlier, this is just a text file, and it's really just a list of URLs, and I've saved mine in a file that I've named "mymanifest.manifest." And that file would look like this. So a required value here is you have to have "cache manifest" as the first line of this file. But from there, you know, comments are any lines that begin with the pound sign, and you're really just listing the URL resources that you want to store locally on disk. And they can be absolute URLs or relative URLs.

So within this cache manifest, there are two different types of entries that you can define. There's explicit entries, and this is the default, but these say, "Go to the cache first for this resource always." And then there's also a way to specify what's called an online whitelist, and you use that with this network keyword.

And this indicates to the browser that you want to always fetch these resources from the network, never from the cache. So here I'm creating this weather application that I want to function offline. I always want to get the forecast dynamically. I never want to show a stale forecast here, so I always want to fetch that over the network.

So I'm going to use the network keyword to indicate that. So once you've defined your manifest, you add this as an attribute to the HTML tag. And that looks something like this. So I have HTML manifest equals offline weather dot manifest is the name of my manifest file.

To make this work, you actually have to make a tweak to your server settings to serve this type of file with a text/cache manifest MIME type. So that's easy to do. On Mac OS X, you just add a line to this file-- private @c.apache2.mimetypes. Just add a line to that file indicating-- in this case, I would wanna serve all files that have a manifest extension with the text/cache manifest mime type.

So now you're using a - you have a manifest defined, and when Safari on iPhone goes to, you know, your application's URL, your resources are going to be initially loaded from the cache if they're there - if they've been previously downloaded. If your manifest file has changed, a new manifest file and the resources within that manifest file will be fetched as necessary.

So this fetching happens automatically if your manifest file has changed. But the part that is manual is you have to actually swap in the new version of the cache files and swap the old files out. So the time to do this is when this updateReady event fires. So here, when onUpdateReady fires, I'm going to call this function yourReadyHandler, which is a function I've defined. And when that happens, I'm going to call swapCache on the application cache. And as I said, that kind of swaps out your old resources and swaps in the newly downloaded version.

So one event that we mentioned there was on Update Ready, but there are a couple other events that you can listen for as well with respect to the application cache. We're not going to go into them in too much detail here for lack of time, but you can check for things like if there was an error, if the files are currently downloading, etc.

So that is today's talk on advanced web technologies. We talked about, you know, feeling built-in with the rest of the system, feeling like a native built-in app. We talked about how to define touch and gesture events through JavaScript with DOM touch. We talked about how to position your content in unique ways and add hardware accelerated graphics to your UI with CSS visual effects. And lastly, we talked about storing data locally, so storing structured data in an SQLite database and also creating a fully offline version of your web app.

So usually when I give this talk, at the end of it people are just like, "Oh my gosh, I never knew you could do all of this stuff in a web application before." And I have to agree that some of this technology is pretty cool. So I have been just issuing an open challenge to the attendees here of the Tech Talks to really take these technologies and really, you know, make something great, make something that people never expected could function in a web application. And then email me about it. Here is my contact info. I'm [email protected]. All of your iPhone web application resources are basically linked from developer.apple.com/webapps. And I've also linked to the HTML5 spec here, and also I've added a link to our CSS visual effects proposal at webkit.org.