使用XPC与另一个应用程序通信

时间:2014-06-04 14:52:22

标签: macos cocoa helper xpc

我有一个窗口应用,并且为了添加一些功能,我需要另一个应用程序,该应用程序在登录时启动并将数据同步到服务器(如果可用)。

我尝试过使用NSDistributionNotification,但它在沙盒应用程序中几乎没用。我查了一下XPC,希望它可以工作,但我不知道如何让它与助手一起工作。到目前为止,我已经使用XPC做到了这一点。

主要应用

    NSXPCInterface *remoteInterface = [NSXPCInterface interfaceWithProtocol:@protocol(AddProtocol)];
    NSXPCConnection *xpcConnection = [[NSXPCConnection alloc] initWithServiceName:@"com.example.SampleService"];

    xpcConnection.remoteObjectInterface = remoteInterface;

    xpcConnection.interruptionHandler = ^{
        NSLog(@"Connection Terminated");
    };

    xpcConnection.invalidationHandler = ^{
        NSLog(@"Connection Invalidated");
    };

    [xpcConnection resume];

    NSInteger num1 = [_number1Input.stringValue integerValue];
    NSInteger num2 = [_number2Input.stringValue integerValue];

    [xpcConnection.remoteObjectProxy add:num1 to:num2 reply:^(NSInteger result) {
        NSLog(@"Result of %d + %d = %d", (int) num1, (int) num2, (int) result);
    }];

XPC服务

In main () ...
SampleListener *delegate = [[SampleListener alloc] init];
NSXPCListener *listener = [NSXPCListener serviceListener];
listener.delegate = delegate;
[listener resume];

// In delegate
-(BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
    NSXPCInterface *interface = [NSXPCInterface interfaceWithProtocol:@protocol(AddProtocol)];
    newConnection.exportedInterface = interface;
    newConnection.exportedObject = [[SampleObject alloc] init];
    [newConnection resume];
    return YES;
}

// In Exported Object class

-(void)add:(NSInteger)num1 to:(NSInteger)num2 reply:(void (^)(NSInteger))respondBack {
    resultOfAddition = num1 + num2;
    respondBack(resultOfAddition);
}

这很好用,现在我需要将此结果传递给Helper应用程序。我怎样才能做到这一点 ?如果XPC不是通信的答案,那么我应该使用哪一个?有什么指示吗?

3 个答案:

答案 0 :(得分:11)

对于一直在努力解决这个问题的人,我终于能够100%使用NSXPCConnection

在两个应用程序进程之间进行通信

需要注意的关键是,您只能创建NSXPCConnection到三件事。

  1. XPCService。您可以严格连接到XPCService 一个名字
  2. 马赫服务。您还可以连接到Mach服务 严格通过名称
  3. NSXPCEndpoint。这就是我们的意思 寻找,在两个申请流程之间进行沟通。
  4. 问题在于我们无法直接将NSXPCEndpoint从一个应用程序转移到另一个应用程序。

    它涉及创建一个拥有NSXPCEndpoint属性的machservice Launch Agent(See this example for how to do that)。一个应用程序可以连接到machservice,并将该属性设置为它自己的[NSXPCListener anonymousListener].endpoint

    然后另一个应用程序可以连接到machservice,并要求该端点。

    然后使用该端点,可以创建NSXPCConnection,从而成功建立了两个应用程序之间的桥梁。我测试了来回发送对象,这一切都按预期工作。

    请注意,如果您的应用程序是沙盒,那么必须创建XPCService,作为应用程序和Machservice之间的中间人

    我很高兴我的工作 - 我在SO中相当活跃,所以如果有人对源代码感兴趣,只需添加评论,我就可以通过努力发布更多细节

    我遇到了一些障碍:

    你必须启动你的机器服务,这些是以下几行:

       OSStatus                    err;
       AuthorizationExternalForm   extForm;
    
       err = AuthorizationCreate(NULL, NULL, 0, &self->_authRef);
       if (err == errAuthorizationSuccess) {
          NSLog(@"SUCCESS AUTHORIZING DAEMON");
       }
       assert(err == errAuthorizationSuccess);
    
       Boolean             success;
       CFErrorRef          error;
    
       success = SMJobBless(
                            kSMDomainSystemLaunchd,
                            CFSTR("DAEMON IDENTIFIER HERE"),
                            self->_authRef,
                            &error
                            );
    

    此外,每次重建守护程序时,都必须使用以下bash命令卸载以前的启动代理程序:

    sudo launchctl unload /Library/LaunchDaemons/com.example.apple-samplecode.EBAS.HelperTool.plist
    sudo rm /Library/LaunchDaemons/com.example.apple-samplecode.EBAS.HelperTool.plist
    sudo rm /Library/PrivilegedHelperTools/com.example.apple-samplecode.EBAS.HelperTool
    

    (当然还有相应的标识符)

答案 1 :(得分:1)

我想我想出了如何做到这一点。您所要做的就是在Xcode中创建一个命令行帮助工具,将其安装为Launchd作业(根据权限要求,可以是守护程序或代理程序)。您可以使用定义的协议与帮助工具进行通信。请参阅Apple的以下示例代码,了解它是如何完成的。

Apple的示例代码: https://developer.apple.com/library/mac/samplecode/EvenBetterAuthorizationSample/Listings/Read_Me_About_EvenBetterAuthorizationSample_txt.html#//apple_ref/doc/uid/DTS40013768-Read_Me_About_EvenBetterAuthorizationSample_txt-DontLinkElementID_17

阅读以下链接,了解您真正想要的内容,守护程序或代理: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/DesigningDaemons.html#//apple_ref/doc/uid/10000172i-SW4-BBCBHBFB

答案 2 :(得分:0)

如果您正在寻找如何在Swift中完成此任务。我编写了有关如何执行此操作的教程:

https://rderik.com/blog/creating-a-launch-agent-that-provides-an-xpc-service-on-macos/

您必须首先创建一个公开XPC服务的启动代理(或守护程序,如果需要更多特权)。 XPC服务将注册为您的代理提供的mach服务。因此,您的代理将必须创建一个如下所示的侦听器:

let listener = NSXPCListener(machServiceName: "com.rderik.exampleXPC" )

要从其他客户端使用该服务,您需要为该mach服务创建一个NSXPCConnection。像这样:

let connection = NSXPCConnection(machServiceName: "com.rderik.exampleXPC")

在幕后,所发生事情的一种简化是,您的代理将您的马赫服务注册到launchd。当您的“客户端”想要连接到马赫服务launchd时,已经对其进行了注册,因此它将建立两者之间的连接。

我希望有帮助。