Poking a Hole in the Sandbox: Using URLs on iOS
Greg Pierce @agiletortoise
agiletortoise.com Tuesday, September 11, 12 Who am I?
Greg Pierce
President, Agile Tortoise
@agiletortoise http://agiletortoise.com
Indie app development, web consulting
agiletortoise.com Tuesday, September 11, 12 What do I do?
Drafts Terminology Phraseology
agiletortoise.com Tuesday, September 11, 12 What am I talking about?
Custom URLs schemes as tool for inter-app communication on iOS.
- Limited options in the sandbox.
- Consume URLs in other apps.
- Provide services with URLs.
agiletortoise.com Tuesday, September 11, 12 Inter-app whaaa?
Integrating with other apps can make your app...
- More useful.
- Offers great opportunities for cross-promotion.
agiletortoise.com Tuesday, September 11, 12 Overview
Part 1 - What? - Local and Lightweight
Part 2 - Why? - Use Cases
Part 3 - How? - Implementation
Part 4 - X-Callback-URL
Q & A
agiletortoise.com Tuesday, September 11, 12 Part 1 - What?
Local and Lightweight
agiletortoise.com Tuesday, September 11, 12 Anatomy of a URL
- URL = Uniform Resource Locator
scheme://domain:port/path? query_string#fragment_id
- “scheme” or “protocol” is registered with OS.
- Safari registers “http” - Phone.app registers “tel” - Mail.app registers “mailto”
agiletortoise.com Tuesday, September 11, 12 Custom URLs
- iOS provides means to register “Custom URL schemes” for apps.
- Registering says you know what to do with “scheme:” URLs.
- Simple entries in app’s Info.plist.
- One app can register many custom URL schemes.
agiletortoise.com Tuesday, September 11, 12 URLs
- Lightweight Messaging between apps.
- No OAuth, Web Services, complex setup.
- Local
- No network require for locally installed apps.
- Few options!
agiletortoise.com Tuesday, September 11, 12 Custom URL structure
- Beyond the scheme and the colon, custom URL can look like anything.
scheme:*
- Not tied to HTTP (host:port/path) structure, but... - reuse tools/code that already exist to parse. - easier to document/consume.
- Must follow escaping/encoding guidelines - Can support 80k characters at least.
agiletortoise.com Tuesday, September 11, 12 Using URLs
- URLs can be triggered like any links
- Link embedded on a webpage
- Programmatically – two important methods:
[[UIApplication sharedApplication] canOpenURL:(NSURL *)url];
[[UIApplication sharedApplication] openURL:(NSURL *)url];
agiletortoise.com Tuesday, September 11, 12 What happens?
When a custom URL is opened...
- Source app is backgrounded. - Target app is launched (or foregrounded) - Target AppDelegate is notified with a URL, using...
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
agiletortoise.com Tuesday, September 11, 12 Part 2 - Why?
Use cases
agiletortoise.com Tuesday, September 11, 12 Testing if app is installed
If you register a unique URL scheme, you give other apps a way to test if your app is installed.
This includes your own apps...great for cross- promoting apps, without annoying people who have already downloaded.
agiletortoise.com Tuesday, September 11, 12 Launching
Without any additional work, registering a URL scheme gives apps a way to launch your app.
See Launch Center Pro from App Cubby...
agiletortoise.com Tuesday, September 11, 12 Launching with Context
Have the user arrive at a specific place in your app...
Facebook: fb://profile fb://events
Tweetbot: tweetbot://post
agiletortoise.com Tuesday, September 11, 12 Launching with Content
Send some bit of string data to the target app.
Drafts drafts://x-callback-url/create?text=%@
OmniFocus omnifocus:///add?name=%@
agiletortoise.com Tuesday, September 11, 12 Executing an Action
Dial a phone number
tel:8175551234
Open this URL, Phone.app will launch and dial the number.
agiletortoise.com Tuesday, September 11, 12 Two-Way Interaction
- All these examples are one-way.
Source App > Target App
- What about 2-way?
Source App > Target App > Source App
- Callback URLs
agiletortoise.com Tuesday, September 11, 12 Instapaper > Terminology > Instapaper
terminology://x-callback-url/lookup? text=ceremony &x-source=Instapaper &x-success=instapaper://
agiletortoise.com Tuesday, September 11, 12 Instapaper > Terminology > Instapaper
Terminology does the “lookup”
x-source param provides friendly name for source
Tap and Terminology will trigger the url in the x-success param
agiletortoise.com Tuesday, September 11, 12 Two-Way with Data - Terminology Replace
terminology://x-callback-url/replace? text=Select &x-success=drafts://x-callback-url/replaceSelection &x-source=Drafts &x-cancel=drafts://
drafts://x-callback-url/replaceSelection &replaceWith=choose
drafts://
agiletortoise.com Tuesday, September 11, 12 Other Two-Way
- iZettle
- Credit Card Transactions
- Scanner Go
- Bar Code Scanning
- Authorization
- Dropbox SDK, Facebook SDK
agiletortoise.com Tuesday, September 11, 12 What not to do with URLs
- Destructive actions
myapp://deleteEverything
- If destructive, require user confirmation.
- Think about HTTP GET RESTful actions.
agiletortoise.com Tuesday, September 11, 12 Part 3 - How?
Implementation
agiletortoise.com Tuesday, September 11, 12 URLScheme Demo App
Example app on Github
https://github.com/agiletortoise/URLSchemes
agiletortoise.com Tuesday, September 11, 12 Consuming URLs
agiletortoise.com Tuesday, September 11, 12 Building URLs
#import "Scratchpad.h" #import "NSString+URLEncoding.h" // Category for encoding
@implementation Scratchpad - (void)examples { NSString *urlString = @"test://action?param1=%@¶m2=%@"; NSString *p1 = @"Hello World"; NSString *p2 = @"You’re Awesome";
NSString *fullURLString = [NSString stringWithFormat:urlString, [p1 urlEncodeUsingEncoding:NSUTF8StringEncoding], [p2 urlEncodeUsingEncoding:NSUTF8StringEncoding]]; NSURL *url = [NSURL URLWithString:fullURLString]; } @end
test://action? param1=Hello%20World ¶m2=You%E2%80%99re%20Awesome
agiletortoise.com Tuesday, September 11, 12 Opening URLs
if ([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url]; }
- Use canOpenURL to build UI, don’t show things that can’t be used.
- canOpenURL doesn’t need full URLs, test with just “scheme://”
agiletortoise.com Tuesday, September 11, 12 Providing URLs
agiletortoise.com Tuesday, September 11, 12 Register scheme
agiletortoise.com Tuesday, September 11, 12 Register in Info.plist
agiletortoise.com Tuesday, September 11, 12 Valid URL Scheme Names
- Sequence of characters beginning with a letter and followed by any combination of letters, digits, plus ("+"), period ("."), or hyphen ("-").
- NOT case sensitive.
agiletortoise.com Tuesday, September 11, 12 Recommended URL Scheme Names
- Your app name as it appears on the device, with hyphens in place of spaces.
My App Name ⬇ my-app-name://
agiletortoise.com Tuesday, September 11, 12 Versioning
If you provide actions that you need to version over time, register additional URLs
x-app-api10:// x-app-api20://
Now you have a way to test for compatibility.
agiletortoise.com Tuesday, September 11, 12 Reacting to URL
On AppDelegate, define:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation; c
- called after applicationWillEnterForeground - called before applicationDidBecomeActive - return NO if you don’t recognize the URL - (Nothing happens, just best practice)
agiletortoise.com Tuesday, September 11, 12 iOS 3 note...
Prior to iOS 4, you handled URLs in....
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url;
If you need to support iOS 3, implement this method and forward to your application: openURL: sourceApplication: annotation method.
agiletortoise.com Tuesday, September 11, 12 Parsing Parameters
myapp://actionName?test=param%20value&test2=paramValue
URLParser *parser = [[URLParser alloc] initWithURLString:[url absoluteString]]; NSString *testParamValue = [parser valueForVariable:@"test"]; // testParamValue == @”param value”
agiletortoise.com Tuesday, September 11, 12 Parsing Parameters
If you parse using some other method, USE THIS METHOD TO DECODE!!!
[str stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
agiletortoise.com Tuesday, September 11, 12 DEMO
(unreheased, apologies in advance)
agiletortoise.com Tuesday, September 11, 12 Part 4
X-Callback-URL
agiletortoise.com Tuesday, September 11, 12 X-Callback-URL
- Specification to standardize URL formats
- Drafts, Terminology, Instapaper, Agenda, Due, iCab Mobile, Poster, Phraseology, Notesy.
- Collaboration of myself, Marco Arment with input from a few others.
http://x-callback-url.com
agiletortoise.com Tuesday, September 11, 12 X-Callback-URL format
scheme://x-callback-url/[action]?[x-callback parameters]&[action parameters]
- [action] is specific to your app/implementation and should typically be a verb.
- [action parameters] are also specific to your app and show be in a URL query string...i.e.:
subject=The%20Subject&body=The%20Body
agiletortoise.com Tuesday, September 11, 12 X-Callback-URL Parameters
x-source: Friendly name of source app.
x-success: Base URL to fire if successful
x-error: Base URL to fire if error occurs
x-cancel: Base URL to fire if user cancels
agiletortoise.com Tuesday, September 11, 12 Finally....
- Why use URL schemes? Why not?
- Why format them with X-Callback-URL? Why not?
- Document what you implement!!!!!!
- Use affiliate links to promote apps you integrate with!!!!!
- UTF8 escape and decode parameters!
- Test with Unicode chars and cold starts.
agiletortoise.com Tuesday, September 11, 12 Resources
Find URL schemes: - http://handleopenurl.com - http://wiki.akosma.com/IPhone_URL_Schemes
Tutorial: - http://mobile.tutsplus.com/tutorials/iphone/ios-sdk-working- with-url-schemes/
X-Callback-URL: - http://x-callback-url.com (sample apps/examples)
URLSchemes Demo App: - https://github.com/agiletortoise/URLSchemes
agiletortoise.com Tuesday, September 11, 12 Q & A @agiletortoise
Slides and Links: http://agiletortoise.com/blog
agiletortoise.com Tuesday, September 11, 12