关于mac app在sandbox下运行时的XPC Service

前天的时候MDP申请下来了,所以昨天花了一天的时间准备将Sleep Screen提交到Mac Store学习一下整个流程。没想到昨天真的成了学习,围绕XPC Service捣鼓了整整一天,最后的结果是:加了sandbox以后Sleep Screen的两个功能无法正常运行,但是我想我不会因此给Sleep Screen判死刑,毕竟自已写的第一个Mac App我还会不断的完善她,让她更强大。虽然如此,对XPC Service算是小有心得了,由于这方面的中文资料几乎就是没有,特总结下来,给后面的人铺点路。
XPC Service是个什么东西呢?我的理解:如果你执行一个需要其它二进制程序来完成的东西,你就必需通过它。比如说:通NSTask执行系统命令或者要执行其它你自已写的随程序附带的命令行程序,当然这里的二进制也包含脚本,python,ruby神马的。
ok,接下两个学习资料:
官方的XPC资料:Creating XPC Services
官方的示例:SandboxedFetch
我承认昨天得有四五个小时浪费在看这个教程和这个示例上,然后尝试在自已写的程序中加入。在我最后跑通的时候,我突然找到一个开源库XPCKit,是对XPCService的封装,XPCKit允许你以更cocoa的方式创建服务端和客户端,在传递消息的时候可以使用字典,数组等对象(强大的一米),而且通过block回调,代码更简洁高效。所以,如果你是第一次学习XPC Service的话,苹果的学习资料看看就成了,具体实现还是建议用XPCKit。
ok,现在是XPCKit的使用方法了。虽然XPCKit很强大,但是按着官方的说明我把它加到自已的程序里还是走了一些弯路,所以记录一下我是怎么用XPCKit跑通的。
1.使用XPCServices,创建你的服务程序(不会搞的话还是看官方说明吧)
2.按照官方说明在主程序里添加Contents/XPCServices和Target Dependencies.
3.把XPCKit直接拖进主程序里,记得在弹出的对话框里把主程序和服务程序都添加上。
4.重点到了。
1).服务端程序,我的main.m里是这么写的。

//
//  main.m
//  sendnotify
//
//  Created by rainbird on 12-7-21.
//  Copyright (c) 2012年 chinakapalink@gmail.com. All rights reserved.
//

#import "XPCKit.h"
#include <Foundation/Foundation.h>
int main(int argc, const char *argv[]){
  //建立一个XPCService监听
  [XPCService runServiceWithConnectionHandler:^(XPCConnection *connection){
        [connection _sendLog:@"Multiply received a connection"];
        [connection setEventHandler:^(NSDictionary *message, XPCConnection *connection){
      //收到请求
            [connection _sendLog:[NSString stringWithFormat:@"Multiply received a message! %@", message]];
     
      //根据不同的类型处理
      if([[message objectForKey:@"operation"] isEqual:@"notify"]){
        //处理一些东西,然后通知成功
        [connection sendMessage:[NSDictionary dictionaryWithObject:@"notify oK!" forKey:@"notify"]];
            }
        }];
    }];
    return 0;
}

但是一直报错,说找不到xpc的类型啥的,这个小问题让我郁闷小半个小时。最后使出了看家本事,在服务端程序的Prefix.pch加入了一条:

//
// Prefix header for all source files of the 'sendnotify' target in the 'sendnotify' project
//

#include <xpc/xpc.h>

然后世界就清静了。
2).客户端程序,其实就是咱们的主程序。
首先引入:

#import "XPCKit.h"

然后加入了一个事件:

- (IBAction)goXPCService:(NSButton *)sender {
  //初始化一个XPC对象
  mathConnection = [[XPCConnection alloc] initWithServiceName:@"com.cnrainbird.mac.test"];
 
  //用来接收结果用的
  mathConnection.eventHandler = ^(NSDictionary *message, XPCConnection *inConnection){
    NSString *notify = [message objectForKey:@"notify"];
    if (notify) {
      NSLog(@"notify message%@",notify);
    }
  };
 
  //发起一请求
  [mathConnection sendMessage:[NSDictionary dictionaryWithObject:@"notify"
                                                          forKey:@"operation"]];
}

程序运行结果:

2012-07-22 11:31:49.251 TestXPCService[1431:2303] LOG: Multiply received a connection
2012-07-22 11:31:49.252 TestXPCService[1431:2303] LOG: Multiply received a message! {
    operation = notify;
}
2012-07-22 11:31:49.253 TestXPCService[1431:2303] notify messagenotify oK!

这里要说一条XPCKit很强大的地方就是输出日志,注意上面的:“LOG: ”,在使用苹果的官方库的时候你会发现用NSLog不会在Debug里输出东西!我在这个地方郁闷了很久,一直以为我写的服务端有问题,后来网上查了挺久资料才有人说可以在console.app里看到,之后调试的时候才算顺利,明白了过程是怎么跑的。所以就冲这个,强烈建议大家用XPCKit!
最后再说一句:用了XPCKit你会发现在sandbox中加入XPC Service简单的一米,苹果自已官方写东西的时候就不能再强大一点儿么?

附件:TestXPCService
我使用XPCKit示例工具,比官方那个要简单易懂一些。

    分享到:

About rainbird

IOS攻城狮
This entry was posted in Mac开发, object-c, 原创 and tagged , , , , , , , , . Bookmark the permalink.

4 Responses to 关于mac app在sandbox下运行时的XPC Service

  1. 老谭 says:

    你这样做还是绕不开沙盒的哇,如果需要发布,你的XPC也需要签名并沙盒的。

  2. 小丸 says:

    服务端是指python、ruby什么的程序吗?

    期待sleep screen早日上架!

发表评论