How 1Password extension loads in 64-bit Safari in Snow Leopard

Kevin Ballard explains how 1Password is able to load an extention into Safari when running in 64-bit mode:

When Cocoa was introduced, one of the behaviors that every Cocoa application automatically acquired was the loading of Input Managers. These Input Managers were intended to allow developers to extend the text input system of OS X in ways that the system did not provide by default. However, these Input Managers were really nothing more than Cocoa bundles that got loaded by every single Cocoa app at launch. This means that it was very quickly abused to become a general plugin mechanism for applications that do not natively support plugins (such as Safari). In recent OS updates, Apple has been deprecating this mechanism, and now in Snow Leopard it’s completely gone for 64-bit apps.

Luckily, the smart folks who make 1Password came up with a solution for their upcoming 1Password 3.0 (which is in public beta right now).

AppleScript is a rather old technology, first introduced in System 7. It is a human-readable scripting language that can control any application that implements support for it, along with a slew of system functions. Under the hood, it sends Apple events to actually talk to each process.

Scripting additions are bundles that provide additional functionality to AppleScript, generally by installing Apple event handlers or doing Apple event data coercion.

The thing about scripting additions is that they will be potentially loaded by any process on the system. Generally, they get loaded into a process that attempts to use an AppleEvent that the scripting addition handles.

The ability to load a scripting addition into a target process simply by sending it an Apple event is the key mechanism that allows us to restore the old Input Manager functionality. And this is exactly what 1Password does. 1Password includes a scripting addition that handles the ONEP/Load Apple event with a context of “Process”. This handler takes a single argument, the path to a given bundle, and it loads that specified bundle into the target process. The last component is a background daemon called 1PasswordAgent. This daemon sends the ONEP/Load Apple event to Safari immediately after Safari is launched, causing Safari to load the 1Password WebKit plugin.

This actually sounds a lot cleaner than the input manager hack. I hope Apple doesn’t disable this in the future. Hopefully it will also provide a mechanism for 1Password to work in Opera & Google Chrome.

Getting the title of a Web View in Cocoa Touch

In an application I’m working on, I display a UIWebView with a navigation bar. I wanted to display the title of the web page in the navigation bar when I load a page, but there doesn’t appear to be any obvious way to do it.

There’s actually a very easy way to get the title (or any other property) of a page in a web view: stringByEvaluatingJavaScriptFromString:.

In this case, I use the delegate method webViewDidFinishLoad to obtain the page title and set the title of the navigation bar,

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString* title = [webView stringByEvaluatingJavaScriptFromString: @"document.title"];
    navbar.title = title;
}

The result looks like this:

iPhone Simulator
Uploaded with plasq‘s Skitch!

More FriendFeed Stuff

I’ve implemented posting in my Cocoa FriendFeed class, and I ended up rewriting the fetch methods to use a NSURLConnection rather than PubSub. I’m now using a temporary PSFeed object to parse the received data rather than maintaining PSFeed objects for all requested feeds. I could probably use a NSXMLDocument, but PSFeed seems cleaner.

Here’s how I’m doing it now:


// this method handles data received from the NSURLConnection
- (void) parse: (NSData*) data {
    PSFeed *feed = [[PSFeed alloc] initWithData: data URL: _url];
    for (PSEntry *entry in [feed entries]) {
        [_entries addObject: [[FFItem itemWithEntry: entry] retain]];
    }
    [feed release];
}

As you can see I’m using Objective C 2.0, so this will only work in Leopard or later.

FriendFeed API

I’ve been playing with the FriendFeed API in Objective C, although I don’t have anything ready for public consumption yet.

Since the fetch methods basically work like RSS feeds, they can be handled easily using PubSub. Most of the code I had to write was to decode the entries returned into something more useful. The methods which require authentication turned out to be no big deal; it can be handled using PSFeed’s login property and the setPassword: method. My next step will be to tackle the publish methods, which can be handled using NSURLConnection.

To make time to work on this, I haven’t been reading my RSS feeds regularly (or checking Twitter). Setting NetNewsWire to manual refresh only is a huge productivity booster. I also haven’t been blogging regularly, as my readers probably noticed.