iOS 应用打开其他APP(附带问题处理)
注册自定义URL协议
首先被启动的应用需要向iPhone注册一个自定义URL协议。这是在你的项目文件夹的info.plist文件进行的(就是你改变应用程序图标的同一个文件)。
Step1. 右键,选择“Add Row”Step2. Key值选择“URL types”
Step3. 打开“Item 0″,然后为该key增加一个URL identifier。可以是任何值,但建议用“反域名”(例如 “com.fcplayer.testHello”)。
Step4. 在“Item 0”下再加一行。
Step5. 选择“URL Schemes” 作为Key。
Step6. 输入你的URL协议名 (例如“testHello://” 应写做“testHello”)。如果有必要,你可以在这里加入多个协议。
操作截图如下:
访问自定义URL
在主应用程序中通过访问自定义URL启动另外一个应用:
[csharp]view plaincopy
NSURL * myURL_APP_A = [NSURL URLWithString:@"testHello://"];
if ([[UIApplication sharedApplication] canOpenURL:myURL_APP_A]) {
NSLog(@"canOpenURL");
[[UIApplication sharedApplication] openURL:myURL_APP_A];
}
自定义处理URL
有些时候我们除了启动还需向另外一个应用发送参数,这是也可以通过自定义的URL来实现,如:
testHello://
testHello://com.fcplayer.testHello
testHello://config=1&abar=2
这时我们在被启动应用中就必须进行自定义处理,在delegate中实现该消息(Cocos2d加在AppDelegate中),例如:
- (BOOL)application:(UIApplication *)applicationhandleOpenURL:(NSURL*)url { // Do something withthe url here }
通常,我们会从参数中解析出URL以便在视图中显示或者存储到UserPreference。下面的例子把URL存储为User Preference的url变量中或者打印出来:
[csharp]view plaincopy
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
if (!url) { return NO; }
NSString *URLString = [url absoluteString];
NSLog(@"%@",URLString);
//[[NSUserDefaults standardUserDefaults] setObject:URLString forKey:@"url"];
//[[NSUserDefaults standardUserDefaults] synchronize];
return YES;
}
其他
基本上至此我们就已经实现一个应用程序中启动另外一个应用的功能,但是为了是我们的代码更加强壮,我在网上又找了一段访问代码,如下:
[csharp]view plaincopy
// 检查用户是否配置了AppId
// 有没有准确配置Info的CFBundleURLSchemes字段
// 是不是可以正确打开
if (!kAppId) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Setup Error"
message:@"Missing app ID. You cannot run the app until you provide this in the code."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil,
nil];
[alertView show];
[alertView release];
} else {
// Now check that the URL scheme fb[app_id]://authorize is in the .plist and can
// be opened, doing a simple check without local app id factored in here
NSString *url = [NSString stringWithFormat:@"fb%@://authorize",kAppId];
BOOL bSchemeInPlist = NO; // find out if the sceme is in the plist file.
NSArray* aBundleURLTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
if ([aBundleURLTypes isKindOfClass:[NSArray class]] &&
([aBundleURLTypes count] > 0)) {
NSDictionary* aBundleURLTypes0 = [aBundleURLTypes objectAtIndex:0];
if ([aBundleURLTypes0 isKindOfClass:[NSDictionary class]]) {
NSArray* aBundleURLSchemes = [aBundleURLTypes0 objectForKey:@"CFBundleURLSchemes"];
if ([aBundleURLSchemes isKindOfClass:[NSArray class]] &&
([aBundleURLSchemes count] > 0)) {
NSString *scheme = [aBundleURLSchemes objectAtIndex:0];
if ([scheme isKindOfClass:[NSString class]] &&
[url hasPrefix:scheme]) {
bSchemeInPlist = YES;
}
}
}
}
// Check if the authorization callback will work
BOOL bCanOpenUrl = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString: url]];
if (!bSchemeInPlist || !bCanOpenUrl) {
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle:@"Setup Error"
message:@"Invalid or missing URL scheme. You cannot run the app until you set up a valid URL scheme in your .plist."
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil,
nil];
[alertView show];
[alertView release];
}
}
另外还有一段启动其他应用的代码:
[csharp]view plaincopy
-(IBAction)openMaps {//打开地图
// Where is Apple on the map anyway?
NSString* addressText = @”1 Infinite Loop, Cupertino, CA 95014″;
// URL encode the spaces
addressText = [addressText stringByAddingPercentEscapesUsingEncoding: NSASCIIStringEncoding];
NSString* urlText = [NSString stringWithFormat:@"http://maps.google.com/maps?q=%@", addressText];
// lets throw this text on the log so we can view the url in the event we have an issue
NSLog(urlText);
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:urlText]];
}
-(IBAction)openEmail {//打开mail
// Fire off an email to apple support
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"mailto://devprograms@apple.com"]];
}
-(IBAction)openPhone {//拨打电话
// Call Google 411
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel://8004664411"]];
}
-(IBAction)openSms {//打开短信
// Text to Google SMS
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"sms://466453"]];
}
-(IBAction)openBrowser {//打开浏览器
// Lanuch any iPhone developers fav site
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"http://itunesconnect.apple.com"]];
}
【iOS开发】-canOpenURL: failed for URL: "xx" - error:"This app is not allowed to query for scheme xx"
控制台输出如图是在我启动一个 Xcode 7 + iOS 9 的 App 之后,控制台的输出。
这在 Xcode 6.4 + iOS 8 时,是不会有的情况,原因是【为了强制增强数据访问安全, iOS9 默认会把所有从NSURLConnection、CFURL、NSURLSession发出的 HTTP 请求,都改为 HTTPS 请求:iOS9.x-SDK编译时,默认会让所有从NSURLConnection、CFURL、NSURLSession发出的 HTTP 请求统一采用 TLS 1.2(SSL 3.1) 协议。】
下面说解决方案:
①如果你的输出信息是-canOpenURL: failed for URL: "kindle://home" - error: "This app is not allowed to query for scheme kindle"
去你的 target 里面的 Build Settings 下的 Enable Bitcode,把它设置成 NO,这不一定会阻挡你的控制台继续输出这条信息,但是可以保证你的 App 正常运行。
②如果你的输出信息是 xxxx - error: "This app is not allowed to query for scheme xxxx"
(在这里因为我的 App 集成了分享到QQ、微信、微博的功能,xxxx部分我看到了 mqq、wechat、sinaweibosso 等多条信息)
info.plist去 Info.plist 里面建立一个叫 LSApplicationQueriesSchemes 的 Array,把你在xxxx部分看到的词汇一个一个填进去,直至控制台没有任何相关输出即可。
③关于其他通过 WebView 访问 http 网址引发的控制台报错信息
NSAppTransportSecurity
NSAllowsArbitraryLoads
如之前所说,Apple 希望我们访问相对安全的 HTTPS,所以在你需要访问 HTTP 时,
虽 Apple 不建议,但可通过在 Info.plist 中声明如上图所示的内容,倒退回不安全的网络请求,这样依然能让 App 访问指定 HTTP,甚至任意的 HTTP。