iOS进程间通信之CFMessagePort/还有 url schema

iOS进程间通信之CFMessagePort

JUN 4TH, 2014

iOS系统是出了名的封闭,每个应用的活动范围被严格地限制在各自的沙盒中。尽管如此,iOS还是提供了若干进程间通信机制,CFMessagePort就是其中之一。

从类名可以看出,CFMessagePort属于Core Foundation层的东西,其实现部分是开源的,代码在可以在苹果的开源代码库中找到。

使用方式

1、消息接收者

CFMessagePort端口消息的接收者需要实现以下功能:

1.1 注册监听

消息接收者需要通过以下方式注册消息监听:

1
2
3
4
5
6
7
8
9
10
11
-(void)startListenning
{
  if (0 != mMsgPortListenner && CFMessagePortIsValid(mMsgPortListenner))
  {
      CFMessagePortInvalidate(mMsgPortListenner);
  }
    mMsgPortListenner = CFMessagePortCreateLocal(kCFAllocatorDefault,CFSTR(LOCAL_MACH_PORT_NAME),onRecvMessageCallBack, NULL, NULL);
    CFRunLoopSourceRef source = CFMessagePortCreateRunLoopSource(kCFAllocatorDefault, mMsgPortListenner, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
    NSLog(@"start listenning");
}

其中LOCAL_MACH_PORT_NAME的定义为:

1
#define LOCAL_MACH_PORT_NAME    "com.wangzz.demo"

经过查看源码发现,CFMessagePort实际上是通过mach port实现的。Mach port是iOS系统提供的基于端口的输入源,可用于线程或进程间通讯。而Runloop支持的输入源类型中就包括基于端口的输入源,因此可以使用Runloop做为CFMessagePort端口源事件的监听者。

上述代码有几点需要说明:

  • 通过CFMessagePortCreateLocal可以创建一个本地CFMessagePortRef对象

  • CFMessagePort对象是靠一个字符串来唯一标识的,这一点非常重要,在这里字符串是由宏LOCAL_MACH_PORT_NAME定义的;

  • 创建CFMessagePort对象的同时设置了端口源事件的回调函数onRecvMessageCallBack,用于处理端口源事件;

  • 将创建的对象作为输入源添加到Runloop中,从而实现对端口源事件的监听,当Runloop收到对应的端口源事件时,会调用上一步中指定的回调芳芳;

1.2 实现回调方法

回调函数为CFMessagePortCallBack类型,其定义部分为:

1
2
3
4
5
6
typedef CFDataRef (*CFMessagePortCallBack) (
   CFMessagePortRef local,
   SInt32 msgid,
   CFDataRef data,
   void *info
);

各个参数的含义为:

  • CFMessagePortRef local

    当前接收消息的CFMessagePortRef对象。

  • SInt32 msgid

    这个字段非常有用,用于标识消息。如果通信双方进程约定号每个msgid对应的数据结构,即可实现较为复杂的通信。

  • CFDataRef data

    通信的真正数据部分。

  • void *info

    为使用CFMessagePortCreateLocal方法创建port端口时指定的CFMessagePortContext对象的info字段,通常为空。

该回调方法可以返回一个CFDataRef类型的数据给port消息的发送者,以实现有效的双方通信,这一点也非常重要。

我的回调函数onRecvMessageCallBack的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
CFDataRef onRecvMessageCallBack(CFMessagePortRef local,SInt32 msgid,CFDataRef cfData, void*info)
{
    NSLog(@"onRecvMessageCallBack is called");
    NSString *strData = nil;
    if (cfData)
    {
          const UInt8  * recvedMsg = CFDataGetBytePtr(cfData);
      strData = [NSString stringWithCString:(char *)recvedMsg encoding:NSUTF8StringEncoding];
        /**
         
         实现数据解析操作
         
         **/

        NSLog(@"receive message:%@",strData);
    }

    //为了测试,生成返回数据
    NSString *returnString = [NSString stringWithFormat:@"i have receive:%@",strData];
    const char* cStr = [returnString UTF8String];
  NSUInteger ulen = [returnString lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    CFDataRef sgReturn = CFDataCreate(NULL, (UInt8 *)cStr, ulen);

    return sgReturn;
}

该方法实现的较为简单,解析约定的数据(测试代码中约定传送的是string),为了测试,同时生成一个CFDataRef数据返回给port消息的发送者。

1.3 取消端口监听

可以通过如下方式取消对port端口的监听:

1
2
3
4
5
- (void)endLisenning
{
    CFMessagePortInvalidate(mMsgPortListenner);
    CFRelease(mMsgPortListenner);
}

CFMessagePortInvalidate会停止port消息的发送和接收操作,而只有调用了CFRelease,CFMessagePortRef对象才真正的被释放掉。

2、消息发送者

发送部分代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
-(NSString *)sendMessageToDameonWith:(id)msgInfo msgID:(NSInteger)msgid
{
    // 生成Remote port
    CFMessagePortRef bRemote = CFMessagePortCreateRemote(kCFAllocatorDefault, CFSTR(MACH_PORT_REMOTE));
    if (nil == bRemote) {
        NSLog(@"bRemote create failed");
        return nil;
    }

    // 构建发送数据(string)
    NSString    *msg = [NSString stringWithFormat:@"%@",msgInfo];
    NSLog(@"send msg is :%@",msg);
    const char *message = [msg UTF8String];
    CFDataRef data,recvData = nil;
    data = CFDataCreate(NULL, (UInt8 *)message, strlen(message));

    // 执行发送操作
    CFMessagePortSendRequest(bRemote, msgid, data, 0, 100 , kCFRunLoopDefaultMode, &recvData);
    if (nil == recvData) {
        NSLog(@"recvData date is nil.");
        CFRelease(data);
        CFMessagePortInvalidate(bRemote);
        CFRelease(bRemote);
        return nil;
    }

    // 解析返回数据
    const UInt8  * recvedMsg = CFDataGetBytePtr(recvData);
    if (nil == recvedMsg) {
        NSLog(@"receive date err.");
        CFRelease(data);
        CFMessagePortInvalidate(bRemote);
        CFRelease(bRemote);
        return nil;
    }

    NSString    *strMsg = [NSString stringWithCString:(char *)recvedMsg encoding:NSUTF8StringEncoding];
    NSLog(@"%@",strMsg);

    CFRelease(data);
    CFMessagePortInvalidate(bRemote);
    CFRelease(bRemote);
    CFRelease(recvData);

    return strMsg;
}

其中MACH_PORT_REMOTE的定义为:

1
#define MACH_PORT_REMOTE    "com.wangzz.demo"

发送消息时要相对简单,首先通过CFMessagePortCreateRemote生成一个Remote的CFMessagePortRef,这里需要注意的是CFMessagePortCreateRemote时传入的字符串唯一标识MACH_PORT_REMOTE必须和消息接收者创建local的CFMessagePortRef时使用的字符串唯一标识是同一个!

通过查看源码发现,CFMessagePortCreateRemote会根据MACH_PORT_REMOTE定义的字符串为唯一标识获取消息接收者通过CFMessagePortCreateLocal使用相同字符串创建的底层mach port端口,从而实现向消息接收者发送信息。

如果消息接收者还没有创建或者通过CFMessagePortCreateLocal创建local端口失败时,想要通过CFMessagePortCreateRemote去创建remote端口肯定是失败的。

说明

  • 很遗憾的是,在iOS7及以后系统中,CFMessagePort的通信机制不再可用。

在使用CFMessagePortCreateLocal/CFMessagePortCreateRemote创建CFMessagePortRef对象时会失败,官方文档中是这么说的:

1
This method is not available on iOS 7 and laterit will return NULL and log a sandbox violation in syslog. See Concurrency Programming Guide for possible replacement technologies.
  • CFMessagePort只能用于本地进程通信。

  • CFMessagePort是基于mach port端口的通信方式,不但可以用于进程通信,也可以用于线程间通信,只是线程间通信有了GCD和Cocoa提供的原生方法,已经能很方便的实现了,没必要再使用CFMessagePort。

  • 进程通信使用场景

iOS系统多任务机制,使得进程间通信基本都只能用于越狱开发。常用的场景是前端有一个UI程序用于界面展示,后端有一个daemo精灵程序用于任务处理。

demo工程

特地做了了个demo工程,以便更好地演示CFMessagePort的使用,可以到CSDN下载

为了模拟进程间通信场景,我将消息接收进程CFMessagePortReceive做成了能够后台播放音乐的程序,以便其切到后台后能继续存活。

由于CFMessagePort不再支持iOS7及以后系统,本demo实在iOS6系统上测试的。

demo使用方式:

  • CFMessagePortReceive启动后,点击Start Listenning创建CFMessagePort接口并开始监听port消息,然后将CFMessagePortReceive切到后台;

  • 启动CFMessagePortSend程序,在输入框中写入内容,点击发送按钮即可和CFMessagePortReceive通信。

  • MessagePort通信过程中会有日志输出,可以使用以下方式查看日志:

    1.真机

    选择:Xcode->Window->Organizer->Devices,然后选中窗口左侧当前设备的Console窗口查看。

    2.模拟器

    选择:模拟器->调试->打开系统日志,或者直接使用快捷键⌘/直接打开系统控制台查看日志。

参考文档


==================================================

一、注册自定义的URL Scheme

  首先我们在工程项目的Info.plist文件中添加以下信息。URL identifier一般推荐使用倒置域名方式以确保唯一性。而Scheme是一个数组,所以我们可以设置多个Scheme,之后我们会测试的。 
Info.plist配置1

当然我们可以看一些生成的源码。 
Info.plist配置2

1.1 URL Scheme启动应用初尝试

  通过上一步在Info.plist文件里配置了应用的URL Scheme之后,Build并Run一下应用。当应用被安装到模拟器上之后。我们则可以首先尝试用Safari来启动我们的应用了。

步骤: 
1. 运行以上应用。 
2. Shift+Command+H返回模拟器主界面。 
3. 然后打开Safari。 
4. 输入urlSchemeOne://,并点击确定。 
5. 就会弹出如下图,点击Open。然后我们的应用就打开了!

open url scheme

  有兴趣的童子试试urlSchemeTwo://也是可以打开应用的了,并且实际上URL Scheme是大小写不敏感的?= =因为我在safari中全输入的小谢也能打开。。。

1.2 在另一个app中启动自定义URL Scheme

  此时我们创建另一个工程,只需要实现一个功能,就是启动我们刚才设定了自定义URL Scheme的app。所以我们在里面设置了一个按钮。当我们点击该按钮时,则会触发打开URL Scheme的事件。首先我们来看一下代码的实现。

AppToOpenURLScheme

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">- (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">IBAction</span>)openUrlScheme:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)sender
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> *url = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> URLWithString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"urlSchemeOne://"</span>];

    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//先判断一下是否可以启动该url</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ([[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span> sharedApplication] canOpenURL:url]) {
        [[<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span> sharedApplication] openURL:url];
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">else</span>{
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"No such url."</span>);
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

1.3 解决问题-canOpenURL: failed for URL:XXX

  如果你是iOS 9.0以上的系统,当你运行上面的第二个工程后点击按钮,你应该会看到一串类似标题的异常输出,并且应用没有想期望的那样进行跳转。哈哈哈哈,这就是蛋疼的iOS 9.0以后的加入的新机制,我们应该还记得9.0同样限制了http请求,再次我们也需要像解除http请求一样在Info.plist中进行一些配置才行。 
下面这个应该是会出现的异常信息。(如果没有你就忽略吧…)

<code class="hljs mizar has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">2016-03-13 20:36:19.622 AppToOpenURLScheme[2637:1248171] -canOpenURL: failed <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> URL: "urlSchemeOne://" - error: "This app <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">is</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">not</span> allowed to query <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">scheme</span> urlSchemeOne"
2016-03-13 20:36:19.624 AppToOpenURLScheme[2637:1248171] No <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">such</span> url.</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

  通过我们查阅资料。我们发现传说有两种方式可以解除这个限制?= =。好吧说实话我两种都试了,但是有一个没弄出来。但是我还是介绍一下两种方法吧。

(1)第一种:支持http协议。额,这种方式我尝试了,没成功,如果有谁成功了记得教教我。。(后面我会贴上我查到的资料链接你们可以参考)这种方式就是在Info.plist中配置一下。

<code class="hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>NSAppTransportSecurity<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">dict</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>NSAllowsArbitraryLoads<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">true</span>/></span>
<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">dict</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

(2)第二种:配置scheme到LSApplicationQueriesSchemes。这种方式我是成功了的。下面介绍这种方法的配置方法。同样的是只需要配置Info.plist文件,而且是只需要在想要启动别人URL的app里设置就可以了!

PS:传说在模拟器下是会有问题,需要真机测试,我测试了真机上的确是正常的!!!

= =。比如说查到的资料,如果你是用了一些第三方SDK,一般都会要求在你自己的应用中配置别人的URL Scheme到LSApplicationQueriesSchemes中,这样你就能通过URL和别人的应用通信鸟~

AppToOpenURLScheme

<code class="hljs xml has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>LSApplicationQueriesSchemes<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">key</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">array</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">string</span>></span>urlSchemeOne<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">string</span>></span>
        <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"><<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">string</span>></span>urlSchemeTwo<span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">string</span>></span>
    <span class="hljs-tag" style="color: rgb(0, 102, 102); box-sizing: border-box;"></<span class="hljs-title" style="box-sizing: border-box; color: rgb(0, 0, 136);">array</span>></span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>

进过以上配置之后,我们再次安装应用并点击按钮,应该就可以进行跳转了!

参考资料:适配ios9出现的问题:-canOpenURL: failed for URL

二、进程间数据传输

  我们之前讲了这么多最终的目标是什么!!!通信啊!!!传数据啊!!!= =。在这里就科普一个啥URL标准(虽然我也没看过),传说URL传递参数需要遵循RFC 1808标准。话不多说,我们开始吧!

  首先我们先实现接受数据的一端的方法。所以我们需要先返回先前创建了URL Scheme的应用中,在appDelegate.m文件中重写这两个方法。这些方法是在当有别的应用通过URL Scheme的方式启动时会调用的方法。

URLSchemaDemon

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//实际过程中这个函数没被调用?- -。一脸懵逼。。。</span>
-(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">BOOL</span>)application:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span> *)application handleOpenURL:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> *)url
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@ %@"</span>, NSStringFromSelector(_cmd), url);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>;
}

-(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">BOOL</span>)application:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span> *)application
           openURL:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> *)url
 sourceApplication:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *)sourceApplication
        annotation:(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>)annotation
{
    <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@ %@"</span>, sourceApplication, url);
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ([[url scheme] isEqualToString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"urlSchemeOne"</span>]) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@ %@"</span>, [url scheme], [url query]);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li></ul>

  解决了接收端的问题后,我们来看发送数据的一方。我们只需要做一些小修改,将数据放在URL中进行传递就好了,当然实际中传递数据时是会对数据进行加密的。因为不排除有同名的URL Scheme的存在,这样可能会拦截传递的数据?然后导致数据泄露?

AppToOpenURLScheme

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> *url = [<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> URLWithString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"urlSchemeOne://?token=123456&id=10086"</span>];</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

  然后我们重新编译运行应用,然后通过另一个应用打开该应用。则会看到如下输出信息。哈哈哈我们可以很清楚的看到通过URL传递的数据正确传递过来了~耶耶耶~对于sourceApplication参数我们一般可以用来限制只有特定的app启动我们应用时才做处理,因为我们无法限制被别的应用调用。

<code class="hljs avrasm has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2016</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">03</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">21</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">25</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13.915</span> URLSchemaDemon[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2675</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1257006</span>] <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">com</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.lysongzi</span><span class="hljs-preprocessor" style="color: rgb(68, 68, 68); box-sizing: border-box;">.AppToOpenURLScheme</span> urlSchemeOne://?token=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">123456</span>&id=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10086</span>
<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2016</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">03</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">21</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">25</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">13.920</span> URLSchemaDemon[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2675</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1257006</span>] urlSchemeOne token=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">123456</span>&id=<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10086</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>

  如果你是基于iOS 9.0进行开发的话,你会发现handleOpenURLopenURL:sourceApplication:annotation:两个方法在iOS 9.0以后官方已经不推荐使用了,转而推荐使用的则是这个方法“。

<code class="hljs objectivec has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">-(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">BOOL</span>)application:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">UIApplication</span> *)app openURL:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSURL</span> *)url options:(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSDictionary</span><<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSString</span> *,<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">id</span>> *)options
{
    <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//可以通过option字典对象取出相应数据</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> ([[options objectForKey:UIApplicationOpenURLOptionsSourceApplicationKey] isEqualToString:@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"com.lysongzi.AppToOpenURLScheme"</span>]) {
        <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">NSLog</span>(@<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"%@ %@"</span>, [url scheme], [url query]);
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> <span class="hljs-literal" style="color: rgb(0, 102, 102); box-sizing: border-box;">YES</span>;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li></li></ul>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值