Hacking OS X: How to write a plugin for Safari

George Brocklehurst (@georgebrock on Twitter)

A presentation at Barcamp London 6, 2009-03-29

These slides: gbrck.com/bcl6
Licensed under Creative Commons BY-NC-SA

What do we need to do?

There is no official plugin API for Safari (or many other OS X applications), so we need to find our own way in:

  1. Get Safari to load our code bundle
  2. Work out which methods in Safari should trigger our code
  3. Replace the relevant methods with our own

Step 1: Getting Safari to load our code

Input Managers

Writing an Input Manager

The property list

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" 
<plist version="1.0">

The bundle

Example bundle code

+ (void)load
	NSBundle *hostApp = [NSBundle mainBundle];

	// Check the host app is Safari
	NSString *bundleID = [hostApp bundleIdentifier];
	if(![bundleID isEqualToString:@"com.apple.Safari"])
	// Check this version of Safari is supported
	NSDictionary *infoDict = [hostApp infoDictionary];
	float v = [[infoDict 
		valueForKey:@"CFBundleVersion"] floatValue];
	if(v < 5528.16)
		//TODO: Tell the user why the plugin hasn't loaded
	// Initialise your plugin here...

SIMBL (Smart InputManager Bundle Loader)

Step 2: Reverse engineering Safari

Our code is loaded into Safari, but we want to add or modify certain behaviours.


F-Script Anywhere

Other tools

Various UNIX command line tools can also be helpful:

Displays the symbol table for an executable
Displays any printable strings contained within a binary file
The GNU debugger

Step 3: Replacing a Safari method with your own method

Two methods for replacing a built in Safari method with your own:


Method swizzling

Example code

#import <objc/objc-class.h>

@implementation Swizzler

+ (BOOL)renameSelector:(SEL)oldSelector 
	Method method = class_getInstanceMethod(class, oldSelector);
	if(method == nil)
		return FALSE;

	method->method_name = newSelector;
	return TRUE;



	onClass:[MyClass class]];
	onClass:[MyClass class]];

Linker settings

Demo application

Source code for a demonstration plugin is available on GitHub: github.com/georgebrock/bcl6-safari-plugin-demo

The demo code is released under a Creative Commons attribution license, so you can do almost anything you want with it.

Any questions?

Ask them at Barcamp, or get in touch via georgebrock.com