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-107
$eventId
ID of event: wwdc2005
$eventContentId
ID of session without event part: 107
$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 107

Uniform Type Identifiers and Launch Services

Application Technologies • 1:02:17

Key features of Tiger such as Spotlight, Automator, and Launch Services take advantage of the Uniform Type Identifier (UTI) technology. This session discusses how to leverage UTIs in your code in order to achieve seamless integration with Mac OS X. We'll give an update on new the Launch Services APIs available in Tiger and also cover some of the "nuts and bolts" details of interacting with the Launch Services database.

Speaker: Christopher Linn

Unlisted on Apple Developer site

Transcript

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

My name is Christopher Linn and I work in the Core Services group at Apple Software Engineering and especially on Uniform Type Identifiers and I also work on Launch Services. This session is actually almost all Uniform Type Identifiers with a little bit about Launch Services in it. Since that's what I know, that's what I'm going to talk about in my session.

Let me just give a quick overview of what we are going to do during the next hour. In the form of several questions that I hope to answer. I presume that, I am making a presumption that I can answer the question, why are you here? And I will give you several reasons and that may answer some other why are you here questions for you that you may have been aware of. And we'll go through, kind of the design background of uniform type identifiers. And then go into some more practicalities of how they are used on Tiger and how you can use them to make your applications better.

So, why are you here? And I don't mean that in the life-affirming answer to everything question, but why are you in this room right now? One reason is that you want to know about uniform type identifiers because of Spotlight. If you've been to any of the Spotlight sessions earlier today, you found out that uniform type identifiers end up being used heavily to categorize importers and search results in the Spotlight framework. So for example, if you look at the--

[Transcript missing]

compatible actions being hooked up in the workflow.

Some other areas in TIGR are core image, several places in the Carbon API, such as Pasteboard, Translation, Navigation, as well as Launch Services itself using uniform type identifiers for working with file system objects and modeling things like document binding preferences. So these are all areas that uniform type identifiers are now used in 10.4. They were introduced in 10.3, but used very sparingly just in one specific area, the Carbon Pasteboard. But it's much more of a foundation in 10.4, and I hope that you'll see that it's a very useful thing to understand and a very powerful concept.

Let's just look back at the things I've mentioned and see how they're layered. Uniform Type Identifiers are very closely related to the Launch Services database. It's actually implemented as part of Launch Services. And then the higher levels of Launch Services itself is a client to the UTI API and database. And then some of the other things we've talked about: Spotlight, pieces of Carbon, the Core Image Framework sit above that and make use of Launch Services and Uniform Type Identifiers. And then various applications including perhaps your application are clients of this technology.

So let me give a design overview and then later on, as I said, we'll get into some more coding examples and practicalities of using the API. What do I mean by type identification? Which is the term I'm going to be talking about quite a bit. It's a very general term and that makes it a little bit hard to get a handle on. So I brought up Dashboard in the Thesaurus to get some ideas. And it says some words in the Thesaurus like Variety, Class, Category. Category I think is probably the best synonym in this case. It's a way of categorizing the objects that we work with on our computers.

So what kinds of things are we talking about? What kinds of objects do we want to categorize and identify? Basically, it's things that the user is working with, and therefore, they arrive at the doorstep of your application, and you've got to be able to know what they are.

So of course, it includes file system objects. But I didn't call it file system type identification. I didn't call it data type identification. It's just type identification, because files, folders, volumes, that's one of the things we can deal with using this technology. There's also Pasteboard. Not only does the Carbon Pasteboard API, the modern one, the new one, introduced on 10.3, not only is it based on UTIs, but actually, the internal Pasteboard that goes between Carbon and Cocoa apps is based on UTIs. And we use this technology to be able to map between the namespaces of those two different Pasteboards.

as well as the old Carbon Scrap API. We can also identify the types of things that aren't necessarily really living in the file system such as contacts, people, information from address book, email messages, calendar events. All these things are searchable by Spotlight and can be identified by UniForm Type Identifiers.

And finally, we can work with data arriving over the Internet that, for instance, might be identified by a MIME type, and we want to be able to link that back to data of the same type, save it to the file system, and have the correct extension. For instance, UTIs can help with that.

So I wanted to look at the grand arc of history of type identification. And in the beginning, there was the file extension. How he hates it. But there's really not a whole lot we can do to get rid of file extensions because they're everywhere and they're used on other platforms a lot and we've embraced them on Mac OS X because we have to. We have to interoperate with other platforms.

And of course, the problem with file name extensions is, well, they're in the name. We all hate that. They're generally not very helpful, not very explanatory. So even though they're in the name, you've got to be sort of an expert to know what they mean. And they're just a free for all. There's lots of -- there can be collisions and redundancy.

So along came the Mac and Apple introduced the OS type four character codes. And this at least isn't in the name, but there still can be collisions and they're not -- text is a great one because it's easy to understand, but most actual OS types aren't. They're not very verbose, not very explanatory. If you look at the code, you don't -- as a developer, you really don't know anything about it just looking at it.

And then in the 90s along came mime types. And this was interesting because you start to see, first of all, it's a lot more verbose. It's kind of plain English. You can understand a lot about what that means. And it starts to kind of get at the idea of types are kind of, they kind of have an organization and relationships that-- there's text types, and there's audio types, and video types. And this was a good idea. And the hierarchy, however, is very fixed and encoded as part of the name.

So it can never change or evolve. And pretty much what we ended up with mime types is the application type ends up being kind of a dumping ground. And even worse than that, even though there's a bureaucracy for registering mime types to avoid collisions, in fact, there's a zillion mime types out there that begin with x-dash as the experimental namespace. And that just kind of sticks for all time.

So mime types aren't really the answer, the ultimate answer, to type identification because of these problems. And there's also, as I have discovered working with this over the past couple of years, there's a lot of redundancy in mime types. There's the x-dash. There's the non-x-dash version of a given mime type. And they're all sort of synonyms for the same actual data type.

So we needed something to not only to be better than this but to also interoperate with all of this type identification that was just sort of a big mess. And so we came up with Uniform Type Identifiers. These are the key points about what a Uniform Type Identifier is.

First of all, it's just a string and it has a naming convention. We reuse, again, as we do in other places on the system, the reverse DNS naming scheme. And we do this solely to--well, not solely, but primarily to prevent collisions. Now there's like a really, really good chance that if you declare your own UTI, Uniform Type Identifier, it's not gonna collide with somebody else's name because it has your company's name as a prefix. It also is handy because it says who the owner of the type is. You know, looking at a UTI that--oh, maybe you can contact somebody at a particular company or at Apple to find out about a particular UTI.

This allows us to make the system freely extensible by third parties, by everyone, all of you, without any central registration bureaucracy because of the collision avoidance. There's also sort of a gestalt of using verbose names because when you have a nice long string like that, it's really easy for a developer to look at that and understand what it is. It's very descriptive.

[Transcript missing]

UTIs are an improvement over other type identification systems, we think. But beyond being a string, we've added a whole collection of information associated with types that I call type representation. There's the idea of a type identifier, but then there's also an abstract notion of a type. What is a type? And I think of it as the association between a unique identifier, the UTI, and a bunch of properties that describe the type.

So in the framework, given a UTI, you can ask for various attributes, such as the description, which is a localized string. So it's a human-readable description. You can associate an iconic image, an icon, with a particular type. And then you can also have any number of other mappings, or tags as we call them, to other spaces, such as extensions, MIME types, and OS types. And this is really powerful because it allows you to abstract your app away from having to know that there's two different MIME types for MP3, and there's two different OS types, and you don't know which one to use.

And you don't want to have to keep track of mapping all of those back to a canonical type identifier. And by associating all this information right in the API, it allows you to work at a higher level in your application by just thinking about, OK, I'm working with MP3s, and the system is going to help me with all of the metadata that is associated with the MP3 type.

But we didn't stop there. We also wanted to formalize this notion of a hierarchy. And there's a bunch of ways in which a hierarchy is pretty useful. But let me just give an example. The terminology we use is conformance. We say that one type conforms to a supertype. So for instance, mp3 conforms to audio.

By the way, I didn't mention earlier the public prefix is a special prefix reserved by Apple for essentially types that aren't owned by Apple. They're more in the public domain, if you will. And so that's why you're seeing all these strings that begin with public. And that's just to unicify them.

Anyway, MP3 conforms to generic audio. It's a kind of audio which in turn conforms to audio-visual content. And as you'll see later, audio-visual content includes other things like movies. And then it gets even more generic that there's something called public.content which covers all sort of document content, if you will. So this is just an introduction to conformance and we'll now go into more of the actual details of how a hierarchy, how our hierarchy is organized. And actually I'm going to go back and say one more word about conformance.

Conformance, it's a little bit hard to grasp the significance of it, but it ends up being the most important part of this technology because it allows you to essentially with other type systems you do string compares. You're basically testing for equality. Is this type something I understand? So you compare a string that comes in from the pasteboard, say, to a type that you, to a string constant that you know of. And you do a whole bunch of compares and you find out what type of data you have.

Well, By replacing a string compare with a conformance test, it allows you to not have to know about every type of image out there in the world. If you can, for instance, just say, is this thing an image? And if it is, then I'm going to give it to QuickTime and see if QuickTime can deal with it.

And that way, you don't have to know about everybody's image type in the universe. You don't have to check for all those types. You do a very fast conformance test of a high-level type, and You can work with a lot more data that way, a lot more kinds of data.

So what we've done with UTIs is actually allow just a multiple inheritance, a multiple inheritance graph of conformance. So the reason we did this is that we came up with two ways of looking at types. There's a physical hierarchy, which looks at a low level technical view of something is implemented, say on disk, as either a file or perhaps a package or a folder. And those are physical representations on disk.

And then there's a functional hierarchy, which is the user's view of a type. And that is especially driven by Spotlight and allows us to categorize things in ways that users view an object, a document, or a piece of data. And for instance, the users don't care whether it's implemented as a package or a flat file, but they care about what its function is in their head.

And every type on the system has a place in both the physical and functional hierarchies. So let's just look at the very top of the hierarchy. We have some good documentation updated for Tiger on the WWDC website that goes into the whole hierarchy. But here just to give you a flavor of kind of how it's organized at the top. The physical hierarchy starts with the root of public.item.

And we needed a root there because mainly because of Spotlight has some basic attributes associated with everything that it can index which includes two things. Data which is what we call flat files or data in memory. Every file is a data stream so it conforms to files are all public.data. Or directories which only exist on disk not in memory.

Directories can be further divided into packages, or plain folders and a volume is just a flavor of a plain folder. Something that the user can browse into. And then from this, these are pretty much abstract types. Well, they're not completely abstract, but often you'll have all the concrete types are descend from this tree. So all image formats, movie formats, all conform to public.data, for example.

Now, there's a functional hierarchy that divides the world differently. And probably the most common type-- there's not a single root in the functional hierarchy, but one of the most common ones is content. And this is all documents. So documents are divided into basic text, which may include marked up text like HTML, or images. And there's another one, audio-visual content, which includes movies and audio.

And so again, every type either plugs into this part of the functional hierarchy, or if it's not a document, it might go into one of the other categories we have, which is messages for email or chat logs, calendar events. So all the specific iCal data types conform to calendar event.

Contacts for address book entries and Archives for disk images and tar archives, things like that. And there's a few more, but this is just to give you an idea of how it's organized. And again, this is spelled out in more detail in the documentation. So, um, sorry, I'm going to go back again.

The, uh, When we get to the demo phase, you'll see how these functional types are used to allow you to The last part that I wanted to touch on very quickly is something that you run into fairly quickly when you start working with this and that's something called Dynamic Type Identifiers.

And this is to solve a particular problem that when we look at any, say, file on disk, we don't necessarily -- we can't necessarily map every extension to a formal Type Identifier. There's lots of things that aren't declared yet or legacy things that will never actually be formalized as UTIs.

And so we generate this funny string when Launch Services, for instance, is asked to say, "What's the UTI for this file?" It will -- instead of giving you no answer, it gives you an answer that preserves what we do know about this object. And what we know about it is that it has an extension, foo. And it's a file, so it conforms to public.data.

So what you get back is this funny string and it's an opaque encoding of some information. But you can pass it around like any other UTI and you can ask questions about it like, "Okay, UTI, what's your extension?" You get back foo. You say, "Do you conform to public.data?" You get back yes. And so it's sort of a way to degrade gracefully when we don't have complete type information. So don't be alarmed when you see something like that show up in your debugger.

All right, so now it's time to move on to the practice portion of the talk where I get into more. details about the API and how to use it. So there's sort of two key usage patterns here that I think are worth thinking about looking at. The first one is just using the existing types that we have built in to Mac OS X Tiger.

And you can use all the existing types we have to adopt new Carbon APIs, work with the file system-- file system objects at a higher level than just raw metadata. Or if you want to run a Spotlight query with known types, you can do that. And then the next level up that we'll talk about a little bit later is declaring new types, extending the type system in your application or your plug-in so that you can more tightly integrate with key features like Spotlight and Automator.

All right, so let's talk more about working with existing types. On Tiger, we have over 150 type declarations built in.

[Transcript missing]

The core API is-- the whole API is actually very simple. The core of it is, as I mentioned, being able to do a conformance test. So UT type conforms to takes two strings and it returns a Boolean. And this is what Spotlight uses and what Navigation Services uses, the Pasteboard, in order to learn about a type that it is working with.

You can also convert to other type tag namespaces as we call them. So, anything--any other kind of identifier is called a tag. It has a MIME or an--MIME type or an extension or an OS type. You can go back and forth mapping between UTIs and those other spaces. And then you can, of course, fetch attributes like the description or indirectly the icon through icon services. These functions are in uttype.h.

Now, going up to the next layer to Launch Services, the Launch Services API, This is the layer at which you can learn about or ask for the UTI of file system objects. UTIs are not stored in the file system. We don't have any file system currently that actually stores a UTI directly next to a file as metadata.

But Launch Services wraps all of the logic around looking at an object, seeing if it's a directory or a file, and what kind of metadata. It looks at all the available metadata, the extension, what have you, and it can give you back what we call a content type.

So Launch Services has this new thing called named attributes where you can ask for things by name such as the content type and things that you're already probably familiar with with Launch Services such as the display name and the kind string. But for purposes of this talk, the content type is the most interesting because this gives you kind of the unifying view of the types of objects that are on the file system.

This is what Spotlight uses. Whenever it's going to import a file or a folder or whatever, it turns to Launch Services and says, "What's the content type of this object?" And Launch Services gives it back a string, and then it uses that string to find an importer for that. And that way Spotlight doesn't have to know that there are, you know, four different ways of identifying JPEG images on disk. It just gets back a single string, public.jpeg, and it finds an importer. for that type.

Another new feature in Launch Services in Tiger is using UTIs to simplify your document claims. So currently in your InfoP list, when you open a bunch of document types, you need to list out a whole bunch of metadata, right? Back to the JPEG example, you need to list all the extensions for JPEG in your document claim, and you need to list, I think it's just one OS type.

And everyone has to go through the same exercise of identifying the redundant types of metadata that identify a particular type in order to claim that for your application or to be able to open that kind of document. And by using a new keyword in your document types section of your plist, the ls_item_content types, and then it takes an array of UTIs, you can make both-- well, you can simplify your Info.plist quite a bit. So if you open JPEGs, you just say public.jpeg. You've got one entry, and launch services takes care of all the details of knowing that, oh, this means that you can handle extension JPG and JPEG, as well as any other metadata that identifies a JPEG.

It also leverages conformance, because when you list a UTI in your info.p list like this, you're saying, you open anything that conforms to this UTI. And it's a much better way of doing what we used to achieve with wildcards. Basically, you can -- with wildcards, you can say either you open a specific type that you identify specific metadata, or you say, I open everything. And that allows a user to drop anything on your application icon. And even if you can't open it, you're still going to get launched and given the object. And at that point, you have to figure out what to do with it.

If you do something high level, like in this example, claim public.data, then what happens is that -- what that means, what public.data means is files in this context. Because files are all data streams. And you're saying, well, what's the point of this? And you're saying, I want to be able to drop any kind of file on my icon, but not a folder and not a volume, not an alias, for example.

It allows the user experience to be much better because then in the finder, the feedback for dragging is much more precise about what kinds of things you want to be able to open in your app. And now is a good time to do a demo to show some of these concepts that I've been talking about. So if we can switch over.

I was looking--can we switch to demo?

[Transcript missing]

The code was available for and which did some interesting things like just maybe open some different kinds of documents, something more than just text. I also wanted a Carbon app because right now Carbon has a little bit tighter integration with this stuff than Cocoa does. Cocoa, you can of course use the C APIs for Uniform Type Identifiers, but it's not currently integrated into the Cocoa Objective C APIs.

But I thought about simple text, Carbon app, and I remembered vaguely that it sometimes displayed more than just text. And so I thought I would try dropping an image onto simple text and see what it did. And this document is too large. And I thought, oh, it doesn't open images. I guess I was wrong.

But I went and looked at source code and I thought, great, now I have to debug simple text. And it must have some sort of lame size check because it thinks it's a text file. And as I debugged it, I realized the only problem is that it doesn't know that this is an image because simple text was never updated to know anything about extensions.

And so in this case, this is a file that has an extension, but it doesn't have any file type code associated with it. So simple text actually has no idea that it's a JPEG file. And the same thing happened when I dropped a movie on. This is too large.

So what can we do about this? And, you know, we can go and add a whole bunch of extensions to the list of what JPEGs are. And we can add a JPEG pin open. But can we make it any simpler and not have to know so much about file metadata? This is a little bit large. I know it's very readable. It would be even readable if it was larger, but I won't have enough room. Is that somewhat readable? No. Yeah, the front row. Okay. All right. My bad. We'll just, we'll go with your preference.

[Transcript missing]

somewhat cryptically determined window type OR open. I love these OR functions. Depending on what I tell you to do, do it. And this is responsible for figuring out what things are. And it's all OS type-based. And it tries to figure out-- it builds up lists of image types and movie types and text types.

And it turns out when you go look at these functions, they're just hard-coded lists of OS types. And they're not even very complete compared to what QuickTime can do as far as importing images movies. So these aren't very useful, and especially if there's no OS type on the file that we're trying to open. So what I did was I put my code over here.

And I'm just going to make a few changes here. I want to work with the UTI. What happens in this function is an FSRef is passed in to the function and we have to figure out what it is. So we want to ask for its content type from Launch Services. So I have a CFString variable there and I'm going to... "Place this if clause with something that basically asks for the content type.

Now see, you have to deal with the wrapping now because you wanted the big font." There it is. We LS copy item attribute, we get back a CFString in the content type, and then we can do conformance tests on that. So I'm going to do first, I'm going to say, does it conform to image, UT type image? And if it is an image, then I'm going to continue doing this little thing that simple text does, where it asks QuickTime if there is an importer available for this kind of image.

And the only problem with trying to do that is that QuickTime is looking for, in this case, the type is the OS type or the file type code of the file. And we know that in some cases, in this case, we don't have one. And we need one. So we can get one from the Uniform Type Identifier API. Because we have the content type now. And let's go paste this in. I put it in the wrong place.

Okay. So, we're going to get back from this function, we're going to get back the OS type or the file code, the type code as a CFString. And then we use a utility function to actually turn it into an actual OS type data type and that happens right here. And we release the CFString.

And then we can, "We can pass that type that we get back into QuickTime and even though the file doesn't have a file type, we can get back an importer that QuickTime can provide. And if we get one of those back, then we know that in simple text terms, it's a picked window."

[Transcript missing]

So what I've added is one more conformance test.

I just say, "Okay, does the content type of the file conform to movie?" And if so, then let's call it a movie file or a movie window. And that means later on, Simple Text will try to create a movie controller for that. So I'm going to go ahead and build that.

and I are going to go ahead and start the session. Let's see what happens. Didn't work. Is that the right app? It is the right app, but... It's still running. Yeah, that's exactly the problem. I told myself a million times, "Quit the app." Who said that? Who said it's still running? Thank you. But you were wrong. Yeah, well it's running again because I just... Alright, now I'm getting too much advice.

[Transcript missing]

Now it's rebuilding everything because I changed where it builds to. Get rid of that evil window. Still running.

[Transcript missing]

What? Yeah, that's not a bad idea.

[Transcript missing]

Okay. Now, this should just work. No, I dragged it to the wrong place. Yeah, yeah, yeah, yeah, yeah, yeah. And now I can do the world premiere of my 10-year-old daughter's clay animation.

I only have one running. I don't want this one anymore. And next problem. I went and looked at the open panel and if we go into our...

[Transcript missing]

All we need to do is look for the open panel. Open File Dialog. This is what puts up the Open Panel.

And it's using the old style Nav Services filtering. So I'm going to get rid of the thing that allocates that special handle that has all the OS types in it. And we're not going to pass it in anymore to the Nav Create Get File Dialog. And we're certainly not going to dispose of the handle when we're done because there is none.

And instead we're going to just add this little bit. If we created the dialogue correctly, Then the next thing we're going to do is create an array of UTIs that we want NAV to filter by. In this case, text, image, and movie. And we're saying anything that conforms to one of these base types, I want you to enable in the File Open Panel. You probably thought I wasn't going to remember to quit. Let's build.

"We've built. Let's run it. Open. and all of my documents are now enabled. Now I've done all this. I've made SimpleText extension aware without having to use any extensions. Isn't that lovely? If you hate extensions, then you don't have to use them to interoperate with them. 10.4. This is supported on 10.4. The last thing I was going to do was make a quick change to the Info P List because there was this other annoying problem. Let's see. I got to get it back.

There we go. I need it in the doc. There was this other annoying problem that now we can-- if you noticed before, even though I couldn't open this file before, it would still highlight. And in fact, you can drag pretty much anything down to simple text, and it will try to open it. You can drop a folder on it.

And it says, it may be in use by someone else. Now we can fix that error message, but what we really want to do is just have proper feedback and not highlight the application icon at all. You can even drop a volume on there. And the reason is because the Info.plist, if you look at all of these document types, it's got all the specific metadata that it wants to claim. Down at the bottom, though, it says, let's claim four stars, which is the OS type for wildcard claims. And that means just drop anything on me.

And what we really want to do is be more specific about what simple text can actually do. So we use this. We use this new key, LS item content types, which is how to claim UTIs. And we replace the wildcard with these same three UTIs, text, image, and movie. And-- Build.

Build very quickly because it was just an IP list change. And let's hide this. Now we can still drag images down, movies, but we shouldn't be able to drag say volumes anymore. No highlighting on the icon. Same with folders. And text opens just fine still. All right, so that was just three simple changes to simple text that enabled it to actually do what it can do and not be blocked by some poor management of metadata. Okay, we can go back to slides.

So now I want to turn to more advanced uses of UTIs and that involves extending the system by declaring your own types. And it's a cooperative system. Anyone can add to it and it's a shared database of information of type knowledge, if you will, that is available to all applications. It's shared across all the processes that are running in the current user's context.

And since it needs to be known even when your app isn't running, we actually declare types in your Info.plist. And this allows, for instance, the finder to know about your types before your app is even run. Types can be declared currently in three kinds of bundles: Applications, Spotlight Importers, and Automator Action Bundles. We limit it to these three because these are the ones that actually need it and there's some scaling issues that we haven't dealt with yet. So these are the places where you can declare a new type.

There's two ways to declare a type. As I said, it happens in your Info.plist, so it's just a little bit of XML. But there's two styles: there's exported types and imported types. And exported types is how you declare something that you own, a format or type that you control. However, you might depend on some type that's not built into the system, it's from some third party, and you know how the third party declares it in their product, but you can't count on that product being installed on the system.

So you just add it to your Info.plist and you call it "imported." And that way we know it's kind of secondary. We know that we'll use this imported declaration if there isn't an equivalent one for the same UTI that's exported. And that way your product continues to work. But if the UTI is not exported, it's not going to be used. So the other product is installed, they are the de facto, the master copy of the declaration, if you will. And so it's just two slightly different ways to declare a type.

And also by doing it in the InfoP-List, it allows us to leverage the bundle format to do resource loading such as the description which can be a localized string. It's loaded from bundle resources as well as the icon. So this is just an example type declaration. It looks something like a document type declaration.

You've got the UT exported type declarations key up at the top, and then what follows is an array of types, each its own little dictionary, and some of the most important keys in there are the type identifier, which is the actual UTI, the single UTI or an array of UTIs that it conforms to. That's really important. I encourage you to read through the documentation about conformance and familiarize yourself with the abstract hierarchy so that you can get your conformance right to work really well with Spotlight.

There's the description, which is the human readable string. And then there's yet another dictionary which lists out all of the, what we call, tags, which are the extensions and the MIME types that you-- and OS types and NS pasteboard string types that you want to map to this UTI.

And once you put that in your info.p list, then all you have to do is get it registered with Launch Services and it becomes active on the system. Registering with Launch Services is, especially in the past but still a little bit, it's a little bit of a black art, but you need to be registered on the system for your bundle identifier to be findable, in order for your document bindings to work and your icons to show up, and now for your type declarations to also be active on the system. For applications, it pretty much happens automatically, either by installing with the Apple installer, or if you're just browsing around the Finder or you launch an application, we notice it and we register your info.p list. For Spotlight importers and Automator plug-ins, it's a little more complicated.

You can drag them into the appropriate library folder, like either the Spotlight folder. Or the Automator folder inside either /library or the library in the user's home directory. And at that point, they'll get noticed by Spotlight right away, because it's watching those folders. It will also get noticed by Automator when the app runs next. If you have your own installer, there is lsregister functions that were available first in 10.3 to allow you to register something right away after you've installed it in the right place.

One note about debugging. I get this question a lot, that you change your InfoP list and it doesn't have any effect. Because you're just trying to do something quick. And I do it all the time myself. You want to change an app in place. You want to change its InfoP list and not have to rebuild. The problem is we don't know it's changed. We don't watch every InfoP list on the disk to know that it's changed.

But if you edit an InfoP list and then touch the mod date of the .app bundle or the importer plug-in, then we notice the next time, say, we go to launch that app, that it's changed. And we will then go inside and read the InfoP list again and re-register it.

So with apps, generally the best practice is touch the mod date, launch the app, and you should be good to go. Now you notice I didn't have to do any of that with Xcode when I was rebuilding SimpleText, as long as I could find where the hell SimpleText was. And that was because Xcode will also re-register your app after you build it.

And that brings us to the Launch Services database. This is more debugging info. People often want to know where the Launch Services database is, and it's in /LibraryCaches, and it begins with com/AppleLaunchServices, and the numbers that come after that, you can probably reverse engineer to figure out what they mean.

But if you really want to blow it away, you can actually blow away all of /LibraryCaches. Some other components might not like to hear me say that, but that's the design point of /LibraryCaches, is that it's a cache. It's all reconstructable, so you can blow the whole thing away, reboot, and everything's supposed to get rebuilt.

And in fact, Launch Services, the database, will get rebuilt when you reboot in such a circumstance. On Tiger, actually every user has a separate Launch Services database and that's because we were getting a little too much crosstalk between having one shared database and multiple users on the system.

and this is not the version of the slides that I approved last night. Oh well. But in order to reset your launch services database, if you really want to, you don't have to reboot. There's easier ways. And there's this tool which is hidden away down in the launch services framework because it's not really a developer tool, but I've talked about it enough on mailing lists that I thought I would just put it out there.

It's called lsregister. And rather than give you the long path, I would just suggest that you use the find command in system library frameworks to look for it. That's a little bit easier to remember than a long path. And once you find it, you can run it and do things like the dash dump switch which will give a long dump. Set your terminal window to unlimited scroll back because it will blow out whatever you have currently. And it's fairly readable dump of what's in the launch services database and all the document type claims and all of the type declarations that are there.

And that can be useful for finding, say, that, oh, yeah, I have that old crummy version of my app that I built two weeks ago and it's still on the disk somewhere. And launch services knows about it, but I don't. And that's why things aren't working right. So the dump is useful for that. And what I suggest in that case is you take that crappy old version of your app, you put it in the trash, and you empty the trash, and it will get unregistered.

You can also start from scratch by doing lsregister-kill-seed and this will erase the database and then rescan for apps just as if you were booting for the first time. You can also force a specific app to get re-registered with the -f switch which stands for force. That way even if it's already registered, it will force it to get registered again even if the mod date hasn't changed. So this is handy for avoiding lots of hair pulling and teeth gnashing and calling me bad names and things like that.

I wanted to have one slide on some of the new API in Launch Services. We talked about named attributes and getting the content type with the display name a little earlier but there's also a few new versions of the LS open functions, new ways to open things. For one thing, we have replaced the launch application function which was part of the process manager, it's still supported but we modernized it. It's a little easier to use, it's part of Launch Services and it still returns a process serial number.

In fact, all the new LS open functions will return process serial numbers for the apps that are used to handle either the app that you're opening or the app that's used to handle the document or the URL you're We also have now functions for managing user preferences both for URL Scheme bindings and also for document bindings.

And we can do this for document bindings, or if you will, binding preferences for document types because we have UTIs now. It used to be that it was very complex to do it because you could have a different binding for extension JPG and a different binding for JPEG and a different binding for OS Type JPEG. And we didn't really want that. That's impossible for the user to understand.

So instead, we have an API which is centered around UTIs and you have one binding for Type JPEG and you have another binding for Type TIFF and what have you. And these allow you to inspect the user preferences as well as set them. And if you're going to set them, I just encourage you to do it on the user's behalf and not just slam things. Thank you.

These new API are in these two header files mentioned here. The last topic I want to talk about was drag and drop service invocation. I just have a couple of minutes left, but this is something that you might not be aware of. If you came to my talk last year, you're aware of it, but it's always worth showing it again because it's a nice little service that your app can offer if it doesn't support it already. If you look up in most applications, you look up in the File menu, there's a Services item.

And the contents of the Services submenu change depending on what's selected in the document window that is in front. If it's text, you get certain services available that are provided by other applications. So for instance, Safari has a service that will do a Google search on text selected. Well, the Services menu is great and it's brought over from Next Step days and it does some really nice things, but it's a little inconvenient.

And so we realized we had all the technology available to integrate it with drag and drop and make it happen in the dock and really leverage the dock as an always present, always on top drag destination. And rather than talk about this anymore, I think I'll just show it to you. So can I have the demo machine? Demo one.

Prior to Tiger, the only thing you could drag down to the doc and drop onto an application was document. A lot of apps will properly make links live, URLs live. But you still find yourself in a lot of cases wanting to open a URL, and you can't just click on it. And now there's a pretty simple gesture. If I can get the timing right. Select something, grab it, drag it down.

It gets turned into a get URL event and sent to sent off to Safari. Yeah, this is very natural stuff, and Safari didn't have to change to make this work. We just added it to the dock in the Launch Services. You can grab some text. I don't want to select that image, though. I'm going to go down here.

Grab some text. I can go, say, to-- back to TextEdit. I wanted to save this off to the side. And--oh, you're thinking it didn't work. Well, actually, it did. It's just white. This web page has to be white. In fact, I can go to plain text. And there we go. There's the text back. Again, that's using TextEdit's service which opens a text selection in a new untitled window.

Now I mentioned that you can do Google searches with Safari. And so let's say I want to learn more about Siberian tigers. I can select that, grab, drag it down to Safari. And since it's not a URL, what Safari does instead is open a new window with a Google search. I can look for images. And here's an image that I like. Let me look at the full-size image here. I like this because it looks like the last photograph this guy ever took.

But this works even with images. You can drag an image in Safari and let's say you like that and you want to borrow it for a while and import it into iPhoto. You just drag it down to iPhoto, it launches and it imports the image into the library.

So this is just some very nice gestures, very convenient, easier than copy/paste, easier than using the service menu up in the file menu. So what do you need to do to support this? Well, if you already have services advertised in your InfoP list, then you probably already support it. If you--oh, can we go back to the slides? Sorry.

If you don't, then I encourage you to read about services. It's basically an NS Services entry in your Info.plist and you can advertise what types of data you act on. In this case, the services can send and return data and the only kind that you can invoke through the dock are send only, the kind that don't return any data.

The way we implement it behind the scenes is a new Apple event so that we can just send an Apple event off to your app and there's a default handler. It's called the Open Contents Apple Event. You don't have to handle the event directly. You can if you want to, but we have a default handler that will actually just turn around, take the data on the pasteboard or put the data back onto the pasteboard and call your service function. So all you really have to do is provide an NS Service and you'll show up in both the Services menu and you'll work with the dock.

So that's all I have to cover today. The things I'd like you to take home and think about are: use uniform type identifiers, use the ones that are built into the system, read the documentation, and use them to simplify your app and improve your user experience. Extend the system to really integrate tightly with Tiger by declaring new types, new UTIs. Think about the new launch services APIs, see if they solve any problems you've been having with some of the new options available. And also, think about offering services now that there are multiple ways to use them on the system. That's it. Thank you very much for coming.

I'm for QA. There's a-- By the way, there's a-- The documentation I mentioned is on the web. Also, we're trying to get the final version of simple text that I showed, that code, we're trying to get that up there too so that you can take a look at that.