iOS平台的进程间通信是一件很蛋疼的事,通过窝大量的资料搜索,最后发现好像比较普遍的实现方式则是使用URL Scheme(好吧好像别的方式我还没搞懂,准备看英文文献学习学习先哈哈哈哈哈)。
URL Scheme就是将一个应用自身“绑定”到一个自定义的URL上,该Scheme可以用于在浏览器或别的应用中启动。PS:一个应用是可以自定义多个URL Scheme的。
首先我们在工程项目的Info.plist文件中添加以下信息。URL identifier
一般推荐使用倒置域名方式以确保唯一性。而Scheme是一个数组,所以我们可以设置多个Scheme,之后我们会测试的。
通过上一步在Info.plist文件里配置了应用的URL Scheme之后,Build并Run一下应用。当应用被安装到模拟器上之后。我们则可以首先尝试用Safari来启动我们的应用了。
步骤:
1. 运行以上应用。
2. Shift+Command+H返回模拟器主界面。
3. 然后打开Safari。
4. 输入urlSchemeOne://
,并点击确定。
5. 就会弹出如下图,点击Open。然后我们的应用就打开了!
有兴趣的童子试试urlSchemeTwo://
也是可以打开应用的了,并且实际上URL Scheme是大小写不敏感的?= =因为我在safari中全输入的小谢也能打开。。。
此时我们创建另一个工程,只需要实现一个功能,就是启动我们刚才设定了自定义URL Scheme的app。所以我们在里面设置了一个按钮。当我们点击该按钮时,则会触发打开URL Scheme的事件。首先我们来看一下代码的实现。
AppToOpenURLScheme
- (IBAction)openUrlScheme:(id)sender
{
NSURL *url = [NSURL URLWithString:@"urlSchemeOne://"];
//先判断一下是否可以启动该url
if ([[UIApplication sharedApplication] canOpenURL:url]) {
[[UIApplication sharedApplication] openURL:url];
}
else{
NSLog(@"No such url.");
}
}
如果你是iOS 9.0以上的系统,当你运行上面的第二个工程后点击按钮,你应该会看到一串类似标题的异常输出,并且应用没有想期望的那样进行跳转。哈哈哈哈,这就是蛋疼的iOS 9.0以后的加入的新机制,我们应该还记得9.0同样限制了http请求,再次我们也需要像解除http请求一样在Info.plist中进行一些配置才行。
下面这个应该是会出现的异常信息。(如果没有你就忽略吧…)
2016-03-13 20:36:19.622 AppToOpenURLScheme[2637:1248171] -canOpenURL: failed for URL: "urlSchemeOne://" - error: "This app is not allowed to query for scheme urlSchemeOne"
2016-03-13 20:36:19.624 AppToOpenURLScheme[2637:1248171] No such url.
通过我们查阅资料。我们发现传说有两种方式可以解除这个限制?= =。好吧说实话我两种都试了,但是有一个没弄出来。但是我还是介绍一下两种方法吧。
(1)第一种:支持http协议。额,这种方式我尝试了,没成功,如果有谁成功了记得教教我。。(后面我会贴上我查到的资料链接你们可以参考)这种方式就是在Info.plist中配置一下。
<key>NSAppTransportSecuritykey>
<dict>
<key>NSAllowsArbitraryLoadskey>
<true/>
dict>
(2)第二种:配置scheme到LSApplicationQueriesSchemes。这种方式我是成功了的。下面介绍这种方法的配置方法。同样的是只需要配置Info.plist文件,而且是只需要在想要启动别人URL的app里设置就可以了!
PS:传说在模拟器下是会有问题,需要真机测试,我测试了真机上的确是正常的!!!
= =。比如说查到的资料,如果你是用了一些第三方SDK,一般都会要求在你自己的应用中配置别人的URL Scheme到LSApplicationQueriesSchemes中,这样你就能通过URL和别人的应用通信鸟~
AppToOpenURLScheme
<key>LSApplicationQueriesSchemeskey>
<array>
<string>urlSchemeOnestring>
<string>urlSchemeTwostring>
array>
进过以上配置之后,我们再次安装应用并点击按钮,应该就可以进行跳转了!
参考资料:适配ios9出现的问题:-canOpenURL: failed for URL
我们之前讲了这么多最终的目标是什么!!!通信啊!!!传数据啊!!!= =。在这里就科普一个啥URL标准(虽然我也没看过),传说URL传递参数需要遵循RFC 1808标准。话不多说,我们开始吧!
首先我们先实现接受数据的一端的方法。所以我们需要先返回先前创建了URL Scheme的应用中,在appDelegate.m文件中重写这两个方法。这些方法是在当有别的应用通过URL Scheme的方式启动时会调用的方法。
URLSchemaDemon
//实际过程中这个函数没被调用?- -。一脸懵逼。。。
-(BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url
{
NSLog(@"%@ %@", NSStringFromSelector(_cmd), url);
return YES;
}
-(BOOL)application:(UIApplication *)application
openURL:(NSURL *)url
sourceApplication:(NSString *)sourceApplication
annotation:(id)annotation
{
NSLog(@"%@ %@", sourceApplication, url);
if ([[url scheme] isEqualToString:@"urlSchemeOne"]) {
NSLog(@"%@ %@", [url scheme], [url query]);
}
return YES;
}
解决了接收端的问题后,我们来看发送数据的一方。我们只需要做一些小修改,将数据放在URL中进行传递就好了,当然实际中传递数据时是会对数据进行加密的。因为不排除有同名的URL Scheme的存在,这样可能会拦截传递的数据?然后导致数据泄露?
AppToOpenURLScheme
NSURL *url = [NSURL URLWithString:@"urlSchemeOne://?token=123456&id=10086"];
然后我们重新编译运行应用,然后通过另一个应用打开该应用。则会看到如下输出信息。哈哈哈我们可以很清楚的看到通过URL传递的数据正确传递过来了~耶耶耶~对于sourceApplication参数我们一般可以用来限制只有特定的app启动我们应用时才做处理,因为我们无法限制被别的应用调用。
2016-03-13 21:25:13.915 URLSchemaDemon[2675:1257006] com.lysongzi.AppToOpenURLScheme urlSchemeOne://?token=123456&id=10086
2016-03-13 21:25:13.920 URLSchemaDemon[2675:1257006] urlSchemeOne token=123456&id=10086
如果你是基于iOS 9.0进行开发的话,你会发现handleOpenURL
和openURL:sourceApplication:annotation:
两个方法在iOS 9.0以后官方已经不推荐使用了,转而推荐使用的则是这个方法“。
-(BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString *,id> *)options
{
//可以通过option字典对象取出相应数据
if ([[options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey] isEqualToString:@"com.lysongzi.AppToOpenURLScheme"]) {
NSLog(@"%@ %@", [url scheme], [url query]);
}
return YES;
}
我们会发现实际上也是可以正确获取到传递过来的数据的鸟~~~
这里主要涉及了两个工程项目。
1. 创建自定义的URL Scheme以及接受数据的工程:URLSchemaDemon
2. 通过URL Scheme打开另一个应用,并传递数据:AppToOpenURLScheme