23

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

我尝试过使用 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 不是这里交流的答案,那么我应该使用哪一个?请问有什么指点吗?

4

3 回答 3

20

好吧,对于任何一直在努力解决这个问题的人,我终于能够 100% 让两个应用程序进程之间的通信正常工作,使用NSXPCConnection

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

  1. 一个 XPC 服务。您可以严格通过名称连接到 XPCService
  2. 马赫服务。您还可以通过名称严格连接到 Mach 服务
  3. 一个NSXPCEndpoint。这就是我们正在寻找的,在两个应用程序进程之间进行通信。

问题是我们不能直接将NSXPCEndpoint一个应用程序从一个应用程序转移到另一个应用程序。

它涉及创建一个拥有属性的 machservice 启动代理(有关如何执行此操作,请参见此示例NSXPCEndpoint。一个应用程序可以连接到 machservice,并将该属性设置为它自己的[NSXPCListener anonymousListener].endpoint

然后其他应用程序可以连接到 machservice,并请求该端点。

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

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

我很高兴我得到了这个工作——我在 SO 中相当活跃,所以如果有人对源代码感兴趣,只需添加评论,我可以努力发布更多细节

我遇到的一些障碍:

你必须启动你的 machservice,这些是行:

   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

(当然,使用您相应的标识符)

于 2017-02-07T16:00:00.227 回答
11

如果您正在搜索如何在 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" )

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

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

在幕后,发生的事情的一个简化是您的代理会将您的 mach 服务注册到launchd. 当您的“客户端”想要连接到一个 mach 服务launchd时,它已经注册了它,因此它将在两者之间建立连接。

我希望这会有所帮助。

于 2019-11-30T12:28:12.230 回答
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

于 2015-07-30T01:19:09.150 回答