How to launch your Mac/iOS app with a custom URL

One interesting feature of iOS and Mac apps is the ability for them to be launched by a custom URL. What this means is that you can set up your app to respond to different links in different ways.

Clicking a link that says myTwitterApp://sendTweet?tweet=hello could send a tweet from your twitter app. It could also be used for configuring your app. Maybe you have an email app that needs some special server configurations. It could be set up so that you just have to visit a webpage on your server and click a link and have it automatically configure your email settings.

Facebook uses the URL scheme for authentication in their iPhone app. If I have an app that wants to authenticate with Facebook, it will try and talk to the Facebook app on the phone so I don’t have to authenticate again in my other app.

I think this is a pretty underused feature and I would bet there are TONS of clever things people can do with it. So how do you actually do it?

I’m going to show you how I’m adding it to the next versions of Thoughtback.

Your first step is adding a URL type to your app’s info.plist. You will add the same key if you’re making an iOS or Mac app. The raw key is CFBundleURLTypes.

Once the key is added links that start with thoughtback:// will launch the apps on both iOS and OS X.

Just launching from a URL is fine, but how do you get any information out of the URL that was clicked? That’s where the process differs between the two platforms.

iOS
Go into your applicationdelegate and override either of these two methods.

- (BOOL)application:(UIApplication *)application 
           handleOpenURL:(NSURL *)url

- (BOOL)application:(UIApplication *)application 
            openURL:(NSURL *)url 
  sourceApplication:(NSString*)sourceApplication 
         annotation:(id)annotation

I should mention that the first method is deprecated, but the second one is only available on iOS 4.2 or later.

Mac OS
This is slightly different on the mac, URL handling is not part of the NSApplicationDelegate protocol.

What you’ll need to do is tell the application to respond to an Apple Event.

-(void)applicationWillFinishLaunching:(NSNotification *)aNotification
{
    NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager];
    [appleEventManager setEventHandler:self
                           andSelector:@selector(handleGetURLEvent:withReplyEvent:)
                         forEventClass:kInternetEventClass andEventID:kAEGetURL];
}

- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent
{
    NSURL *url = [NSURL URLWithString:[[event paramDescriptorForKeyword:keyDirectObject] stringValue]];
}

Parsing the URL
So now that you have the URL that launched your app, you’ll want to get the information out of the string. The most typical way to send information is with a query string. Here’s an example that Thoughtback will use.

thoughtback://send?thought=Interesting Thought&redirect=http://fredandrandall.com

We want to pull out a few different things from that. First we want to grab “send” because that’s the action thoughtback will take. Then we want to get the thought that will be sent and the url that Thoughtback will redirect to when it’s done sending the thought.

To parse out “send” we can use NSURL’s host method.

To get the query string, we can use NSURL’s query method.

Parsing the query string is a little more difficult but this block of code, that I found on StackOverflow, will put it into an NSDictionary for you.

NSString *query = [url query];
NSArray *queryPairs = [query componentsSeparatedByString:@"&"];
NSMutableDictionary *pairs = [NSMutableDictionary dictionary];
for (NSString *queryPair in queryPairs) {
  NSArray *bits = [queryPair componentsSeparatedByString:@"="];
  if ([bits count] != 2) { continue; }

  NSString *key = [[bits objectAtIndex:0] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
  NSString *value = [[bits objectAtIndex:1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

  [pairs setObject:value forKey:key];
}
This entry was posted in Uncategorized and tagged , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>