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: wwdc2005-128
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 128
$eventShortId
Shortened ID of event: wwdc05
$year
Year of session: 2005
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC05 • Session 128

Introduction to Web Kit Development

Application Technologies • 41:54

Learn how to enable your application with Web Kit, the same powerful HTML and JavaScript engine that powers the Safari web browser.

Speakers: Chris Blumenberg, Kevin Decker

Unlisted on Apple Developer site

Transcript

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

Hello. Welcome to Introduction to Web Kit Development, Session 128. My name is Chris Blumenberg. I'm a software engineer on the Safari Web Kit team. So let's get right to what you're going to learn here. First, I'm going to briefly discuss what is Web Kit. I'm going to go into the basics of Web Kit.

Then I'm going to talk about what can be done with Web Kit. Web Kit is not just about web browsing and I'll show you that. Then I'm going to spend the majority of my talk answering common questions. These are questions that are asked by developers who are new to Web Kit.

So what is Web Kit? Well, when people think of Web Kit, they usually think of Safari. It's the engine inside of Safari. It makes Safari render web pages. It's a framework. It's available to Cocoa and Carbon programs on Mac OS X. Its responsibility, its main responsibility is to display HTML, images, plugging contents such as Flash, QuickTime, et cetera. It's basically an API wrapper around Web Core and JavaScript Core. Web Core is our open source engine based on KHTML and JavaScript Core is our open source JavaScript interpreter based on KJS. And as of this week, Web Kit's open source too.

So what can be done with Web Kit? Well, I'm going to answer that question by telling you what has been done with Web Kit. So here are some really cool apps. I'm a little biased, but they're pretty cool, I think. I'm going to focus on a few of them here.

First one is Dashboard. I probably don't need to tell you what Dashboard is, but what's cool about Dashboard is its use of Web Kit. When I think of displaying a web page in a program, I think of a white square inside of a window. But in Dashboard, a web page is the actual program or what they call widgets.

Then there's Mail. Mail uses Web Kit for displaying email messages and in Tiger, it uses Web Kit for editing and composing email messages. It does that using our Web Kit editing feature which we added in Tiger. And then lastly, I'm going to focus on this program, Coliqui, which is an IRC client which uses Web Kit to display IRC text.

It's a really cool app. In fact, I think it's become the IRC client of choice on the Web Kit team. So with the examples I've shown up here, the ones that I focused on, I want to draw this point that it's not just about browsers anymore. You can do things with Web Kit that's not just about web browsing.

So developers ask a lot of questions. Being on the Web Kit team, we are bombarded with questions. But that's okay. We actually like that because that reminds us that, you know, people are using our technology. So what I've done today is I've compiled a set of questions that come from developers who are new to Web Kit. So let's start off with how can I create a web view? Well, before I go into that, I'm going to discuss what a WebView is. WebView is Web Kit's main view class. In Safari, it's basically responsible for displaying everything but the Chrome.

So to create a web view, there's several ways to do that. You can create it in Interface Builder. Basically, in Interface Builder, it's just a drag and drop procedure. From code, you can do it using Objective-C, our Cocoa API. Or you can do it using our C API.

So here's a code example of how to do it with Cocoa. Basically, you just call the standard initWithFrame method on WebView. And then once you've done that, you add the WebView to the view hierarchy using addSubview. And here's how you do it in Carbon. It takes a few more lines of code to actually do that in Carbon. The main thing you have to do is call hi-webview-create. That creates the WebView. You call hi-view-setframe. That sets the frame of the WebView. And then you call hi-view-add-subview to add it to the hierarchy.

So I discussed how to create a web view. Now let's go to loading content in the web view. Now, loading a URL, telling a web view to load a URL is a pretty straightforward thing. But developers tend to ask, how can I load content from memory when I don't have a URL for that content? Well, before I go into that, I need to discuss what a web frame is. See, every web view has one or more web frames. The web frame's main responsibility is to manage the load of content.

It holds that content or that data with the web data source class. It displays that content with the web frame view class. So in this simple example to the right here, we have a simple web page. We have actually one web frame, which is what we consider the main frame. And in this example where we have multiple frames, we have one frame for the mainframe, one frame, one webframe for the child frame, and another webframe for the frame to the right there, which is another child frame of the mainframe.

So loading in WebView. This is done. This is-- you instantiate this. You initiate this on a web frame. and there's several content types that you can ask WebFrame to load. You can ask it to load an NSURL request, which is basically a wrapper around an NSURL. You can ask it to load an NSString, which is most likely going to be an HTML string. You can pass it NSData. You can ask it to load NSData, which is basically your data in memory, regardless of the MIME type.

Or you can pass it a Web Archive. And Web Archive is a new data type, which we unveiled in Tiger and I'm going to discuss that later. And lastly, you can hook this all up in Interface Builder so that you can have a text field, which is basically a URL field. Once the user hits return, it will automatically send that URL to the WebView and we're going to show you that as well.

So to get back to the question, how do I load content from memory with NSData in my web view? The first thing you want to do is make sure-- well, a good thing to do is make sure that the web view can handle the MIME type for the content. And you do that using the canShowMIMEType method. So once that passes, you get the mainframe out of the web view. And then you call the load data method on the mainframe.

And just in case you're curious, this is the way you do it with NSURL request. You basically get the mainframe as we did before. Then you create a request using request with URL. And then you ask mainframe to load request. So let's go to a demo of how you can do all this in IB without any code whatsoever. And then we're going to bring on Kevin Decker. Thanks, Chris.

So -- As Chris mentioned, there's a number of ways you can use this in your programs. You can use it from Carbon, you can use it from Cocoa. In fact, we're going to show you a way that requires hardly any lines of code. In fact, it requires no lines of code. And so, we decided to put a little game for this at my expense, of course. And we're going to show you how to do this in one minute or less. And I happen to have a stopwatch here.

Everyone can see it? And I think this totally calls for some music. So, I'm going to open up my iTunes library here. And I think this will do quite nicely. So, I'm going to try to do this in one minute or less. We'll see what happens. So, here goes. Oh, I don't want iTunes.

Oh, off to a bad start. Whatever. Oh, ah, okay. The clock's a good thing to have. Okay, well I can have five seconds, guys. Come on. The first thing you want to do is link into the Web Kit framework. It's very important. Otherwise, your app will not work. Kevin, I don't think you're going to be able to do this. I think you're right. Library, frameworks, Web Kit.

Let's just give up, man. Boom, put that in there. Resources. Build it. Now we want to design our interface. We have to design it in 35 seconds. So, we're going to drag a web view here. Well, I think it's actually 30 seconds. There we go. We probably want some buttons. How about like back, forward. We'll label them in 10 seconds remaining. Where's the butt? Actually, I don't think you're going to do this. At this point, I'm convinced. So, let's say take your old string from, forward, back.

and back is going to be go back, forward. This is a really, really ugly web browser, but I promise it works. Take your old string from, oh, okay, well no, no, no, it's done, it's done, it really is. There we go. So my buttons really do work. There you go. So if I can do this in one minute, imagine what you can do in one month of your time. So there you go. Thanks, Chris. Thank you.

Okay, thanks, Kevin. So discuss how you can create a web view. We've shown you how you can load content in web view. Important thing to do when you're loading content in a web view is to display progress or have a progress bar working. This is what many developers ask.

How can I make a progress bar work with a web view? Well, tracking progress in WebView is done using notifications. Once you observe these notifications, you'll get a notification when WebView has started loading. You'll get several notifications as progress has updated while it's loading a web page. And then you'll get a finished notification which tells you that it's done loading.

And within any of these callbacks or at any time, you can call the estimated progress method on WebView which will tell you the progress completed. So here's some code which observes a notification. In this example, we're just observing the progress started notification, but you should probably observe the other notifications as well.

It just doesn't fit. and then this is our callback. So in our callback we call the estimated progress method on the web view and simply we set that as the value on the progress bar and that's all you got to do to get a progress bar working. Now the--something I want to mention is that, you know, you don't have to have a progress bar. You can use the estimated progress method to display any kind of progress with any kind of widget in your application.

Okay, so we got content loaded in our WebView. We're displaying progress. Related to progress is making a URL field work. Now, that may seem like a simple thing. You know, you tell WebView to load a URL, you know what the URL is. You can just tell your URL field to update.

But sometimes it's not that simple. For example, if a user clicks on a link, you need to be notified or told that WebView is now visiting that link. So the question is, how can I make a URL field update as I follow links? Well, this and many things that you'll see today is done using delegates. WebView's behavior is controlled, basically controlled by delegates. They respond to informal protocols, which means that you can pick and choose which delegate methods you want to respond to. And lastly, these things are managed on the WebView. You set and you get them on the WebView.

So before I go into making a URL field work, I need to discuss a tricky topic, which is provisional and committed. This is a concept that is held on the web frame. So I'm going to go into this slowly and give you a metaphor as well. So first of all, a web frame load, when it started, it's considered provisional.

Once data is received, that load is considered committed. So what this means is until data is received, the web frame will be displaying the previous web page. And if that load, the one which was provisional, succeeds, then that becomes the web page which is displayed. So to manage this, to manage that content and that data, the web frame has two data sources actually.

It has the provisional data source for the load that we've started and we're waiting to receive data on. And it has the committed data source, which is either the previous web page or the web page that has just begun loading. So here's a metaphor for you. Let's just say you ordered a new iMac. That iMac is considered provisional because it takes several weeks, days, perhaps months to receive that iMac in the mail.

Meanwhile, You're using your, you gotta keep using your old iMac. You don't want to throw it out while you're waiting for the new iMac to arrive. But once that new iMac does arrive and you have it set up, that becomes your committed iMac. And you can toss the old iMac away.

So, to get back to making a URL field work, this is done using the Web Frame Load Delegate. The Web Frame Load Delegate, which is something that is implemented by you, is informed when a load has started in the Web Frame, when it's become provisional, when that load has redirected, you know, if there are server redirects or what have you, when that load becomes committed, in other words, when the content for that load is now displayed, and when the load has finished or when it's failed.

The Web Framework Delegate is also informed when a page title or page icon is received, because this is part of the loading process. It's informed when the page is scrolled to an anchor. That usually happens after the page is done loading, but you need to know this notification because the URL has actually changed. You get the pound and the anchor after it. And it's also informed when JavaScript is ready. This is when you can start interacting with the JavaScript engine.

So this is a sequence of events here. These are the sequence of calls to the Web Frame Load Delegate. First you'll get the start message, which is the load is-- the provisional load has started. Then you'll get the committed message, which means that load is committed. And then you'll get the done message, which means the frame is done loading. And then lastly, you can get the close message, which indicates that the frame is no longer used whatsoever. So we can break this down a little further.

Before you get the committed message, and after the load is started, you can get several server redirect messages. Even further, you get the page icon and page title messages after it's committed. And then after it's done, you can get the anchor scroll message and the client redirect message.

So here's an implementation of the Web Frame Load Delegate. In this example, I've implemented didStartProvisionLoadForFrame. This is the didStart method. And in this case, what I'm doing is I'm checking that the frame in question is the mainframe, because we only want to update the URL field when it's the mainframe.

So in this case, we want to show the provisional URL, the URL in question, the URL that we've begun loading. That's what we want to display in the URL field. We want to do the same exact thing for did receive server redirect for provisional load for frame. You'll get several of those messages all while that load is still provisional.

Now, if that provisional load fails, you know, if no data is received and there's a failure, you want to go back to showing the committed URL. That's the pre--in other words, the previous web page. Same thing if the load fails after it's become committed. That's what the did fail load with error message is about. You want to show the committed URL.

And if it succeeds, you get the did finish load for frame. You want to go back to showing the committed URL. And if there's a redirect or rather an anchor scroll in the page, you'll want to show the committed URL which will reflect the anchor on the URL.

And this is the implementation of those methods that we were calling. So showProvisionalUrl calls the provisional data source method on the frame. And that'll get us back the provisional URL. and then show committed URL calls the data source method on the frame, which is the data source. This is the committed data source. So let's do a demo of making a URL field work.

I didn't know I loved HTML. 30 seconds. 30 seconds? Yeah, there you go. OK, so I want to open up a demo here. and this demo, go ahead and run it. This is what you'll get with basically our last example except I expanded the text field a little bit more.

I had a minute and 30 seconds instead of one minute. But in this case, you know, when I go to let's say like the QuickTime site or if I go to, you know, www.google.com and I click on news, notice this doesn't change. So this is what we want to fix. How are we going to do it? We're going to do it with these delegates.

So as you saw from Chris' slides, here's the exact same methods that he had in his slides. Show provisional URL and show committed URL. So what we want to do is for--and the delegate methods we have here, they're basically not implemented. The skeletons are there but they're not implemented. And so we want to wire that up.

And so it's really, really simple. And so what we want to do is we want to say if--I'm sorry, if WebView main frame because we're interested in the main frame, that's our point of interest. which is equals frame. and then we want to say self show provisional URL.

Okay. And I'm just going to copy this because I don't want to keep on typing it. And now, we're going to do show provisional URL for this one because we want to get all the URLs. As you navigate to a link, you know, in case things change, you know, from start to finish, you want your address field to get all those. So that's what we're going to do for this case.

So if it was a provisional failure, we want to show what that failure was. So we'll say show committed URL. And we have a couple more down here. When the frame finally did finish, we want the committed URL. And lastly, we want the-- if that actually failed, so. Colons. Oh, colons are good, yeah.

There we go. Run it. Okay. So now if I go to QuickTime, we get that. And I'll also go back and let's go to the Google example. And I can click on news.google.com. And you notice it automatically switched to this. So that's really cool. I mean this is a feature all browsers have. But let's do more.

Let's do something cool. I mean after all, this is Mac OS X. Let's step beyond the, you know, a traditional web browser for a minute. And you know, I see these core image transitions, Chris, and I thought wouldn't it be just really neat so that when I click a link, you know, I get one of these whiz-bang core image effects.

Well, our delegates are a point of interest because that's the right time and the right place. So we know when to start the transition. We know when to prepare for the transition. And so let's just do that right now. So in the case of when we started a provisional load, I happen to have code that is all set up that says self-setup transition.

And I And then down here, when we finish loading, we want to say-- this is-- when the mainframe is done loading, we want to start the transition. So we just want to say self start transition. And there's one more thing I want to do here. I want to say self set document has content yes. So this example will be online so you can see how it works. So now I'll go to the QuickTime site. There you go. You know, so I'll go to, you know, Hickstar.com. There you go. Just like that. That easy. So, thanks.

Thanks, Kevin. Okay, so, so far we've discussed basically how you can get a simple Web Kit app up and running. Now, after you've done this, you're going to want to start customizing Web Kit. And that's when many developers ask, how can I change what happens when a link is clicked? Well, this is done using yet another delegate. This is the Web Policy Delegate. Basically, the Web Policy Delegate is consulted when WebView is about to make navigation changes.

When it is consulted, the Policy Delegate has three possible decisions to make. It can decide to use that navigation, which means continue with that navigation. It can decide to ignore that navigation, which means, you know, let's stop right here. Or it can decide to download that navigation, which would basically cause the URL to download at that point.

Unlike other delegates in Web Kit, this one is asynchronous, so you don't have to decide right away. If you want to display a sheet to ask the user what he wants to do or she, you can decide later because we pass you a listener object which you can retain and respond to at any time.

So it's consulted in three different times. Before the load starts, for example, if the user clicks a link, right after the user clicks the link before the load starts, it'll be consulted. If the load does start, if you choose to process that click, after the server has responded and the MIME type is received, it'll be consulted at that point. And unrelated to the first two, it'll be consulted when your application has been asked to open a new window. A web page can ask you to do that, and at that point you can decide whether you want to or not.

So here's a sequence of events when a user clicks on a link. So in Web Kit, we receive the link, we receive the event for the link being clicked. We request the load from the delegate. In this case, the delegate has decided to, yes, use the request. So then we start the load.

Once the MIME type has been received, we ask the delegate, can we use this content based on the MIME type? And the delegate, in this case, says yes, use it. So at that point, the content is then loaded. So this is the kind of most common sequence of events with the Web Policy Delegate.

So here's an example of how you can intercept clicked links. This is the decide policy for navigation action method. This is the method that gets consulted right after a link is clicked. So in this example, if the action was a link clicked, the delegate here is deciding to ignore the click link, which means stop doing anything. And then this is when you want to start doing your specialized action. This is how you customize a click link. Now if the user clicked on something else, such as a form control or something else, we're deciding to use it, which means, yeah, allow that to process.

And here's the decide policy for MIME type method. Here's an implementation of that. And in this example, we're downloading the content based on its MIME type. So what we're doing is we're checking the web view. Can you show this MIME type? If not, if so, yes, display it. If not, download it to a file.

And lastly, here's the decide policy for new window action. This gets called every time a web page asks you to open a new window. In this example, we've implemented a very simple, if not overly simple, version of pop-up blocking. In this case, we're saying, you know, never allow any windows to open.

which some of you might like. Okay, so let's keep going down this customization route here. Many developers ask, "How can I prevent WebView from loading certain URLs?" This is done with yet another delegate. This is the Web Resource Load Delegate. It's consulted and informed of the load progress of sub-resources. Sub-resources are images, JavaScript files, CSS files, plugin content, etc. The Web Resource Load Delegate can decide which of these resources gets loaded, and it can actually decide which URL these resources are loaded from.

So here's a sequence of events for the Web Resource Load Delegate. You'll get a message, "We'll send request," which is telling you that it's going to send out that request. You'll get the received response message, which tells you that the server has responded and gives you the response of the server. You'll get several received data messages. And then you'll get the done message, which tells you that the resource is downloading.

So here's an example of we'll send request. In this example, we're preventing all non-file URLs to load. So this is an example of an application that only wants to load local content. It doesn't want any sort of remote content. So what we're doing is simply, if the thing is not a file URL, we're returning nil, which means don't send out that request.

Uh, and if it's--if it is a file URL, then we're saying, "Yes, handle that request by returning it." So let's continue to go down this customization route. And what I'm going to go into now is how can I add a context menu item, which is a common question.

This is done using the Web UI delegate. The Web UI delegate has several responsibilities. It manages window-related activities, such as opening windows and setting the sizes of windows. It's responsible for displaying JavaScript status text, if you have a status bar in your application. It's responsible for displaying JavaScript alerts, because JavaScript can ask you to display an alert panel.

It's responsible for managing window Chrome, because a web page can decide which toolbars and such are displayed. It allows you to customize context menus, which is what I'm going to show you. And the Web UI delegate has control over dragging. That is dragging to and from a Web view.

So here's an example of how you add a context menu item using your web UI delegate. This is the context menu items for element method. So what it does is, first it checks, did the user click on a link? Sorry, that's wrong, but I should correct this and say, this message is called every single time the user control clicks or right clicks on a web view.

So the first thing it does is, it checks if the user has control clicked on an image. If so, what we're doing is we're taking the default menu items, these are the menu items that Web Kit would display if we didn't implement this method, and we're simply adding an open image and preview menu item.

And we're adding that to the list of default menu items. And so from now on, whenever the user clicks on an image, they'll get the list of Web Kit menu items plus the open and preview menu item. Now if the user didn't click on an image, they'll just get back the standard Web Kit context menu. So let's do a demo of how to add a cool context menu item. Okay. Thanks, Chris.

So our last demo here, we started with, you know, we have this really cool transition. And I don't know about you guys, but the page scroll is kind of cool, but it's not my favorite transition. I want to be able to choose from different transitions. And so wouldn't it be neat to be able to right click? This would be a cool thing for the context menu to be able to right click and, you know, choose which transition you want. So let's go to the UI delegate that Chris just mentioned. Let's open it up. And as you see, this is what you'll start with.

You'll start with an empty UI, an empty context menu items for element. And this is where you can put whatever you want in here. So in our case, I have a little--just to save some typing, I have a little snippet of code that puts the list of all the core image transitions available.

for the context menu item. There it is. And so we make sure that we're not clicking on an image or we're not clicking on a link and if so, then display this show transitions thing. So I'll build this, run it and let's see, use page transition. There it is. It was really that simple.

So let's do a dissolve. Let's go to--let's go back to the QuickTime thing. There it is. Let's do a--maybe a diagonal swipe. Let's go to Mac OS X. Let's go to, the ripple is my favorite transition. So I'll go here because there's a lot of color. And let's do ripple. And I'll click this.

There it is. And yes, we can even do it in slow motion. So... The shift key. The shift key. There you go. The demo would not be complete without the slow motion thing. So... And it also wouldn't be complete without this copy machine thing. We even searched the Internet to, you know, for at least two minutes to find this copy machine sound. So when I click on theater... Yeah, there you go. So it was really simple. You can, you know, you just take this method, put whatever you want in it and that will show up on your contacts. So there you have it. Thanks, Kevin. Yep.

So let's get back to the UIDeli again. And another thing it can do, which I mentioned before, is customize dragging. Well, the Web UI delegate is consulted when a user drags to and from a WebView. When dragging to a WebView, The Web UI delegate can decide which of these actions can occur, whether loading can occur, an editing-related action can occur, or whether we can leave it up to DHTML to define which action occurs. Now when dragging from a WebView, the Web UI delegate can decide which things can get dragged, whether or not images, links, a selection can get dragged, or we can leave it up to DHTML to define what gets dragged.

So in the Web UI delegates--excuse me-- in the Web UI delegate, the dragging APIs, when they refer to destination, that means dragging to a WebView. When we refer to source, that means dragging from a WebView. And this is all controlled via bit masks. So in this example, we have drag destination action mask for dragging info. This gets called periodically as a user drags something over a web view.

So in this example, we're saying only editing operations can happen in this web view. If you have an editor which uses Web Kit, you probably don't want it to go and load URLs. So you know, when a URL is dragged over the web view. So this is the action that you'll And this is how you can customize dragging from. This is the drag source action mask for point method. This gets called when the user begins to drag something from a web view. In this example we're saying only images, links, and selections can be dragged. Basically we're not going to allow DHTML to define what gets dragged.

So I mentioned editing before. Let's go into how you can actually enable editing. Well, first of all, a WebView can be made editable as of Tiger and I think Panther possibly as well. Yes. And this editing is WYSIWYG. Basically, the user can modify the web page just as it's editing text. And all while this is happening, the underlying web page is getting modified. You can use WebView editing to compose HTML documents from scratch. Or you can use it to modify existing web pages if you want to do that.

and the thing I want to mention today is that WebView uses, excuse me, Mail uses WebView editing in Tiger, so you're probably already using it. So this is how you enable editing. Yep, it's pretty much that easy. All you do is call setEditable. This can be done at any time and after doing so, your web view will become editable.

So related to editing somewhat is preventing selection. This is a common question that developers ask. And this is done using the Web Editing delegate. The important thing to note about the web editing delegate is that it can be called whether the web view is editable or not. Basically, it's called when the user makes selection changes or when the user modifies the document in some way. What I mean by modify, I mean add content, remove content, or change style. Now, when the web editing delegate is consulted, it can decide to prevent these operations from occurring or it can modify how these editing operations are made.

So to disable selection, this is pretty simple as well. You just basically return no in the should change selection DOM range, select the DOM range method. This gets called every time the user is trying to change the selection. You just say no, which means don't allow the selection to ever occur.

So once you've got your web page up and running, you've got it customized, most apps that use Web Kit and WebView allow you to print that WebView. So let's go into that. It's a pretty straightforward thing. Basically, you use the NSPrintOperation method-- excuse me, object in App Kit. The important thing to note about that, though, is that you don't pass the WebView to NSPrintOperation. The WebView has scroll bars, and it clips the content. So if you pass the WebView to NSPrintOperation, you'll just get that little visible snippet.

What you want to do instead is pass the document view. The document view is the view inside the web view which is actually displaying the content and it's completely--and it's maybe larger than the web view. So this is how you do it. You get the document view out of the frame view. You pass that to NSPrintOperation, and then you call runOperation on the operation to print it. It's that simple.

So somewhat related to printing content is saving web content. So how can I save web content to disk? Well, you do that using Web Data Source. Web Data Source, as I mentioned before, is responsible for managing the data of a frame or a web view. It holds the main content data. When I refer to main content data, I'm basically referring to the actual HTML page. But it also holds the sub-resources. These are the things that I mentioned before as well. These are the images, the JavaScript, these are things that the main content has requested.

So there's two ways to save data in Web Kit. You can save just the main content data. This is equivalent to saving the page source. Or you can save the main content data plus all the sub resources. So you basically, you have an all in one solution there. And so how do you do that? How do you save the main content and all the sub resources? Oh, I meant to slide that in. Oops. That's done using Web Archive.

A web archive is a new data type. It's as of Tiger. It holds the main content data plus all the associated sub resources. Basically, it allows you to view web content completely offline, all in one, all together. So it can be used to save all data as one single file. And it's also used as a page board format. In fact, our editing APIs and mail and everything else that uses WebView editing is using web archives for copy and paste.

So here's an example of how you save just the main content. You do this by calling the data method on the data source. Once you've got the data, you can just write it out to the file. And here's how you save everything. This is how you save a web archive. And it's pretty similar. You just call the web archive method on the data source. And then you call the data method on the archive, which returns you the data, the encoded data of that archive. And then you write that out to disk.

So let's do our last demo of how to edit and save a web archive. Thanks, Chris. So we have this application here called Blot I want to use. And I want to use Blot to do two things. I want to first show off the web archive. And second, we're also going to use Blot to edit a web page.

And so I thought to myself, you know, self, what would be a good web page to edit? I'm in the mood to face somebody's blog maybe. And a certain coworker of ours runs a blog. So let me just open up this blog. And this is--here we go. So we're in Blot. This is basically what you would get in mail, an editable web view.

And so I'm going to click right here, the improved web view or Web Kit. I'm going to say like, "You have been owned." And we'll just edit this out here. We don't need that. Let's also go over here and this is Leet speak, by the way. And so I think Dave has a picture of the ACID2 graphic that he fixed. It's down here somewhere. So, ah yes, this will be a good area right here. So we'll just take this, cut this off. And we'll get rid of this stuff. Hopefully I won't break this.

Okay, okay. Yeah, we can leave that. And we'll say this site -- oh, I don't want a link though. This site has been defaced by Super Kevin. And then, oh yeah, we probably want the copyright sign, so we'll take that, put that there. Now we'll save this site, the new -- we'll save it as a web archive.

And what this means is, you know, he's got style sheets here, he's got images. If I just save just the source and try to open up this and I'm not online, I'm not going to get anything. So web archive, think of it as like thin versus, you know, fat. You have everything. So everything you need. So let's call this Dave_owned.

So we'll save that. I really didn't mean to put that in my documents, but that's okay. So I can open this up in Safari, but just to demonstrate, there's no smoke and mirrors here. Let me disable the network on this computer. So we'll, maybe we can just do built-in Ethernet and let's put in off. Apply now. Open up this. And then we'll see that it's working.

So we're and... Oh! It didn't work. Well, it was supposed to work. It worked well enough. It worked well in practice, but I'm not sure why this is. Your blog is resistant to hacking. Okay. That's what it is. So, okay. Well, that's basically the idea is that you get all the resources, they're saved in this file and you have everything you need. So, there you go. Thank you, Kevin.

Okay, so I think we've answered, hopefully I've answered all the questions that I have up here today. So if you have any questions, you can ask them right now during our Q&A. Or you can join the Web Kit SDK dev mailing list. That's at lists.apple.com. So I also want to stress that Web Kit can do much more.

This is just the introduction in Web Kit which allows you to access the actual bits and structure of the web page. You can add JavaScript classes so that you can have JavaScript classes which run native code in your application. You can have Web Kit and Netscape plugins that work in Web Kit and much more. And to learn about that, you'll want to go to the advanced Web Kit session which is just right over here, Presidio, in about 30 minutes.

So here are all the apps again that I showed you before. I think you may have learned enough today to do one of these or something similar. So now you can do it. Forgive me for the cheesy slide but I think it's true. So for more information, you can go to this site. I'm sure you've seen it before, developer.apple.com/wwdc2005.

And here are the sessions again. I already mentioned Advanced Web Kit Development, which is going to start right after this one. And there's also Safari for Web Designers, for those who want to know how to develop web pages for Safari. I think that one's at 2 o'clock. So if you have any questions and you don't want to send it to a mailing list, you'll probably want to email Mark Malone.