Essentials • 51:45
Safari on iPhone enables web developers to create applications that truly look and feel like built-in applications. Learn how to detect orientation changes, recognize touch events, create custom site icons, and other advanced techniques to help you deliver a uniquely native experience in your web application on iPhone.
Speakers: Tim Omernick, Brad Moore
Unlisted on Apple Developer site
Transcript
This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.
Good morning, everybody. Can you hear me? Great. My name is Tim Omernick, and I'm an iPhone engineer at Apple. So over the past year, almost, we've been working really hard to get the SDK ready for people to start writing iPhone applications. Now, obviously, we're very excited about this, but we've also taken this opportunity to add some really exciting things to Safari on iPhone 2.0 that you, web developers, take advantage of in your applications.
So I'm going to focus mostly on that, but before I get started, I wanted to talk about web applications today. There are over 1,700 iPhone web applications, approaching 1,800. There are more popping up every single day. These do a variety of really awesome things. I could talk about all of them, but we'd be here for a while, so I'm just going to highlight three of them that I use very frequently.
First up, here's a little version of Wikipedia. Anybody who knows me knows that I spend way too much time on Wikipedia, so I really like this. You notice it has a nice big search field at the top. It's really easy to get to. Additionally, the content area of this web app is all fit to the width of the device, and so the text is nice and legible. It's very easy to navigate around inside of Wikipedia using this.
This is the iCal train. I live down closer to Apple, so whenever I need to get to the city, I can use this to look up train schedules. I just wanted to highlight the shiny button, sort of iPhone-style art. Additionally, it has the pinstripe background and sort of the standard list look. When you tap "View Schedule," it slides over to a sectioned list, much like you'd see in the iPod app on the iPhone.
Everybody knows Google. I'm sure you've all seen this. I just wanted to highlight this because I think they've done a great job of taking all of their different web apps and sort of condensing them down into something that really fits well and is really usable on the iPhone. I think they've done a great job with this.
So these are really cool apps. Again, there are a whole bunch more. A common thread with these applications is that they look like iPhone apps. People have gone to this extra effort to make it seem like these apps are real native iPhone applications. They really feel at home on the iPhone. So while these look like real iPhone apps, we think that they could be made a little bit better, of course. They look like iPhone apps, but they don't always feel like iPhone apps, and this is an important distinction.
Many of these web applications suffer from what I like to call delayed interaction. Just to show an example of what this is, here's the AOL television listings web app, which I think is actually one of the better-looking web apps out there. It looks like a real native application.
But the illusion starts to sort of break down as soon as you start interacting with the content here. When you touch one of the television shows, instead of getting the nice blue highlight like you're used to in iPhone lists, you get this gray highlight thing and the bubble that pops up. I'm sure you've all seen this thing. So this is informative, but not exactly what you would expect or want in a web application.
Additionally, a web application today cannot take advantage of multitouch or gestures. These are really important to native iPhone applications. Just to show an example here, this is the Maps application. It has the pinch gesture. You can zoom in and out using a two-finger pinch. You can also zoom out quickly by tapping with two fingers on the map. So this is something that's just not possible today in a web application, and we're hoping to solve that.
So what are we going to talk about today? We're going to go over JavaScript touch and gesture events, CSS visual effects, which you can use in addition to JavaScript touch and gesture events to provide fluid, responsive user interface feedback. We're going to talk about how to store user data within your web application, and additionally, we're going to go over some tips and tricks that you can use to polish and really add some shine to your iPhone app. So let's get started with JavaScript touch and gesture events. You can think of this as multi-touch for JavaScript.
So the first thing you get right out of the box is more interactive controls. Instead of this sort of delayed interaction thing that you see in iPhone web apps today, you can respond directly to the user's touches. You can implement custom gestures. We have identified a couple of common ones that we think people are going to use in all sorts of different applications in a variety of ways.
So we've come up with gesture events that sort of standardize two gestures that we're very fond of. But you can use the raw touch events to implement whichever gestures you want. So you can have some sort of a two-fingered pinch while you're doing a zigzag kind of thing or whatever. Just use your imagination.
Drag and drop is something people have been asking us for a lot, and until today, it just has not been possible on the iPhone. So we're going to show you how to do that. Pretty much this is open-ended. You can use this for whatever you want, whether it's just simple touch interaction or really advanced multi-touch gestural input. Now you can do the same sorts of things that native iPhone applications can do.
So what's the big problem with mouse events? Why can't you do these sorts of things with mouse events? Why didn't we start with this existing model and maybe extend that to support a device that's based on a touchscreen? Well, there are a lot of web applications and web pages out there that were written under the assumption that the user is on a computer and has a mouse and that there are scroll bars. None of these assumptions are valid on the iPhone. So we have this sort of simulated event model where when you're touching the page and moving your finger around, you're really just scrolling around. And no events are really sent down into the page until you tap and release.
And this works fine on the vast majority of websites that are out there, but it doesn't afford the kind of flexibility that you might want in an application. Amen. So for simplicity for web applications that are designed from the get-go to work well on a multi-touch-based platform, we're introducing JavaScript Touch and Gesture Events.
If you've done any sort of programming with mouse events, though, you can sort of conceptually think of this as a lot like mouse events, but instead of having one cursor with one point, you've got a lot of cursors. In actuality, they're fingers, but they work pretty much the same.
So to show you a little demo of what's possible with JavaScript touch events, I'd like to invite my friend and colleague Brad Moore on stage for a little demo. Brad? Thanks, everyone. I'm Brad. I work with Tim on the iPhone software engineering team. So we've got some great demos for you today, but they've been distilled down for simplicity's sake, and I want to start out with a slightly more intricate, motivating example.
So here we have Apple's retail page, but it's been enhanced with a fun feature that works beautifully on the iPhone. Let me show you that now. This is, of course, a normal web page. I can scroll around, zoom into images. But if I zoom into this div, I discover it's not just a static image. It's rather an embedded VR scene.
And the cool thing about this is it's not using QuickTime VR. It's, in fact, not using any plug-in at all. It's using nothing but CSS transform, JavaScript event handlers, and HTML elements, so all core web technologies with which you're probably already familiar. And it's just fun to use. It's very responsive. It's even hardware accelerated. And it's this direct interaction that makes iPhone apps so fun to use natively. And now web apps can be first-class citizens in terms of the interactivity story. So hopefully this whets your appetite, and now Tim's gonna take you through the details.
Thank you, Brad. So that was just a little example, pretty high level, of what you can do with touch events. So now I'd like to talk a little bit about how they work. So like I said before, this is pretty similar to mouse events. But each one of the user's fingers you can sort of think of as its own distinct mouse. So each finger that comes in contact with the screen will generate a sequence of events. And these events are: when you touch the screen, that will send a touch start event.
If you then move your finger around on the page, that will send a sequence of touch-move events for every time you move your finger. And then when you lift your finger, that will send a touch end event. So just as an example, a simple example of how you might want to use this, if you wanted to detect something like a tap or just a double tap with a single finger, you could look for a touch start followed by a touch end with no touch moves in between.
Additionally, there is a touch cancel event. If you've been paying attention to the UIKit sessions, you might see some similarities between this event model and the touch event model in UIKit. So we've got this touch cancel event, which is sent by the system in certain situations, like when you're interacting with web content and you get a phone call or the user suspends Safari.
For the touch cancel event, the difference between touch cancel and touch end is you wouldn't necessarily want to perform whatever action your content was supposed to perform on touch end on a touch cancel. So to register for these events, this works just like any other DOM event. We have HTML event handlers, onTouchStart, onTouchMove, onTouchEnd, and onTouchCancel, just four new handlers. And these all take the event as the first argument. Of course, you can also do this from JavaScript using Element.AddEventListener.
So you've got an element that is registered to receive touch events. What do you do from there? Well, this event isn't any normal event. This is actually a touch event, which has a few special properties that you should know about. If you want to process all of the touches that are on the page, regardless of what they're touching, you can look at event.touches. And this is really useful if you're implementing your own custom gesture, where if you don't really care about where the user is touching on the page, you just care about what the fingers are doing in some relative fashion.
So you can get all the touches on the page through event.touches. If you just want to look at the touches that are in the node or element that's receiving this event, you can get target touches. This is really useful when you have multiple things on the page that are all independently tracking touch events, so that you can easily differentiate touches in one element from touches in another.
Additionally, you can get the set of changed touches, which are just the touches that have moved in this event. This is, again, useful if you're implementing a custom gesture where you're just looking at the fingers that are moving. Or, for example, something like drag and drop, where, again, you're just interested in moving fingers, not necessarily the full set of fingers that are down on the screen.
Okay, so that's pretty easy. We can get the set of touches. What is that? Well, this is just a standard JavaScript list, so you can get the number of touches that are down by getting the length of that touch set. You can just access this touches array just like any other array, so you can get the event.touches at i.
Important touch properties. Like I said before, a touch event -- touch events work a lot like mouse events. And in fact, you can think of a touch as encapsulating a lot of the same sorts of information that a mouse event encapsulates. So a touch has a target, which is the node that is receiving the event.
Additionally, there's an identifier which you can use to track the touch between successive invocations of your touch handlers. This is useful for something like drag and drop. There's Page X and Page Y. This is the touch location in page coordinates. Just like mouse events, though, you can get the coordinates in other coordinate spaces, client and screen.
So these are pretty much the important touch properties that you're going to be dealing with in general. A couple of examples of how you might want to use touch events. If you wanted to do some sort of a two-finger tap like you see in Maps to zoom out, that would be pretty easy to do.
You could just add a touch start handler to your element, look for two touches that are down in that target, Cancel the operation on touch move because that would be more of like a pinch gesture or some sort of a rotate gesture or something like that. You're just looking for two fingers coming down and then releasing. And then on touch end, you would perform whatever action you would perform on the two-finger tap. It's pretty easy stuff.
There's the swipe gesture. You see this a lot in Apple native applications, like in Mail, to quickly delete messages. You could do something like this pretty easily with touch events, where you could have a touch move handler that just looked for motion mostly in the X direction. Of course, canceling the swipe if there's any diagonal or vertical motion or if more fingers come down.
So these are a couple of the common gestures that you see all over the place on the iPhone that now you can actually add to your web application, which I think is pretty cool. Now, there are a couple of gestures that Apple is pretty fond of, and we think that people are going to use these in a lot of different applications. We just keep coming back to these over and over again. There's the pinch gesture to zoom in and out. You see this all over the place in the iPhone, in Safari and Mapped and Photos.
There's also a rotate gesture, which I don't think you see anywhere on the iPhone, right? But it's pretty cool. We keep coming back to it for our demos for touch events. So we'd like to standardize this behavior and make sure that it feels consistent in all of your applications. So we're adding gesture events, which are a simpler way to track touches, specifically two or more touches that are happening on the screen at once.
Now, with touch events, you can get access to the set of raw touches and perform much more advanced processing. For gesture events, this is just for simplicity and ease of implementation. So when there are two more touches on the screen and you're registered to receive these events, you'll get a gesture start event. Followed by one or more gesture change events for when your fingers move around, or if additional fingers come down on the screen or are removed. And finally, there's the gesture end event for when the gesture is over.
So to register for these event handlers, just like with touch events and mouse events and other DOM events, there's an onGestureStart, onGestureChange, and onGestureEnd HTML attributes that you can use, or you can do @EventListener. By the way, touch and gesture events both capture and bubble, as you might expect if you're a JavaScript pro.
Okay, so we've got an element that's receiving gesture change events. Well, what's in this event? If you wanted to do something with the rotation of the gesture, you could look at event.rotation. And this is the number of degrees clockwise that the user has rotated since the gesture began.
There's also the scale, event.scale, and this is a value that is less than one when the user is pinching in. You might interpret that as maybe a zoom out or something. And it's greater than one when the user is pinching out, maybe sort of a zoom in operation.
It's interesting to note the rotation and scale can both be set or are both set in a gesture event, so you can actually respond to both gestures simultaneously if you wish. Additionally, you can have a single element that responds to both touch and gesture events, allowing for all sorts of interesting multi-touch interactions.
I should mention prevent default. This is the standard JavaScript mechanism for controlling browser behaviors. This is pretty important for touch events and gesture events because Safari implements default implementations of touch events and gesture events. For touch events, that's how Safari scrolls around on the page. For gesture events, that's how Safari zooms in and out.
So you can control this behavior, override this behavior, by calling preventDefault inside of your touch or gesture event handlers. So just a quick example for a touch handler to prevent scrolling inside of some element, you would call preventDefault on the event. And in a gesture change handler, you would call prevent default to prevent zooming inside of Safari. You can also turn off zooming using other techniques like the meta viewport tag, but this allows sort of selective control over the zooming behavior for certain elements or not.
So that was JavaScript touch and gesture events, just a couple simple additions to HTML and JavaScript that you can use to implement the same sorts of advanced multi-touch interactions that are possible in native iPhone applications, which I think is pretty exciting. So now I'd like to talk a bit about CSS visual effects. This is a new technology in Safari on iPhone 2.0.
It's also on Safari 3.1 on the desktop. And this will allow you to perform hardware-accelerated, really, really fast, efficient transforms and transitions and animations. And this is really useful when combined with touch and gesture events, because you can provide the sort of fluid, responsive, immersive feedback that you're used to in an iPhone application.
So again, the big deal here is that CSS visual effects on the iPhone are hardware accelerated. This means that when you affect an element by transforming it somewhere else on the page, you're not affecting the page layout, which is a really expensive operation that can go through the whole DOM, maybe execute some JavaScript, et cetera, et cetera. So this is a very efficient way to affect changes on your web page.
So for best performance, you should avoid changing-- these are just the standard sort of DHTML things that you're used to. Don't change the top, left, and width, and height to sort of move and resize elements. Instead, there's a WebKit transform property. I'll talk about this in a second.
And you can use this to affect the sort of hardware-accelerated transforms that I'm talking about. Additionally, you should try to avoid adding or removing elements to or from the document. This can also be pretty expensive computationally and cause relayout and repainting. So instead, try to change the opacity of elements that are already in there. If you want to show something on the page, just fade it from opacity 0 to opacity 1.
A couple of examples of CSS transforms. So we've got this little green box. We're going to go ahead and set different transforms on it. Here we're going to set it to translate 300 and 300, so it'll move down and to the right. Here we're going to rotate it 152 degrees. And let's go ahead and make it twice as big as it is right now.
So these are just a few of the different effects you can achieve using CSS transforms. There are actually a whole ton of them, like skew effects. You can do 3D perspective transforms, or even apply arbitrary 4 by 4 matrices to elements. But I wanted to highlight these three because you might be able to see how these map almost directly to touch and gesture events. You might imagine that the translate for this element is controlled by just dragging around on the page, and the rotation and scale are controlled by gesture events.
So just a code example of how you might do something like that. We've got an element that is set to receive touch events. And what we're going to do is take the first touch out of the touch list and just grab the X and Y out of there. So we're going to figure out where on the page the touch is. And this is pretty simplistic, but we're just going to move the element to wherever the finger is by setting the WebKit transform.
This is a much more efficient way to do this kind of thing on the iPhone than setting top and left. I'm not going to get too into detail here. This is actually a very, very deep topic with a lot to cover. There's an entire session that's devoted entirely to this. It's later today in Presidio at 3:30.
It's called "Enhancing Your iPhone Web Application with CSS Transforms and Animations," which is quite a mouthful, but this session is really awesome. I highly encourage everybody to check this out. Now I'd like to invite Brad Moore on stage again for a quick demo to show us how to use touch and gesture events.
Thanks, Tim. So we're actually going to see code this time. We're going to dive into an example of drag and drop. And for those of you who somehow haven't seen drag and drop before, here's a page in Safari on my Mac. And as I click my mouse, the image changes.
As I drag my mouse, the image tracks the cursor. And as I release my mouse, the image changes again and it stops tracking. So this is a really common DHTML pattern. And it's easy to implement in JavaScript with mouse events. So let's see the source for that now.
So we've got three mouse handlers that correspond exactly to the events I described. On the mouse down event, I'm performing an image swap here, changing the source. On the mouse move event, I'm updating the left and top properties of the style attribute so that it tracks with the cursor. And in the mouse up, I'm again swapping the image. Pretty simple, right? Let's see how it works on the iPhone.
So here's the page, and when I tap on it, I don't get any feedback. And instead, I get this dialogue asking me to save the image, not what I was expecting. And when I try to drag it, the entire page pans rather than the image. And if you've ever developed a web page that takes advantage of mouse events and then viewed it on the iPhone, you've found that you don't really get interaction over time because of the feature Tim spoke of, that Safari uses all your events to navigate about the page and scale it. So we've got touch events now, so let's fix that. So I'm going to go back to the code.
And first things first, let's go to the body and install some handlers that are simply going to prevent default. Now, as Tim mentioned, it's especially important to prevent default when you're working with events on the iPhone because so often the default behavior causes some very user-visible and potentially jarring behavior if it's not what you're looking for. So with just this change, let's see what the website looks like on the phone. So I'll reload.
And now, as I press and hold on the image, I don't get any dialogue. And as I try to drag it, the page doesn't move around. So of course I'm not getting the interactivity I do want, but I'm no longer getting the interactivity I don't. So going back to the code, let's go install the handlers that will actually do the work we're interested in.
So I want to point out that I'm installing the handler on the image itself, the handlers I care about. And this is an important distinction for mouse events. With a mouse event, it's going to deliver the event to whichever element happens to be beneath the mouse at any point in time. With a touch event, that's not the case. The recipient of the touch start is going to continue receiving any subsequent touch move and touch end events, even as you move off the element.
So it's possible to track it if you move your finger very quickly, for instance. And we think this is an easier programming model, especially when you have multiple fingers on the screen. So with that aside, let's go define the handlers. So right next to the mouse down event handler, I'm going to define touch start.
And you see the touch start looks almost line for line exactly like the mouse down does, except that instead of pulling the information directly from the event itself, I'm getting it from a touch within the event. Now, of course, there could be multiple touches here, and if I want to truly take advantage of multi-touch, I would reach in and grab all those different touches. But if I want to do that, I'm going to have to do it in a different way. So I'm going to go ahead and add a touch move.
And I want to point out something here. Right now, I'm using left and top on the touch move. And that's going to work. I'm going to update the CSS style. And that's going to cause the page to relay out and redraw. And it will be pretty responsive. But the frame rate won't be tremendous.
And iPhone users in particular have come to expect really fluid and responsive feedback to any interaction they have. So rather than go this route, I'm going to instead use the WebKit transform property and just do a simple translation, as Tim discussed. So with this change, let me go back to the phone and show you what it looks like. And now I've got Fluid Drag and Drop. And that's pretty exciting because this was not possible before iPhone 2.0.
So thank you for that. But you know, we're not just trying to achieve parity with mouse events. We actually have a very powerful programming model. And if you'll bear with me, I'm going to leave this as it is, but leave the handlers as they are. But I'm going to add a second element to the page.
Oh, which doesn't appear to be here. Well, demo gods are not with me. But I cannot show you this now, but it's very easy to have multiple images dragging and dropping at once. So that said, that's not the only way you want to interact with multiple touches on screen. You can do independent actions and have each event apply to a separate element on the screen.
But something else you might want to do is combine those touches together to synthesize a single event, a gesture as we call it. And we certainly encourage you to go out and discover and play with your own and apply them to websites. But Apple has already popularized some system-wide gestures that we want you to use for free to get consistent behavior. So I have a toy little authentication page I want to show you. I'll just go to that now. Okay.
So, this is a little dial. It's an image separate from the background. And you can imagine that visually I want to update this using CSS transform. And just as an aside, this is something, like, you couldn't do without CSS transform. So, CSS transforms are very powerful in addition to giving you great performance. But I'm most interested right now on the interaction. So, let me show you in the source code how I can actually change this page to make it respond. And, of course, it doesn't respond at the moment.
Here's the source. And first things first, I'm going to prevent default so I don't get the interaction I don't want. And then I'm going to go in and add some gesture listeners. And note here that I'm adding event listener rather than doing inline JavaScript via attributes. Both methods are supported, and these are fully compliant DOM events.
So going up to the meat of the implementation, I'm going to have gesture start, gesture change, and gesture end. And I'm doing a little bit of bookkeeping in start and end so you get a nice feeling of inertial scrolling. But really, everything that makes this interactive is in gesture change. And I'm doing two things. I'm preventing default for good measure, and I'm updating the rotation.
And to update the rotation, I simply query from the event, and then I'm going to add a new rotation. And then I'm going to add a new rotation. And then I'm going to add a new rotation. And then I'm going to add a new rotation. And then I'm going to add a new rotation. And then I'm going to add a new rotation. And it gives me the angular displacement in degrees.
And that's it. That's all I have to do when I get consistent behavior with the rest of the system, instead of tracking multiple touches coming and going on the screen and making complex inferences about what angle I should be at now. I can just use what the system provides me. It's not really more expressive than touch events, but it's a whole lot easier, and we think you're going to like this. So let me save this change and go back to the demo.
[Transcript missing]
Awesome. Thank you, Brad. So that was CSS Visual Effects. Now I'd like to talk to you about storing local user data in your iPhone web application. There are certain kinds of data that you might use in your program that rarely or never change. A couple examples here. There's static application resources, things like images and scripts and style sheets. These may never change for the whole lifetime of your web app, but your users are constantly downloading them over and over again.
User-created content and preferences, even things as simple as, you know, display sort orderings in a list or whatever, there are certain pieces of information that maybe you want quicker access to than having to go fetch them from a network.
[Transcript missing]
When you open it and start scrolling around and zooming to different places, it's actually caching all those tiles to disk, so the next time you open Maps and start scrolling around in the same area, which is pretty convenient because you probably don't move around that much, those tiles are already going to be cached, and so the user experience is improved because you don't have to go redownload everything. And a lot of our apps do this. The YouTube app does something similar for video data and thumbnails. So you can imagine using this sort of technique in your web application as well.
In general, we'd kind of like to get the ball rolling and get you guys to start thinking about pre-caching data as much as you can for faster access or eventually offline use. You should always strive to eliminate unnecessary network traffic. This is especially important in a high-latency environment like Edge or even 3G.
So to solve this problem, we're introducing named databases for your site. You get five megabytes maximum per database. And this is a database that you open and control through JavaScript. But behind the scenes, it's actually SQLite. This is the same database that we use in a lot of Apple's own iPhone applications. For example, the Contacts database, that's all just SQLite.
Again, there's YouTube and Maps that store everything in SQLite. A whole bunch of applications in the iPhone are actually using this underlying technology. So you know it's screaming fast and it works great. It's built on asynchronous transactions, so while you're running a database query in your JavaScript, it's not going to interfere with the rest of your web application until it's complete.
I just want to show you a quick example of how you can use this feature. So to open a database, you'd start first, if you wanted to be a good web citizen, by checking for the existence of the database feature itself, which you can do by looking for window.opendatabase.
And this is the function that you call to open a database for your website. You give it a name, a version, a display name, and an estimated size. You don't need to worry too much about making the name unique, because your database is already unique to your domain.
This will return null upon failure, which you can do whatever you want. Probably shouldn't alert like that, it's a bad idea. So once you've opened your database, the first thing you're going to want to do is create a schema. This involves creating tables and populating your database with default objects. So we're going to do that by starting a transaction in our database. You just call database.transaction, and you pass in a function that will get called to run your transaction.
And here's that function now. You see that it just calls execute SQL on the transaction. And the SQL that you're executing here just creates a table called Things with a column name, so specific. The second argument here is an empty array. You can actually pass in arguments to your SQL string if you want. You can have wild cards in there. And the third argument is populate database, a function that I define. which, upon successful creation of the table, will go and insert an object into the table. In this case, we're putting an iPhone 3G into the Things table.
Okay, so you've got your table all set up, got your schema in place. To perform a query, again, this is just a transaction, so inside of your transaction, you're going to execute some SQL. And in this case, we're going to select the name of everything in the things table. And when that's done, it's going to call a function called show things.
The show things function, it's pretty convenient, actually, in the results of a database query in JavaScript, because all you have to do is get results.rows, and these are the rows returned from the query, and then you can just look up properties inside the objects that are bound directly to the database column. So in this case, I just alert the name of everything in the database.
It's pretty simple to use. I'm not going to get too into detail on this because this is actually part of the HTML5 specification, which Apple contributes to. The database feature is actually available in both iPhone 2.0 as well as Safari 3.1 on the desktop. So this is an open standard.
If you want to know more about the database feature, there's full documentation and examples and everything, you should check out the W3 site, the HTML5 Working Group, where you can read about local databases as well as the other things in HTML5. There's also an entire session here at WWDC tomorrow at 2:00 PM. So if you're interested in how this works, you should definitely check out this session.
So that was storing local user data. Now I'd like to talk a little bit about some tips and tricks that you can use to really add some shine and polish to your iPhone web application. So this is the link highlight. I'm sure you're all familiar with this thing.
You can actually customize the color of this. It doesn't have to be gray. You can make it pink or orange or whatever. You're more likely to just want to turn it off, which you can do by setting the color to something that's transparent, just have an alpha value of zero.
There's the callout bubble that appears when you hold down on some clickable element on the page. Again, this is useful for links and such, but not so much for buttons and other UI elements. So you might want to turn this off by setting the CSS property WebKitTouchCallout to None or Default to turn it back on.
Detecting orientation changes. If you have a sort of advanced iPhone application that maybe has two different views, depending on whether you're in portrait or landscape mode, you can use the orientation change event to detect the changes in the user interface orientation of Safari. So you register for onOrientationChange, passing in your handler function, and then you can get the current orientation by looking at window.orientation. The values there are zero for standard portrait mode, 90 and -90 for the landscape modes.
Web Clip. This is something that I'm sure everybody in this room knows about, but I just wanted to stress this. I think it's pretty important. Any page or web app from within Safari on the iPhone can actually be added to the home screen as a web clip so that users can access them just like applications.
This is really cool. By default, the icon for your web clip will just be a screenshot of your site scaled down to fit. And if you kind of squint, you can sort of make out what those sites are. But, you know, users really like when you take the extra effort to make shiny, distinctive, simple icons so they can really quickly recognize which site is which. So please, if you are making a web app or a web page for the iPhone, specify a custom icon for it, which is pretty easy to do. This works a lot like fav icons. You just put a link tag in your document.
Here we're specifying the Apple Touch icon and pointing it at a ping file on the web server. Now, this will specify the icon just for that one document. If you want to have an icon that is applied across your entire site, which Apple.com and various other sites do, you can install appletouchicon.ping just at the root of your web server, and Safari will automatically look there whenever you're adding a web clip.
Your icon should be 57 pixels by 57 pixels. If it's any other size, then Safari will scale and crop it to fit inside the standard icon size. Your icon will automatically be rounded and have the glass applied to it, so there's no need to do that. However, if you have a really good icon designer, someone who's really picky and wants to specify exactly, you know, how shiny it should be, you can specify a pre-composed icon, which is the full real deal.
No rounding or no shiny stuff will be applied. We'll just take your icon as is and display it on the home screen. So, clapping icon designer over there, apparently. So, you can do that by doing exactly the same thing but tacking -precomposed to the end of Apple Touch Icon.
The auto-correction feature on the iPhone is really awesome. It's really powerful. It works in multiple different languages, et cetera, et cetera. But your web application may have its own sort of completion UI, and you wouldn't really want the iPhone's built-in auto-completion to sort of be happening at the same time as that. So if you want to turn that off, you can use the auto-correct attribute on the input element.
Google's little completion thing. UI WebView. So I've been sort of talking about all of this in the context of web applications, but WebKit is actually useful in a native application as well. So you can make it in code, make a UI WebView in code, look at UIWebView.h. But we've also got interface builder support, so you can just drag out a WebView. Just like on the desktop, loading a document into a UI WebView is really easy. You just make an NSURL, you wrap it in a URL request, and then you give that to the WebView through load request.
Now, you can imagine doing something kind of boring and simple with this, some sort of legal, please, blah, blah, blah, I agree to sell my soul sort of thing. But you could do something more interesting with it. You could have some sort of like a chat client and use it as a display engine for the speech bubbles if you want to do something like that. There are a multitude of different uses for WebKit inside of a native application.
If you're going to do anything sort of complicated like this, you might want some sort of communication between your web content and the native side. So you can control the web content inside of a UI web view through String by evaluating JavaScript from String. And so this will allow you to call functions that you've defined inside your custom web content to append things to the document or just change whatever's in the page.
Communication the other way, we don't have WebScript object yet, but you can achieve some level of JavaScript to native communication through the UI WebView delegate mechanism. An example of how you can do something like this. Here we've got a WebView should start load with request navigation type method, and this is defined on the delegate of my WebView.
This is such a hack, but I think it's kind of cool. So here we're looking at the URL scheme, and we're looking for a string that we've defined, in this case, myapp. And if the rest of the URL is some command that we recognize, like do something, we'll go ahead and do something. And then from the JavaScript side, to invoke this command, all you have to do is just navigate there.
You notice in the Objective-C side, we return "no" to actually prevent navigation of that non-existent bogus URL. So those are some tips and tricks that you can use to really add some shine and polish to your app. I'd like to invite Brad Moore on stage one final time to show you how you can bring it all together and really take advantage of these tips and tricks.
Thank you, Tim. So we just covered a huge array of things, and rather than try to incorporate every single item from that bag of tricks into a toy website within UI WebView, I want to ground this with an example that's actually out on the web today. A lot of you are probably familiar with IUI. It's a framework that came out within about a month of the iPhone's launch.
And it tries to, with a little bit of clever CSS and JavaScript, make it very easy for web apps to have the same look and, to a certain extent, feel of native applications. So here we have an example of IUI as applied to Digg. And indeed, it does look like a native navigation-based app. I can scroll through, and it looks great.
But as soon as I begin interacting with this, I begin to notice some discrepancies. So notice that when I tap on something, the blue highlight isn't responsive. It actually comes after my finger is already lifted. And when I tap on buttons, I get an odd highlight. In fact, if I tap and hold, I get a highlight and a callout that are very jarring and sort of make it impossible for me to suspend my disbelief. It no longer feels like a native application.
The IUI developer should be commended. I mean, they used every trick at their disposal to make this look like a native app. But before today, making this feel like a native app was just really an impossible task. But now that we have all these tricks Tim just discussed, we can improve this greatly with just a few simple changes. So let me go over to the code and do that now.
So here we have IUI's CSS page. And I should, as an aside, we could prevent the default behavior like the callout and the tap highlight, as mentioned before, just by preventing default on the touch event. But with a framework like IUI, there is some behavior you do want, like the scrolling. So preventing default is a little heavyweight, and we can do something more precise if we use CSS. So here I have my very promiscuous selector. Please don't do this in actual code. But for the purposes of the demo, it's a lot easier to apply to everything.
So you see that I'm setting the web touch callout to none and the webkit tap highlight color to a clear color, which effectively disables it. And there's no performance cost having a clear color. So if I set these two things, I'm going to remove some of the artifacts I don't want to see. So, you know, two lines of code, really. Let me show you what the demo looks like now.
And of course, I can still scroll, but now when I press and hold, I don't get any jarring highlight or callout. And I think that's really wonderful, and it took almost nothing to achieve. We also probably want the blue highlight and other elements to be more responsive. And there are a lot of ways to attack this.
Probably the correct thing to do is rewrite the JavaScript handlers to use touch events directly, since it is designed for the iPhone. But another thing we could do is simply install a no-op touch handler, and then all of a sudden the cool and active pseudo class is going to be reinterpreted by Safari on the iPhone to last for the duration of the touch down. And that's something else we can try.
But what I'm going to do for this demo is go into the code and... Go to the JavaScript, and I'm going to add a touch start listener that does a tiny bit of the code, a tiny bit of the work that the existing click handlers do, but it's just going to do it earlier in the process. So if I make this small change and then go back to IUI and reload, You'll see that all of a sudden I'm getting that responsive feedback that just makes this feel like a native app.
Now, we've got touch events now, and you can imagine all sorts of cool features you would add to make this even more like a native app or better. We could add reordering. You name it, we could add it. But you see how little code it took to make it suddenly feel so much better.
And I think that's a message you should really take home. You don't have to have a visually complex or an interactively complex to benefit really greatly from incorporating these techniques. So hopefully you'll take these techniques home and make your web apps feel as good as they look. And I think Tim has more to cover.
Thank you, Brad. So in summary, we think that web apps already look good. You guys have done an awesome job of making sure that your web apps look like they're at home on the iPhone. But now that your apps can feel good, too, you can use multi-touch interaction in the same way that a native application can. You can use touch events combined with CSS visual effects for native performance and really fluid, immersive, responsive user interfaces.
You can cache data locally for faster access. This is always going to improve the user experience of your application. You should do this wherever possible. In general, I hope after this talk, you're more generally equipped to fine-tune your web application for the iPhone. If you want more information about anything that we've talked about today, you can ask Mark Malone or Vicki Murley, our Safari Internet Technologies evangelists. We've also got an entire section on developer.apple.com that's devoted to web application development. You can look on developer.apple.com/webapps.
A few sessions I wanted to mention. I mentioned a few during the slides, but here they are again. Enhancing your iPhone web application with CSS transforms and animations. You'll learn how to do all sorts of really amazing 2D and three-dimensional effects and animations in Safari on the iPhone. using Dashcode to create and debug iPhone web apps. I didn't mention Dashcode in this talk at all, but they've made a bunch of great enhancements for Safari on iPhone 2.0 to help you create and debug web apps.
There's also a hands-on session tomorrow where you get to build an iPhone application like what you saw today. Hands-on. There's a lab coming up today at 2:00. I'll be there, Brad will be there, a bunch of my team will be there. So if you have any questions about iPhone web application development, please don't hesitate to come down and ask questions.