Building Advanced iBooks HTML 5 Widgets and iAd Rich Media Ads

Session 611 WWDC 2013

iAd Producer’s visual design approach belies its advanced customization and development capabilities. We’ll go beyond drag-and-drop to discover powerful iAd JS classes, show you how to create dynamic data-driven objects, and demonstrate debugging and performance optimization techniques you can use right away.

In this session, my colleague Mark Malone and I are going to show you how you can take your content to your next level by adding your own customization while maintaining great performance.

So first, let me give you a quick refresher of what iBook Widget and iAd are that are rich in application running on iOS device.

You can do a lot interesting things.

Browse a gallery.

Play a game.

Amazing performance.

You may think this is a native application.

However, if we look under a cover, there's this mini website working in HTML, CSS and JavaScript.

So there isn't any rocket science involved here.

So if you're a web developer, it's good news because you're experience and knowledge is going to be really valuable here.

Even if you're not a web developer, don't worry because iAd Producer make it super easy for everybody.

So here is what we will learn today.

First, we're going to look at content customization and then we'll you look at testing and debugging techniques.

Lastly, we're going to cover performance optimization.

So content customization, how are we going to do that?

Under a cover, iAd Producer create your content using web technology.

And we can use the same exact technology to do customization.

First, I'm going to show you how we can do some custom style using CSS.

In iAd Producer, I have this project in development.

This is image in the center I would like to apply some custom style on.

First, normally, my first approach is to use the auto-inspector.

I can do a lot interesting things there.

I can [inaudible], apply a filter.

Behind the scene, like those auto-inspector are applying CSS property.

So you're already writing custom CSS if you are using this inspector.

It's just that iAd Producer is doing it for you automatically.

But what if you what if you want to use some CSS property not backed by this inspector?

There are two ways to go about it.

The first approach is to import a CSS file.

In iAd Producer, you can import CSS JavaScript file like you could for image and video.

And the CSS JavaScript file will get bundled with your content automatically on export.

In this particular example, I imported a file called custom.css.

Let's take a look.

Inside that file, there's a custom style setting skew transform and it's targeting object with custom-transform as a class name.

If I go back to my project, at this point, the image is not getting the skew transform because it's not having it doesn't have to right custom CSS name applied.

To fix that, we can go to the property inspector.

And there's a CSS class field and I can type in custom-transform.

At this point, if I do export or assimilation, I will find that the skew transform is applied to the image in the center.

So that's one way to apply custom CSS in iAd Producer.

Now, we go and look at another approach.

The second approach is to use a Code Editor.

We can open the Code Editor by clicking on the Code button on the bottom toolbar.

Here is what the Code Editor looks like.

You will see a list of file on beside.

Global.css is a file that you can add you custom CSS style and make it available to your content.

Global.js is the same idea except uses the JavaScript file.

So previously, we applied a class name to our image object and we can use it right here in Global.css.

And here's an example.

Here's an example of pocketing an object by its class name.

We can also target the same object by its unique ID.

Let me show you how that works.

So back to our project.

iAd Producer automatically generate a unique ID for every single object by combining the page name and the object outlet name with a dash.

Let's take a look at this example.

In this project, we have a page called Introduction and the object outlet name is "curiosity".

Therefore, the unique ID for their image is going to be Introduction-curiosity.

And here's an example how I can reference it in Global.css.

Super simple.

So that was CSS customization.

We're going to shift focus and talk about JavaScript.

So at this point, I have a really beautiful page.

But at the same time, it's not that interesting because this is only showing a static image.

I want it to be dynamic and always look fresh to our user.

To do that, I'm going to write some JavaScript code to point the latest satellite image from NASA and display it in a multi-cell object.

To start, I'm going to show you how we can get that data from NASA and on page load.

So in iAd Producer, we can Object and Page by event and we can add customization by implementing JavaScript callback for those events.

And we can see the event by going to the Code menu item.

And for example, we're going to look at the Page Event.

And there we can see a list of event, the Page Flyer.

View Did Load is particularly interesting because it's the event that got fired when the page finished loading.

We going to choose that and we'll see a list of action base available for the event, and we're going to pick Execute JavaScript.

When we choose that option, we will see the Code Editor.

And there we can add the code to connect to the NASA server.

So how do we do the server connection?

If you talk to a web developer, he or she will probably recommend something called XMLHTTPRequest, it works.

But in iAd Producer, we have something nicer for you to work with.

It's called iAd.XHRLoader.

It's a really nice and simple API, and let me show you how that works.

You can create an object of iAd.XHRLoader by passing in a URL.

Imagine the blue box you see here is an object of it.

Every iAd.XHRLoader has an interesting property called delegate.

The delegate letter iAd.XHRLoader know who notify when the loading status change.

And it could be any JavaScript object.

In this diagram, I'm going to assign it to an object represented by the green box here.

And I did with this [inaudible], I can ask the iAd.XHRLoader to start loading and one or two thing would happen.

If the loading is successful, the iAd.XHRLoader is going to fire a loaderDidComplete notification and the green object will receive it and do some interesting manipulation with the return data.

However, if their loading turned out to be unsuccessful, it will get different notification called loaderDidFail and the green object will get that notification and it could choose to do some error handling from there.

So this gives you this diagram gives you our view how iAd.XHRLoader works and here's how it looks in code.

It's supper simple.

It doesn't take that many lines of code.

We are going to look at this in detail in a demo shortly.

Now, let's look at let's move on to the next task.

I'm going to show you how we can use the data from the server and populate it in a multi-cell object.

So back to iAd Producer.

I have replaced a single image with a gallery, a multi-cell object.

And this form, we have a data from NASA.

I'm going to show you how we can plot that into this multi-cell object we see on screen.

So imagine the gallery we saw earlier represented by this purple box you see on screen.

Every multi-cell object have an interesting property called dataSource.

The concept of dataSource is really similar to delegate property you saw earlier.

The dataSource property let the multi-cell object know where its data is coming from.

Imagine the dataSource is represented by the green box you see here.

In order for the green object to supply data to the multi-cell object, you need to implement two methods.

The first method is numberOfCellsInContainer.

It lets the multi-cell object know how many cell there's going to be.

The second method is called cellAtIndexInContainer.

It just returns the cell object at a different index.

So this gives you an overview how to load a dynamic content in a multi-cell object.

And here's how it looks in code.

It's also super simple.

It doesn't take that many lines of code.

To give you a concrete idea how these all work, I'm going to ask Mark to give you a demo.

Great.

[ Applause ]

Thank you very much Chi Wai.

Great. So I've got here on my canvas, we're building this particular example is an iBook widget and I've got on the canvas one of these multi-cell items.

And you can see, if you double-click on it, I can look at each one of the cells in here.

And the sort of the standard behavior for laying this out is to jump in here and maybe I've got three event associated with Mars curiosity and I want go and add a new one, well, I can drop in a new cell here.

I can lay it out to look like the other one or maybe I can have a sort of arbitrary content in there and it's a really nice easy way to go and layout quite a bit of content.

But if you go in and you preview it, you'll see that it will preview it in a way that, except for that cell, actually looks really nice.

There's this nice fluid motion back and forth and it looks a lot like a cover flow experience.

It's all tied up for tap and ready for people to attend, interact with it.

So if I close my preview here and go back to my cells, you'll see that I can double-click in and I can actually delete cells as well, right?

So this is how you can go and edit this if you want to go and add more cells when they're static.

Now, this is a gallery view and if I select the Inspector, you'll see that I got one of the cells selected.

But if I just click out, you'll see that it's a gallery view.

It's got a name here.

And it's a good example of one of our multi-cell objects that has some great properties.

But we actually have quite a few of those multi-cell objects.

We've got this wizzy carousel that will spin and it has multi-cells that you can go and pop content in, and a true cover flow view.

This is an example of a gallery here that I've got on the canvas and then a series of other kinds of examples, and they're all going to have a different visual representation.

But from a sort of dynamic and interactive capability, they're going to have a great experience and that's what you're going to want.

So, this is a rather static implementation and I think the whole point to this particular example is to take this cover flow or this flow view that's up here and convert it to something that's much more dynamic.

We're going to call to the server.

We're going to get these milestones that you see in here, bring them back, and populate this thing based on just calls to web server.

So the reality is I don't need any of these cells.

And if there's any content in here, I certainly don't need any of the content associated with it as well.

And it's going to bring it down to basically a prototype cell, one cell that's going to represent sort of the cookie cutter that I'm going to use for each one of the calls that I make to the network or for each one of the records that I get back from the network.

And so maybe I'll go and just make it real clear that this is generic information I can put in.

This is a date, placeholder and title that goes here.

Get a little more room here and the description goes here.

You sort of get the picture.

This is just sort of a cookie cutter that I'm going to use repeatedly after I call to the server.

So let's get into some of the code.

I want to make a call to my web service and I want to pull back all of those events on the fly.

Maybe there's a new step in the Mars curiosity landing and I want to have that show up within my iBook.

Well I've got some really cool interaction with the social media and I want to pull that content back into my iAd on the fly as well.

Well it's these technologies that will make this work.

So, what am I going to do?

I'm going to click the Code button, bring it up.

Hopefully, it's large enough so that you can see.

I have nothing selected on the page when press the Code button.

And so, what it did was it opened the Code Viewer in the context of the page.

If I had a button selected, it would open the Text Editor and the context of the button and you sort of get the way that it works.

And so, what have you got in here?

Well you got the name of the page here on the left.

It will be unique JS file for each one of those objects that I'm going to go and add some code to it.

Drop down for all of the events associated with this particular object so I can hook into the viewDidLoad, will appear after it's actually appeared, or I can have code fire as the page is going away, going to hide.

So, this is the little function that I'm going to go and override when this function is called.

I'm going to have my code that calls back to the server kickoff and this is what it's going to call.

It's going to call a local web service that I've got running here.

I've got a little JSON feed.

It's a parent is a timeline and it's got a series of milestones for each one of the Mars curiosity landing milestones.

And as, you know, something new happens with the curiosity, I'll go and add a new record to here.

And whenever this particular add or this widget is opened, it's going to call to this feed and pull in the appropriate content there.

So that's what it looks like.

And the way that I'll go and implement this is using one of those great classes that we've got within iAd Producer.

And so, I'll just drag it in here, cheat a little bit.

Drop the code in.

And just to explain what I'm doing here is I'm going to go and get a reference to that gallery view that's sitting on the page.

You saw that it had a name of Timeline Gallery View and I access it through this outlets which is an array of all the items sitting on a page, and I'm going to store that in a variable.

And then the next class that's really cool here is this iAd Archiver class.

What I'm going to do is I'm going to go into that gallery view that's sitting on the page, take that one cell that I created as my prototype cell and basically create a serialized version of that storage.

Sort of freeze dry it and save in this property sitting here on this page.

Pretty straightforward behavior.

The next step is I'm going to go and call a web or set a of web service variable to the path to that JSON file that you saw.

I'm going to hold the results of the call to the server in this variable called Milestones and I'm going to initialize it so I don't get in trouble later.

And then here is the magical XHRLoader class that I'm going to call.

And again, this just is a wrapper for XMLHTTPRequest but it's super simple to go and implement and you don't have to look at ready states and the other properties that typically you're looking at, at that particular level.

So here I'm instantiating my object.

And if there's any confusion about, well, what is this class, you'll notice that I've got documentation that's built right in and I can show the documentation or I can find the text that I had selected.

And if I want to get a little bit more information on this class, I could just type it in and you'll see that it will filter the list oops XHRLoader, there it is, and get the various details.

But I pretty much know what I'm doing for this particular example so I don't need to bring this up.

But it's really nice to have the DOCs right there for you.

All right, so I'm instantiating one of these objects.

I'm setting its delegate property this page, meaning this particular page is going to want to listen for all the callbacks associated with the success or failure of calling my particular website.

And then I'm going to tell that bad boy, that loader object to go and fetch the content, load the content that you're pointing to here, and that's what that load call does there.

So as I said, when I call Load, it's going to call one of two methods, we saw them in the slide.

Let me just go ahead and drag them in from my little cheater over here.

Drop it in.

It's loaderDidFail.

We pass in the loader, so it will be a reference to this instance that I created here.

There'll be an error code as well.

And here I'm just throwing up a silly alert.

You know, you need to do something a little bit more important here, especially if you know that there's no network connection, you might want to load some resources from the local file itself.

Maybe put placeholder images there and some placeholder text in case there isn't an internet connection.

And this is the loaderDidComplete call.

And this is, if I successfully called back to my server, pull back all that JSON text, I'll be passed back that loader and I can inspect it, pull the content out of it and do some interesting things with it.

So rather than having this alert pop up, I'm going to go and drop in some more code in here.

Boom. And what does this do?

Well, here I am getting a reference to that gallery view that's sitting on the page again because I'm going to want to go and poke some data into it.

Saving it as a local variable called Gallery View and then I'm going to go and set that dataSource delegate property that Chi Wai mentioned.

And by setting that property to this, I'm saying this page is interested in all the callbacks associated with how this gallery view is going to get populated.

All right, the next step is to grab this loader that came in.

Ask it for its context, what's going to be that raw text that you saw in the JSON feed.

I'm going to convert it to a JSON object by calling Parse.

And then I'm going to pull out those milestones that you saw in there which is going to go and basically set this local property array to have all of those values in it.

So now I've got an array full of objects for each one of my cells.

And the last step in the entire process here is to go and tell the gallery view that's sitting on the page to reload its data.

And when it does that, it's going to call its dataSource delegate and say, "OK, what you got for me?"

And the way it does it, as you saw on the slides, are these boom these two particular calls, numberOfCellsInContainer and cellAtIndexInContainer.

This first one says, "OK, I'm this multi-cell view.

I'm supposed to show a whole bunch of content.

Well how many of this little view should I display?"

And so, this should return a number and I'm going to try to type it with one hand here which is basically I'm going to go to my milestones variable.

It's an array, so all I care about really here for this is the length.

Perfect. So it's going to say, "OK, yeah.

Gallery view, I got this number of milestones in my JSON feed that came back, so this is how many cells that you need to go and fill out."

This particular function here is cellAtIndexInContainer and it passes in that gallery view there and it also passes in the index, which one of the cells doesn't need to display at the particular time, and what I'm supposed to do is create a view, instantiate a view and just return it a result of this particular function.

And the multi-cell container will go and drop it into one of those cells as a subview.

So it's super easy to go and implement.

So rather than return Null, let's return something interesting here and here is the actual code for that.

Drop it in, there we go.

All right, so let me go through this again.

I'm creating a new view and I'm using that archived one, that freeze dried one that I saved early when these ad first launched.

And I just say restore from Archive and what it does is it instantiates one of those views with the image placeholder, the title and the date and the description field at the bottom.

It gives me a new instance of that.

I'm going to go and grab the particular instance or the particular milestone that was returned from my JSON call and that's passed in as the index here.

I've got this array.

I'm going to pull out the one that I care about and put it in this variable.

And then the rest of this content is going to create an image based on the URL that's being passed in for that particular image and then set the various date, title and description properties on that particular freeze dried version.

And then the last step is, OK, return that back to the multi-cell container so it can plunk it in and drop it in the right spot.

So that's all the code that I need.

Just move that over.

Go back to my view, nothing at my sleeve, no assets in here, no.

If I hit Preview here, it made the call to the local server and there are all the items sitting in it and even some additional ones, just so you know I wasn't cheating.

So all of this content was being pulled on the fly.

And like I said, you could go and add another item on your server the next time this is launched.

It would go and pull down the appropriate content.

So that's a bit of an overview of pulling content on the fly.

I think one other thing, just to mention really quick, is these multi-cell views, if you look at them, you'll see that you can add more and more and more.

And if you're worried about memory consumption when you're building this out, just keep in mind that we take care of doing a lot of efficient memory management with these.

I could, say, insert cell, insert cell and create 50 of these, but from a DOM perspective, what's in memory, we make sure to set display none on those items that aren't visible at any given time.

So that's something that we take care of so that you don't get in trouble in case you pull down 300 cells and want to go and populate.

We're pretty good with the memory management and that's actually a really good best practice for you folks as well.

So that's the demo and I'll pass it back to Chi Wai to take it to the next step.

So that was JavaScript customization.

We're going to shift focus and talk about HTML.

So if you look into in iAd Producer, if you look into your Object Library, there's an awesome object called HTML Under Dynamic Content.

We can add that to canvas.

And double-clicking on the object, it will give us the Code Editor.

And there we can add our custom HTML.

The HTML object is super flexible.

We can literally put any kind of HTML code inside.

One great use case is format of text.

With the HTML object, we can do all kind of interesting things with text.

We can set the font, color, create hyperlinks.

The sky is really the limit here.

Another great use case of the HMTL object is MathML.

Back to your Code Editor, I can define my mathematical equation in MathML.

If I go back to canvas and look at my HTML object, now it becomes a mathematical equation.

It's super beautiful and also really straightforward.

So now if we go back to our project that we've been working on, at this point we have a beautiful gallery.

It's dynamic.

Always look fresh to our user.

But we're going to take it to the next level.

We're going to add a video.

NASA have an interesting site, like you have all kind of video content in it.

However, it doesn't provide direct link to the video file so we cannot really use a video player object built in, in iAd Producer.

Fortunately, like a lot of video sharing site, it does provide an embeddable HTML object.

And we can use it for our I mean we can use it in iAd Producer and let me show you how.

And now if we go back to our canvas, we can add our HTML object.

We can go to Code Editor and paste in the HTML snippet provided by NASA and we save and close that, we get our beautiful video from NASA.

Super simple.

So that was HTML.

And I'll show you a number of ways to do customization using web technologies.

I'm going to change subject and talk about performance.

So performance and user experience go hand in hand.

You cannot possibly provide a great user experience without having great performance.

To help you accomplish the best possible performance on your content, I'm going to talk about some testing and debugging tools and then I'm going to give some tips and tricks for optimization.

First, let's look at an iAd project I have been doing in the weekend.

It's a particle assimilation model.

I figured out the physics and math and I think it's ready to go.

Here's the assimilation I have on a Mac.

The particle is doing exactly what I wanted to and also the frame rate is pretty good.

It's 50, 60 frame per second.

But if I run it on my iOS device, though I'm getting their correct behavior but I'm not getting good frame rate.

I'm only seeing 20 frame per second.

So obviously, I'm not I mean I'm not ready to ship this yet.

To help you identify issue performance issue like this on device, there are two tools you can use for testing and debugging.

The first one is Remote Web Inspector from Safari.

The second one is the Instrument app that come with Xcode.

First, let's talk about the Web Inspector.

The Web Inspector is a debugging tool that comes with Safari.

In iAd Producer, you can attach a Web Inspector along with your content on export.

And let me show you how that works.

First, you want to make sure you have Web Inspector enabled on your iOS simulator and device.

To do that, simply go to Settings.

And if you go to Safari, there's an Advanced option and you can turn on Web Inspector there.

And after that, we can go back to the iAd Producer.

There's a Preview menu item and we want to make sure show Web Inspector when Previewing is enabled.

So what that does is that next time when you do a preview where there is an iOS device or iOS simulator, the Web Inspector will show up along with the content.

And let me give you an example.

So I do a preview and will see my content in the background a Web Inspector out front.

With the Web Inspector, we can do powerful performance analysis.

One thing we could do is to identify CPU hotspot.

To get started, we need to go a tab called Instrument on the Web Inspector.

And we can start the JavaScript Profiler and we can run some interesting report.

We can do a we can run a report like this.

We can see the number of call per function.

It's really easy to identify CPU hotspot by singling out function with a normal amount of calls.

Another thing we can do with the Web Inspector is to monitor network traffic.

On the same view, we can capture a live network report like this.

If we take a closer look, for every single file, we can see the file size, latency and duration.

So it's really easy for us to identify network inefficiency or bottleneck.

For memory related issue, we're going to use a different tool.

Instrument is the application we want to use to identify memory issue on device.

To set it up, first we need to download Xcode.

Xcode is free on the Mac App Store and Instrument will come along with it.

To give Instrument the permission to profile your iOS device, first we need to do some setup on Xcode.

So we want to launch Xcode and go to the Window menu item.

In there, we want choose the Organizer option.

Here's the Organizer window.

If your iOS device is connected to your computer, you will see on the side bar.

To give Instrument the permission, you want to choose the device and then click Use for Development.

At this point, you're all set.

You can quit Xcode and launch Instrument.

And this is a screen you will see when you launch Instrument.

And you want to choose Activity Monitor for iOS.

And you can get a memory usage report like this.

Let's take a closer look.

With this kind of information, you can see how much memory your content is consuming at a given point of time and you can also see a breakdown of the memory footprint.

Super powerful.

To show you Instrument and Web Inspector in action, I'm going to ask Mark to come back and give you another demo.

All right, so here is the actual project that you saw on the slides.

And just to let you know that it's real, I'll hit the Preview button and you can see it's running here on the Mac and it looks great.

And that's, as you would expect, it's running on a Mac.

The reality is we know that if we write applications or if we write websites that have all sorts of complications with them there within them, they might perform differently on the some of the mobile devices.

I mean it doesn't have the same fat pipe necessarily, the same chipset.

And so, the reality is it's all about testing on the device.

And we've got some great tools to go and test on the device.

Now if you download and install the Xcode toolset, you'll get the iOS simulator.

And it does a pretty close job of going and simulating that have something would run on the device.

You can choose Preview and Simulator and export the widget rule, export the ad, we'll launch the appropriate tester application on the platform and you can bring it up.

Let me shrink it down a little bit so you can actually see it.

And there it is running simulated on the device.

Still pretty good of course because it's not running on the actual chipset.

It's not using the same networking, those types of things.

But it's certainly something that's capable and gives you a really good feel for, you know, how far you are, how close you are to doing the real project or completing your project.

So, I'm just going to go and close that, come back up here.

Another option is actually you can go and Preview in Safari.

This application generates great web content.

So, the reality is a lot of this content will actually run in Safari as well.

And so, a lot of folks will just choose Preview in Safari for just doing that quick look of how their ad experience or how their widget experience is coming along.

And then the final one of course is the one that you always want to use, certainly before you ship.

But also as you're working in your design efforts, you want to make sure that you're building something that's really going to perform well on the device.

And of course, we've got built in preview on device there as well and that will not be there if you don't have a device connected.

So if you launch iAd Producer and you want to go demo on device, if it's not actually tethered, then you're not going to see this particular menu.

But once you tether with an iPad or an iPhone, this will become enabled and it'll do the right thing for you.

So previewing on a device is definitely what you want to do and we're all about trying to figure out, "OK, what's going on with this particular examples?"

so I'm going to check Show Web Inspector when Previewing.

And of course, the Web Inspector will show in all of these.

It'll show on Safari, the simulator and on device as well.

And now just to preview on device, I'm going to choose Preview on Device.

It talks to you about what you need to do on your device.

I've got an iPad that's plugged in over here and I'm just going to unlock it.

It's not very interesting to see but it'll walk you through the process of maybe you need to load the Tester app on your device.

It'll go and install that for you and might ask you some permissions in order to get the debugger hooked up to the device.

But I'm just going to press OK here.

It's going to export whatever I've got on the screen, bundle it up, ship it over the cable, and move it over to the device.

And so, there's a little Widget Tester application over here.

And if I'll go and I launch it, you'll see when I do this particular example.

I just launched it.

Now it's running on the device.

It's running here on the desktop.

And you'll see that the Web Inspector launched.

A bunch of detail over information over here, I can hide that.

But you can see the DOM that's generated, the markup that's generated when this was exported.

Lots of HTML goodness.

How everything is categorized here.

All the scripts are put together within the inspector.

And just to level set here.

We've had two incredible sessions on the Web Inspector.

So I'm going to touch this thing fairly light today.

But if you go back and look at the videos we had in Introduction to the Web Inspector as well as an advanced version of that session and they're great if you really want to get in to the nuts and bolts.

But, you know, the idea of this particular demo is to figure out what was going on with the sample and I'm going to focus the bulk of my time in this little Instruments icon that's right up here.

So it looks like a little stopwatch.

So I've got my sample running here on the iPad.

The balls are bouncing around as I would expect.

And the first thing that I want to look at are the network requests.

If you're building in iAd, you know that you're pulling content down from the network.

You're typically using cellular data as well and we know there's all sorts of efficiencies and inefficiencies associated with cellular network when it comes to latency and those types of things.

You could be pulling from a Wi-Fi network or maybe you're just pulling locally.

It's always good to get a feel for sort of what, you know, the what's the network profile associated with your Widget or iAd gesundheit.

So, I've got network requests setting here, so I'm going to hit Start Recording, this little button.

And then I'm going to tell my widget to reload to fetch all the assets.

So I'm going to do a Command-R and then I'll see it update here on my iPad.

And it's loaded.

It's done.

I'm going to press Stop Recording.

And you can see all sorts of very numeric specific information associated with the latency of these items.

But the nicest screen to look at is basically this one without all of the numbers there.

And it gives you a really good feel for the loading aspect of your particular widget or ad.

You'll see a timeline across the top.

And this purple bar is when the load event was called for this particular item.

And that's when it's presented on the screen, and let's assume that all the assets are present.

And that's the thing that you want to get as short as possible.

You want that load to be called as quickly as possible so people aren't waiting around wondering why they're looking at a blank screen.

And so if I look at this, it says, "Oh, it's about" I don't know, 2.71, let's say.

And just to get a feel for the rest of the content here, you'll see the times associated with downloading each one of the assets as well as how long it takes to actually process some of these as well.

And if you look at this last file, this particle.js which is the nuts and bolts of all the animation that you see spinning around in that example was gadded by this particular file here, and this is a bit of a contrived example.

If I look at it, I can see that the thing is called lorem.js which is, you know, suspect to begin with.

And going up, there's this other one called ipsum.css.

So that sounds pretty suspect as well.

I mean it's kind of a silly example but I think the point to make with this is this particular project has a bunch of files better compressed, thrown down to the device.

But there's a good chance that you're still shipping down to the device extraneous files.

Maybe it's part of your development effort, you're using third party libraries or maybe you had other source code trees that you were pulling in and then you decided, "I don't need those."

You're doing your testing on the Mac.

You didn't see any sort of performance issues.

But then when you go and you look at the device, it's taking forever for this particular page to load.

So, always go and take at look at the files that are here and make sure that they're what you actually want because they all impact this bar here to impact the load time and you want to keep it as short as possible as I said.

So clearly, I've got a couple extraneous silly named files here.

Another good example of a best practice here, certainly in a cellular network and in sort of low bandwidth areas is pulling in a series of particles.

Each one of these are the little molecules that you see bouncing around in that demo.

There is a separate file for each one of these.

And one of our best practice is when we're doing mobile development is to take all of those and combine them into a single image so that you're only waiting for that one file, a certain amount of time, but when it comes you get all of the images associated with it.

So another good best practice is to not only remove this extraneous content here but also take all of those images and combine them into one.

And I've got one of those that's sort of pre-baked as well which I can show you.

Let me go ahead and close this and I'll pull up this one.

And so I've gone back, I've optimized my project.

If I go and look at the assets here, it just has the one JS file that's required for this.

This is where all my code logic is.

Here's my particles.

All put together within one image.

And then if I zoom in a little bit closer here, you'll see that iAd Producer allows you to do this image spriting technique with the single image.

So there I've selected one of the beads.

If I go and look at my Inspector, you'll see that it's using the same image for every single one of these and it's just computing an offset or it's using an offset within that particular image.

And you can actually see it if I double-click in it.

All of these other images are here but we're just showing a real slice of it.

So it's making one request, pulling it down and then just showing a little portion of it.

It's great best practice.

All right, so let me go back out to my overview.

And so, what's what am I going to do next?

Well let's do a little bit more sleuthing here.

Let me go back and preview it on the device and see if I have any gains, and I bet I will.

Launches, comes back up.

It's running.

I'm going to hit Start Recording, do a Command-R to relaunch, and Stop Recording 'cause it's completely loaded.

Now, look at the times here.

I mean it brought it down significantly.

And although it was a bit contrived, it's still fairly significant.

Some of these files that you'll use or may use physics libraries, those types of things, in your ads or in your widgets when you're building them can take up a huge amount of real estate in a significant amount of time.

And there is just the one image being pulled back and then we're doing all the right thing about spriting it.

So, I don't remember what the number was before, but this is probably a quarter of the time that it was to load.

So the faster that you can get content on the page, the better, and that's what you want.

You want this bar to be further and further down, this number to be smaller.

All right, another thing that we can take a look at in this particular project is sort of performance.

We can look for hotspots.

Where is this particular item spending the bulk of its time?

Maybe it's getting a little sluggish and, OK, clearly something is going on.

Well, I can hook in to the profiler here and hit Start Profile.

And you'll see we have two different options for profiling.

We can watch the JavaScript as it's actually running.

See all the calls it makes.

We can do that for CSS selectors as well and try to find out what's going on, where is something spending the bulk of its time.

So I want to do a JavaScript profile in this particular example.

Hit Profile.

Now, it's going to run.

The balls are bouncing around here on my device.

If this was a multi-page add or multi-page widget, then you'd want to start doing some navigation just so you got a good, you know, coverage of the app while you're doing your profiling.

But this is just bouncing around.

It's a single page.

I'm going to hit Stop Profiling and then select my profile.

And here is where I'll zoom in a little bit so you can see it.

You'll see this little disclosure item where it'll show me all the function calls and how much time it's spending within each one of them.

Right, so there's 100 percent of the calls are being made in this particular program but I can also see that there is this particle simulation move particle that's got the bulk of the calls actually happening and all the other numbers there are relatively small, and that sort of makes sense.

The bulk of the code being executed right now should be to move the little balls around, so that makes total sense.

And if I drill in a little bit more, you'll see that something that doesn't make sense is actually it looks like the collision detection is being called a lot more than actually the rest of the code that's there.

It's all about calculating how close it is to something.

And this is a real life example that we run into when we were trying to when the team was trying to debug something.

It was doing all sorts of inappropriate calculations, spending way too much time in this particular function.

And the way they found it was they found that it was spending the bulk of its time in this call.

And if you go over and you click on the line there, it'll take you directly to that call and you can review the code and you can say, "I see it.

I was brain-dead.

I put the wrong, you know, item in here and this is why this is misbehaving."

So that's what JavaScript profiling looks like.

And taking a look at network requests.

The next thing that I'll do is I'll show you some items on Instruments.

So Instruments, as Chi Wai said, it comes it gets downloaded along with the Xcode toolset.

So I've got Xcode on this device.

But what's a little bit frustrating if you're not used to it is the fact that if you go looking for Instruments I'll go into my launch pad here and just type INS, it's not found.

OK, I've downloaded Xcode.

Where is this silly tool?

Well it's actually embedded within the Xcode bundle.

So the best way to find it, certainly the first time, is to go and use your [inaudible] spotlight, type in, launch it, and now you've got Instruments launched.

And then you can do the trick of saving it in the DOC and then you can go and access it multiple times whenever you want to go and get access to it.

So this is Instruments launched.

And what we want to do is take a look at the memory profile associated with this particular demonstration.

And so, what I'm going to use is this Activity Monitor instrument that's here.

Always make sure that you're targeting the OS here 'cause I'm going to go and do the profiling of the memory as it's actually on the device.

Not a lot of need to profile it while it's running on the MAC or in the simulator.

So I'm going to choose the Activity Monitor.

Place it there.

Now I've got in on the left.

And now all I need to do is say, "OK, Activity Monitor, I want you to monitor a process that's running currently on this type of device."

So under the process' dropdown, you'll see there's my iPad connected, here's this machine as well.

I don't care about that.

With that iPad selected, I'm going to go and choose a target.

So this is the process that's on this particular device that I want to connect to.

So I can go and I can look at the memory profile associated with my iAd or I can look at the memory profile associated with my iBooks widget, the tool will perform the same.

So I'm going to choose iBook's widget tester because Chi Wai's example is a widget.

Now I connect to that process and what I want to do is come into my pad and press Record.

It will go and launch the widget tester.

And if you can see, it's got some pretty sweet graphs here, right.

And you can see some traces about how much of the memory is consumed and that's fairly interesting.

But what's really interesting is testing the memory profile associated with my particular widget or ad.

So now I'm going to go and launch that and you should see a spike in memory here.

And that's expected, right?

There's a lot objects being allocated.

And if I look at this chart, it looks pretty good.

It looks fairly flat.

And that's actually what I want.

Once things settle down a little bit, I should see memory allocated.

It sort of gets free and then it finds this sort of flat line of coexistence on the platform.

And that's what you want to see, maybe little bump here and then.

But if you see some sort of incline, that means you're leaking memory associated with your particular project.

Maybe things aren't getting freed or you're just building up arrays until they explode.

So this data down here, it's a lot of data and all we really care about is our iBook widget tester that we're taking a look at.

So if I spell it, i-B-o-o you'll see here, I've zeroed down.

And now I've got actually the raw data.

Instead of just looking at a pretty chart up here, you'll see that I can look at the real memory as well as the virtual memory.

And you just want to make sure that these numbers, even though they'll bounce around a little bit, they always hover within a particular range.

And that range will vary based on the content that you've got on a page.

So, this is a great best practice especially if you're using WebGL with a lot of vertices.

Depending on what you're doing, you may have constraints in memory if you're building an ad.

There might be a cap 'cause you're running in a shared memory space with the application that's displaying your ad.

You might have other constraints.

Again, this tool is a great way to look at the visual aspects of how your memory is being consumed as well as the raw data associated with it.

So that's it for Instruments and the Web Inspector.

Let me turn it back over to Chi Wai.

[ Applause ]

Thank you Mark.

With Instruments and Web Inspector, we know that we're not flying in the dark when we run into performance issue.

Now, let me give you a summary.

Very first thing, always test on device.

Second item, always test on device.

As I showed you earlier, what you see on a MAC simulation could be with [inaudible] thing.

So, I'm going to say it one more time.

Test on device.

So, with Web Inspector it's really easy to identify CPU hotspot and we can also look at the network traffic life.

And we can help by doing image spriting and also removing unused asset.

With Instrument, we can memory the memory footprint on device and we can save some memory by removing hidden element by applying display:none.

So what we have learned today.

We learned that iBook widget and iAd are just mini website within an HTML, CSS and JavaScript.

And we learned that we can do customization with the same exact technology.

I showed you how we can put data from a remote server and show the data in a multi-cell object.

And lastly, we looked at Web Inspector and Instruments.

You can do some powerful performance analysis with these tools.

With what you learned, go download iAd Producer.

It's free.

It's fun. It's super easy to create amazing content with great performance.

For more information, contact Mark Malone.

He's our iAd Technology Evangelist, also our awesome demo person of the day.

There is documentation online and developer forum in case you need help.

Here are some related sessions.

I mentioned earlier, there is an Introduction to iAd Producer happened this morning.

The video should be available shortly online.

There will be iAd Integration session happening tomorrow.

There're two Web Inspector sessions that happened yesterday.

The videos should be available online by now.

And if you are interested and want to learn more about Instrument, there's a session tomorrow you should definitely check it out.

Thank you for attending this session.

I will see you around.

[ Applause ]

Apple, Inc. AAPL
1 Infinite Loop Cupertino CA 95014 US