Creating Spotlight Pluginsby Matthew Russell
Last time, we used Spotlight to query and manipulate metadata for existing files. This is great, but what if you want Spotlight to index a file custom file format, perhaps some marvelous format that you created yourself? Don't fret. Spotlight was designed to be extensible and to accommodate any file format. In this piece, you'll learn how to index a custom file format by creating a Spotlight plugin.
A Spotlight plugin simply parses and returns the useful metadata from a file to the Spotlight server; the server handles the rest. Apple has provided a nice example of creating a Spotlight plugin that you should skim over before proceeding. It's located in
/Developer/Examples/Metadata, includes a simple application that creates a custom file format, and supplies a Spotlight plugin for that custom file format. In particular, take note of these highlights:
Creating a Spotlight Plugin for Stickies
If you haven't noticed by now, Spotlight does not index the notes that Stickies creates. This is at least in part because Spotlight indexes files by their extension, and each file extension should map to a unique Uniform Type Identifiers (UTI). Unfortunately, Stickies stores all of its information in
~/Library/StickiesDatabase: a single file encapsulating multiple notes that has no extension. This situation is basically the worst possible scenario, but we can have some good fun working with it. The ideal situation would have been for Stickies to create a separate file on disk for each note, and for each of these files to have an extension. This is the new approach used by Mail as of Tiger's release. (Previously, Mail had stored the information in a single Unix-style "mbox" file.)
There are only a few basic steps to creating a Spotlight plugin, and Xcode really streamlines the process. All that you really have to do is use the template Xcode provides, define a method body, and make a few other minor changes. Since Stickies poses such an interesting situation, we'll have to do some clever hacking. The basic procedure we use will work in virtually any other situation, so this makes for a very practical learning experience.
~/Library/StickiesDatabase file does not have an extension. Creating a soft link with an extension can't help us any and, incidentally, neither can creating a hard link. (It appears that, Stickies rewrites the file each time it processes an update, so the file's inode changes, breaking the hard link.) Changing the applicable occurrences of the "StickiesDatabase" string in the bundled Mach-O executable with a hex editor would be the easiest approach to fix the dilemma, but would have violated Apple's End User License (specifically section 2.C), so we'll stay away from that. Instead, we'll simply have
cron periodically copy and rename "StickiesDatabase" to a file with an extension. (Check here for a cron tutorial, or check the man pages.) In Terminal, type
crontab -e to open up the table for editing, paste in the following line, and save it.
* * * * * cp ~/Library/StickiesDatabase ~/Library/StickiesData.aaa
This line says to copy and rename "StickiesDatabase" to "StickiesData.aaa every minute. The "aaa" is an arbitrary extension that I made up and is highly unlikely to create a conflict with existing applications. This approach saves us from violating Apple's End User License, and still creates the desired effect (with a slight delay involved).
Now that we'll always have a "fresh" StickiesDatabase file with an extension in place, we can proceed. Here's a quick overview of what we'll do:
- Create a new project in Xcode
- Set the UTI types the importer supports
- Update the schema.xml file
- Copy in some additional project files that allow us to parse the "StickiesDatabase" file format
- Implement the
- Make some minor changes to the project to resolve compilation/linking errors
- Copy the plugin into
/Library/Spotlight/and troubleshoot as necessary
Create a New Project in Xcode
When you create your new project, choose "Metadata Importer" from under "Standard Apple Plugins," and name the project, "StickiesImporter." Take a moment to peruse "GetMetadataForFile.c." The file "main.c" is interesting, but mostly cookie cutter stuff we don't necessarily have to be concerned with at an application programming level.
Create a "Metadata Importer" using Xcode.