From 3365f0c163ba8680ddf2295a369561b34dfe85a6 Mon Sep 17 00:00:00 2001 From: jverkoey Date: Sun, 31 Jul 2011 18:35:40 -0700 Subject: [PATCH] [interapp] Add the InterApp feature. --- src/interapp/deps | 0 src/interapp/src/NIRunApp.h | 234 ++++++++++++++++++++ src/interapp/src/NIRunApp.m | 414 ++++++++++++++++++++++++++++++++++++ 3 files changed, 648 insertions(+) create mode 100644 src/interapp/deps create mode 100644 src/interapp/src/NIRunApp.h create mode 100644 src/interapp/src/NIRunApp.m diff --git a/src/interapp/deps b/src/interapp/deps new file mode 100644 index 000000000..e69de29bb diff --git a/src/interapp/src/NIRunApp.h b/src/interapp/src/NIRunApp.h new file mode 100644 index 000000000..8d90ee4ab --- /dev/null +++ b/src/interapp/src/NIRunApp.h @@ -0,0 +1,234 @@ +// +// Copyright 2011 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import +#import + +@class NIMailAppInvocation; + +/** + * An interface for interacting with other apps installed on the device. + */ +@interface NIRunApp : NSObject + +#pragma mark Safari /** @name Safari **/ + +/** + * Opens the given URL in Safari. + */ ++ (BOOL)safariWithURL:(NSURL *)url; + + +#pragma mark Google Maps /** @name Google Maps **/ + +/** + * Opens Google Maps at the given location. + */ ++ (BOOL)googleMapAtLocation:(CLLocationCoordinate2D)location; + +/** + * Opens Google Maps at the given location with a title. + */ ++ (BOOL)googleMapAtLocation: (CLLocationCoordinate2D)location + title: (NSString *)title; + +/** + * Opens Google Maps with directions from one location to another. + */ ++ (BOOL)googleMapDirectionsFromLocation: (CLLocationCoordinate2D)fromLocation + toLocation: (CLLocationCoordinate2D)toLocation; + +/** + * Opens Google Maps with a generic query. + */ ++ (BOOL)googleMapWithQuery:(NSString *)query; + + +#pragma mark Phone /** @name Phone **/ + +/** + * Opens the phone app. + */ ++ (BOOL)phone; + +/** + * Make a phone call with the given number. + */ ++ (BOOL)phoneWithNumber:(NSString *)phoneNumber; + + +#pragma mark SMS /** @name SMS **/ + +/** + * Opens the phone app. + */ ++ (BOOL)sms; + +/** + * Start texting the given number. + */ ++ (BOOL)smsWithNumber:(NSString *)phoneNumber; + + +#pragma mark Mail /** @name Mail **/ + +/** + * Opens mail with the given invocation properties. + */ ++ (BOOL)mailWithInvocation:(NIMailAppInvocation *)invocation; + + +#pragma mark YouTube /** @name YouTube **/ + +/** + * Opens the YouTube video with the given video id. + */ ++ (BOOL)youTubeWithVideoId:(NSString *)videoId; + + +#pragma mark iBooks /** @name iBooks **/ + +/** + * Returns YES if the iBooks application is installed. + */ ++ (BOOL)iBooksIsInstalled; + +/** + * Opens the iBooks application. If the iBooks application is not installed, will open the + * App Store to the iBooks download page. + */ ++ (BOOL)iBooks; + +/** + * The iBooks App Store ID. + */ ++ (NSString *)iBooksAppStoreId; + + +#pragma mark Facebook /** @name Facebook **/ + +/** + * Returns YES if the Facebook application is installed. + */ ++ (BOOL)facebookIsInstalled; + +/** + * Opens the Facebook application. If the Facebook application is not installed, will open the + * App Store to the Facebook download page. + */ ++ (BOOL)facebook; + +/** + * Opens the Facebook profile with the given id. + */ ++ (BOOL)facebookProfileWithId:(NSString *)profileId; + +/** + * The Facebook App Store ID. + */ ++ (NSString *)facebookAppStoreId; + + +#pragma mark Twitter /** @name Twitter **/ + +/** + * Returns YES if the Twitter application is installed. + */ ++ (BOOL)twitterIsInstalled; + +/** + * Opens the Twitter application. If the Twitter application is not installed, will open the + * App Store to the Twitter download page. + */ ++ (BOOL)twitter; + +/** + * Begins composing a message. + */ ++ (BOOL)twitterWithMessage:(NSString *)message; + +/** + * Opens the profile for the given username. + */ ++ (BOOL)twitterProfileForUsername:(NSString *)username; + +/** + * The Twitter App Store ID. + */ ++ (NSString *)twitterAppStoreId; + + +#pragma mark Instagram /** @name Instagram **/ +// http://instagram.com/developer/iphone-hooks/ + +/** + * Returns YES if the Instagram application is installed. + */ ++ (BOOL)instagramIsInstalled; + +/** + * Opens the Instagram application. If the Instagram application is not installed, will open the + * App Store to the Instagram download page. + */ ++ (BOOL)instagram; + +/** + * Opens the Instagram camera. + */ ++ (BOOL)instagramCamera; + +/** + * Opens the profile for the given username. + */ ++ (BOOL)instagramProfileForUsername:(NSString *)username; + +/** + * The Instagram App Store ID. + */ ++ (NSString *)instagramAppStoreId; + + + +#pragma mark App Store /** @name App Store **/ + +/** + * Opens the App Store page for the app with the given ID. + */ ++ (BOOL)appStoreWithAppId:(NSString *)appId; + +@end + +@interface NIMailAppInvocation : NSObject { +@private + NSString* _recipient; + NSString* _cc; + NSString* _bcc; + NSString* _subject; + NSString* _body; +} + +@property (nonatomic, readwrite, copy) NSString* recipient; +@property (nonatomic, readwrite, copy) NSString* cc; +@property (nonatomic, readwrite, copy) NSString* bcc; +@property (nonatomic, readwrite, copy) NSString* subject; +@property (nonatomic, readwrite, copy) NSString* body; + +/** + * Creates an autoreleased invocation object. + */ ++ (id)invocation; + +@end diff --git a/src/interapp/src/NIRunApp.m b/src/interapp/src/NIRunApp.m new file mode 100644 index 000000000..837955a79 --- /dev/null +++ b/src/interapp/src/NIRunApp.m @@ -0,0 +1,414 @@ +// +// Copyright 2011 Jeff Verkoeyen +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +#import "NIRunApp.h" + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation NIRunApp + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)stringByEscapingParameterString:(NSString *)parameter { + return [(NSString *)CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, + (CFStringRef)parameter, + NULL, + (CFStringRef)@";/?:@&=+$,", + kCFStringEncodingUTF8) + autorelease]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)sanitizedPhoneNumberFromString:(NSString *)string { + if (nil == string) { + return nil; + } + + NSCharacterSet* validCharacters = + [NSCharacterSet characterSetWithCharactersInString:@"1234567890-+"]; + return [[string componentsSeparatedByCharactersInSet:[validCharacters invertedSet]] + componentsJoinedByString:@""]; + +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Safari + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)safariWithURL:(NSURL *)url { + return [[UIApplication sharedApplication] openURL:url]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Google Maps + +/** + * Source for URL information: http://mapki.com/wiki/Google_Map_Parameters + */ + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)googleMapAtLocation:(CLLocationCoordinate2D)location { + NSString* urlPath = [NSString stringWithFormat: + @"http://maps.google.com/maps?q=%f,%f", + location.latitude, location.longitude]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)googleMapAtLocation: (CLLocationCoordinate2D)location + title: (NSString *)title { + NSString* urlPath = [NSString stringWithFormat: + @"http://maps.google.com/maps?q=%@@%f,%f", + [self stringByEscapingParameterString:title], location.latitude, location.longitude]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)googleMapDirectionsFromLocation: (CLLocationCoordinate2D)fromLocation + toLocation: (CLLocationCoordinate2D)toLocation { + NSString* urlPath = [NSString stringWithFormat: + @"http://maps.google.com/maps?saddr=%f,%f&daddr=%f,%f", + fromLocation.latitude, fromLocation.longitude, + toLocation.latitude, toLocation.longitude]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)googleMapWithQuery:(NSString *)query { + NSString* urlPath = [NSString stringWithFormat: + @"http://maps.google.com/maps?q=%@", + [self stringByEscapingParameterString:query]]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Phone + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)phone { + return [self phoneWithNumber:nil]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)phoneWithNumber:(NSString *)phoneNumber { + phoneNumber = [self sanitizedPhoneNumberFromString:phoneNumber]; + + NSString* urlPath = [@"tel:" stringByAppendingString:phoneNumber]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Texting + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)sms { + return [self smsWithNumber:nil]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)smsWithNumber:(NSString *)phoneNumber { + phoneNumber = [self sanitizedPhoneNumberFromString:phoneNumber]; + + NSString* urlPath = [@"sms:" stringByAppendingString:phoneNumber]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Mail + +static NSString* const sMailScheme = @"mailto:"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)mailWithInvocation:(NIMailAppInvocation *)invocation { + NSString* urlPath = sMailScheme; + if (NIIsStringWithAnyText(invocation.recipient)) { + urlPath = [urlPath stringByAppendingString:[self stringByEscapingParameterString: + invocation.recipient]]; + } + NSMutableArray* parameters = [NSMutableArray array]; + if (NIIsStringWithAnyText(invocation.cc)) { + [parameters addObject:[@"cc=" stringByAppendingString:[self stringByEscapingParameterString:invocation.cc]]]; + } + if (NIIsStringWithAnyText(invocation.bcc)) { + [parameters addObject:[@"bcc=" stringByAppendingString:[self stringByEscapingParameterString:invocation.bcc]]]; + } + if (NIIsStringWithAnyText(invocation.subject)) { + [parameters addObject:[@"subject=" stringByAppendingString:[self stringByEscapingParameterString:invocation.subject]]]; + } + if (NIIsStringWithAnyText(invocation.body)) { + [parameters addObject:[@"body=" stringByAppendingString:[self stringByEscapingParameterString:invocation.body]]]; + } + if ([parameters count] > 0) { + urlPath = [urlPath stringByAppendingFormat:@"?%@", [parameters componentsJoinedByString:@"&"]]; + } + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark YouTube + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)youTubeWithVideoId:(NSString *)videoId { + NSString* urlPath = [@"http://www.youtube.com/watch?v=" stringByAppendingString:videoId]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark iBooks + +static NSString* const sIBooksScheme = @"itms-books:"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)iBooksIsInstalled { + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:sIBooksScheme]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)iBooks { + BOOL didOpen = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:sIBooksScheme]]; + + if (!didOpen) { + didOpen = [self appStoreWithAppId:[self iBooksAppStoreId]]; + } + + return didOpen; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)iBooksAppStoreId { + return @"364709193"; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Facebook + +static NSString* const sFacebookScheme = @"fb:"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)facebookIsInstalled { + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:sFacebookScheme]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)facebook { + BOOL didOpen = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:sFacebookScheme]]; + + if (!didOpen) { + didOpen = [self appStoreWithAppId:[self facebookAppStoreId]]; + } + + return didOpen; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)facebookProfileWithId:(NSString *)profileId { + NSString* urlPath = [sFacebookScheme stringByAppendingFormat:@"//profile/%@", profileId]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)facebookAppStoreId { + return @"284882215"; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Twitter + +static NSString* const sTwitterScheme = @"twitter:"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)twitterIsInstalled { + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:sTwitterScheme]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)twitter { + BOOL didOpen = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:sTwitterScheme]]; + + if (!didOpen) { + didOpen = [self appStoreWithAppId:[self twitterAppStoreId]]; + } + + return didOpen; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)twitterWithMessage:(NSString *)message { + NSString* urlPath = [sTwitterScheme stringByAppendingFormat:@"//post?message=%@", + [self stringByEscapingParameterString:message]]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)twitterProfileForUsername:(NSString *)username { + NSString* urlPath = [sTwitterScheme stringByAppendingFormat:@"//user?screen_name=%@", + [self stringByEscapingParameterString:username]]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)twitterAppStoreId { + return @"333903271"; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark Instagram + +static NSString* const sInstagramScheme = @"instagram:"; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)instagramIsInstalled { + return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:sInstagramScheme]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)instagram { + BOOL didOpen = [[UIApplication sharedApplication] openURL:[NSURL URLWithString:sInstagramScheme]]; + + if (!didOpen) { + didOpen = [self appStoreWithAppId:[self instagramAppStoreId]]; + } + + return didOpen; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)instagramCamera { + NSString* urlPath = [sInstagramScheme stringByAppendingString:@"//camera"]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)instagramProfileForUsername:(NSString *)username { + NSString* urlPath = [sInstagramScheme stringByAppendingFormat:@"//user?username=%@", + [self stringByEscapingParameterString:username]]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (NSString *)instagramAppStoreId { + return @"389801252"; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma mark - +#pragma mark App Store + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (BOOL)appStoreWithAppId:(NSString *)appId { + NSString* urlPath = [@"http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=" stringByAppendingString:appId]; + return [[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlPath]]; +} + + +@end + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////////// +@implementation NIMailAppInvocation + +@synthesize recipient = _recipient; +@synthesize cc = _cc; +@synthesize bcc = _bcc; +@synthesize subject = _subject; +@synthesize body = _body; + + +/////////////////////////////////////////////////////////////////////////////////////////////////// +- (void)dealloc { + NI_RELEASE_SAFELY(_recipient); + NI_RELEASE_SAFELY(_cc); + NI_RELEASE_SAFELY(_bcc); + NI_RELEASE_SAFELY(_subject); + NI_RELEASE_SAFELY(_body); + + [super dealloc]; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////////// ++ (id)invocation { + return [[[[self class] alloc] init] autorelease]; +} + + +@end