Application integration using the iPhone SDK
Recently the successful iPhone applications Trein and iNap realized a tight integration, in that you can activate iNap directly from Trein. How to create the integration on the side of the ‘receiving’ application, iNap in this case, is described in the iPhone SDK example ‘Launch Me’.
When integrating applications, you typically want to pass data from one to the other, in this post I’ll describe how the incoming parameters can easily be extracted in the receiving application.
The receiving application will register itself in the OS (for details see the ‘Launch Me’ example), and the result is that it can be activated from another application or from a hyperlink in a webpage. An example of a url that activates another application is:
myapp://myapp?latitude=51.3&longitude=5.2&title=middle of nowhere
In the receiving application the method - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url will be called on the application delegate object, and in this method you need to extract the parameters from the URL. The following code shows how to do that with minimal code. Like Apple’s example, it does a lot of checking to prevent undesired usage, in this case the url parameters must meet the exact specifications (i.e. no missing parameters, no extra parameters) otherwise the request will be ignored.
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
// You should be extremely careful when handling URL requests.
// You must take steps to validate the URL before handling it.
// If any of the validations fails, bail out returning NO.
if (!url) {
// The URL is nil. There's nothing more to do.
return NO;
}
// Split the url into two sections, one section with the base url and one with the parameters.
NSArray *urlSections = [[url absoluteString] componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:@"?"]];
// Check that you actually got a base section and a parameter section.
if ([urlSections count] != 2) {
return NO;
}
// Check that the base part of the url is what you expect it to be.
if (![[urlSections objectAtIndex:0] isEqualToString:@"myapp://myapp"]) {
return NO;
}
// Split up the parameter section into a parameter Array.
NSArray *parameterArray = [[urlSections objectAtIndex:1] componentsSeparatedByCharactersInSet:
[NSCharacterSet characterSetWithCharactersInString:@"&="]];
NSEnumerator *parameterEnum = [parameterArray objectEnumerator];
NSString *parameter, *value;
// The parameters values that we are expecting.
NSString *latitude = nil, *longitude = nil, *title = nil;
// Run through the array of parameters.
while (parameter = [parameterEnum nextObject]) {
// Get the value that goes with this parameter, and if it is missing break.
if ((value = [parameterEnum nextObject]) == nil)
break;
// Check the parameter value against the parameters that you support/expect,
// and assign the matching value to the right variable.
if ([parameter isEqualToString:@"latitude"])
latitude = value;
else if ([parameter isEqualToString:@"longitude"])
longitude = value;
else if ([parameter isEqualToString:@"title"])
title = [value stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
else {
// An unexpected parameter was passed, bail out.
latitude = nil;
longitude = nil;
title = nil;
break;
}
}
// Check if we got all parameters (in this case all are mandatory), if not bail out.
if (latitude == nil || longitude == nil || title == nil) {
return NO;
}
// Use the parameters to do your thing.
CLLocation *location = [[[CLLocation alloc]
initWithLatitude:[latitude doubleValue]
longitude:[longitude doubleValue]] autorelease];
[someObject activateDestination:title location:location];
return YES;
}
Is there an easy way to pass these parameters to a view controller that will print them on the screen (not using alert message)! I’m not sure if I should create my own protocol to pass these parameters. I cannot read the values from a different view or update labels views from within this method! (labels are in a view controller, while this method is in the app delegate)
please advice!
You can create an IBOutlet in the application delegate class, and link that to a view controller in interface builder. Then in the delegate function you can pass the data to that view controller.
This does require that the view controller and application delegate are in the same .xib file.
Thanks for your reply, but I’m still confused…
Let me clarify what I want to accomplish…
I have these files inside a “SampleApp”:
- SampleAppDelegate
- SampleAppViewController
I have a NSString, a button and a label in the “SampleAppViewController”. when you click the button, the application exit and open another application (type URL, or do anything inside that other application). After that, the “SampleApp” relaunch with the URL handled inside the “- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url” method. Then, I want to check the URL string and do different actions inside the “SampleAppViewController” based on the url received. For example, show it on the screen, change the view background color, add it to NSString, show an actionSheet that will be handled inside the “SampleAppViewController”…etc.
I tried to create an instance of the ViewController class in the delegate (and tried to create an instance of the delegate class in the viewController too <– not a smart move, but I tried) and set the NSString inside the ViewController to hold the "message", but the NSString still "nil". Also, the label on the screen still empty.
One more thing, how can I run the debugger again after my application relaunch?
Actually that did work (I just forgot to link them inside the .xib)! I created a method inside the view controller that displays the actionSheet instead of doing it inside the app delegate.
Thanks for this info. Do you know of an example where a iPhone web app links to an iPhone native app (of course, not including mail, maps, etc.)? Your post indicates this is possible.
I don’t know of such an example. The key is in the receiving application that needs to be able to handle this. If so, any application or web app can start that applications.
Thanks so much for posting this. I’ve been searching how to take the launchme example to the next level, but until now never found how to parse the parameters properly.