Write Spotlight Search Index Metadata in Objective-C

When searching for files with Spotlight on macOS, the search index respects certain metadata fields assosiated with the file. This metadata can be used to improve search results and to provide additional information about the file. In this post, I’ll show you how to write this metadata to a file using Objective-C.

Understand extended file attributes

The metadata that Spotlight uses to index files is stored as extended file attributes. These attributes are key-value pairs that are stored in the file system and can be accessed using the xattr command-line tool. The xattr tool can be used to list, read, and write extended attributes.

To list the extended attributes of a file, use the following command:

xattr -l file.txt

Spotlight uses several different attributes to enrich its search index, such as com.apple.metadata:kMDItemWhereFroms and com.apple.metadata:kMDItemDownloadedDate. These attributes are used to store information about the file’s origin and download date, respectively. In this article, we will write the com.apple.metadata:kMDItemDescription attribute to a file (see documentation).

Write extended file attributes in Objective-C

To write extended file attributes in Objective-C, we can use the setxattr function from the sys/xattr.h header file. This function takes the path to the file, the name of the attribute, a pointer to the value, the size of the value, and a set of options as arguments.

The following code snippet demonstrates how to write the com.apple.metadata:kMDItemDescription attribute to a file. First, we define the file path and the description that we want to write to the file. Then, we convert the description to a C string and call the setxattr function to write the attribute to the file. For these metadata attributes, the value is a binary plist, so you need to convert the description to a binary plist before writing it to the file.

#import <Foundation/Foundation.h>
#include <sys/xattr.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSString *filePath = @"/path/to/file.txt";
        NSString *description = @"This is a description of the file";
        const char *attributeName = "com.apple.metadata:kMDItemDescription";

        // convert value to binary plist
        NSData *value = [NSPropertyListSerialization dataWithPropertyList:description
                                                                   format:NSPropertyListBinaryFormat_v1_0
                                                                  options:0
                                                                    error:nil];
        size_t size = value.length;

        // do not follow symbolic links, create or replace the attribute
        int options = XATTR_NOFOLLOW | 0;

        int result = setxattr(filePath.fileSystemRepresentation, attributeName, value.bytes, size, 0, options);
        if (result == 0) {
            NSLog(@"Successfully wrote extended attribute");
        } else {
            NSLog(@"Failed to write extended attribute");
        }
    }
    return 0;
}

This way, you can write extended file attributes to a file using Objective-C. The setxattr function returns 0 on success and -1 on failure, so you can use this to check if the attribute was written successfully.

To validate that the attribute was written to the file, you can use the xattr command-line tool again to list the specific extended attribute:

xattr -p com.apple.metadata:kMDItemDescription file.txt