使用 XPC 与另一个应用程序通信
Posted
技术标签:
【中文标题】使用 XPC 与另一个应用程序通信【英文标题】:Communicate with another app using XPC 【发布时间】:2014-07-25 07:11:49 【问题描述】:我有一个窗口应用程序,要添加一些功能,我需要另一个应用程序,它在登录时启动并将数据同步到服务器(如果可用)。
我尝试过使用 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 不是这里交流的答案,那么我应该使用哪一个?请大家指点一下?
【问题讨论】:
【参考方案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】:好吧,对于一直在努力解决这个问题的任何人,我终于能够 100% 使用 NSXPCConnection
在两个应用程序进程之间进行通信
要注意的关键是你只能为三个东西创建一个NSXPCConnection
。
-
XPC 服务。您可以通过严格连接到 XPCService
一个名字
马赫服务。您还可以连接到 Mach 服务
严格通过名字
NSXPCEndpoint
。这就是我们
寻找,在两个应用程序进程之间进行通信。
问题是我们不能直接将NSXPCEndpoint
从一个应用程序转移到另一个应用程序。
它涉及创建一个拥有 NSXPCEndpoint
属性的 machservice 启动代理 (See this example for how to do that)。一个应用程序可以连接到 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
(当然是你对应的标识符)
【讨论】:
如果有,请发布更多代码。需要在我自己的应用和使用我构建的 SDK 的其他应用之间进行通信。 您有什么问题?已经有一段时间了,很多地方都有代码,如果你能帮助进一步解释这个问题,我可以尝试为你发布更多相关的代码^ 这在生产应用中是否可行? 几年前我离开了公司,所以我不确定他们是否最终将其转移到生产中——我知道应用商店中的沙盒应用存在问题,其他人会必须回答这个问题:\或者你必须尝试一下 是的,任何人都想知道如何在沙盒应用中做到这一点,Apple 有这个演示:developer.apple.com/library/archive/samplecode/…【参考方案3】:如果您正在搜索如何在 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")
在幕后,简单来说,您的代理会将您的 mach 服务注册到 launchd
。当你的“客户端”想要连接到一个 mach 服务时,launchd
已经注册了它,所以它会在两者之间建立连接。
希望对你有帮助。
【讨论】:
我是 swift 新手,你能用 Objectvie c 制作吗以上是关于使用 XPC 与另一个应用程序通信的主要内容,如果未能解决你的问题,请参考以下文章