macos - 是否可以将 pyobjc 与私有的 XPC 帮助工具和 XPCInterface API 一起使用?
问题描述
我相信这个问题的答案是“不”,但我将它发布给社区以防万一有人比我更成功。
我有一个特权帮助工具,客户端 Cocoa 应用程序与 NSXPCConnection 和 NSXPCInterface 一起使用。接口本身包括一个通过完成处理程序块提供返回码的方法。
在 Objective-C 中,客户端代码如下所示:
NSXPCConnection * xpcConn = [NSXPCConnection alloc]
initWithMachServiceName:kSvcName
options:NSXPCConnectionPrivileged];
// MyProtocol defines an instance method runCommand:(NSString*) withReply:^(int result)
NSXPCInterface * mySvcIF = [NSXPCInterface interfaceWithProtocol:@protocol(MyProtocol)];
xpcConn.remoteObjectInterface = mySvcIF;
[xpcConn resume];
if (nil == xpcConn.remoteObjectProxy) {
NSLog(@"ERROR - remote interface is nil, can't communicate with service");
}
[[xpcConn remoteObjectProxy] runCommand:nsstrCmd withReply:^(int result) {
NSLog(@"service result is: %d", result);
if (result != 0) {
self.svcResult = result;
self.svcCommandComplete = YES;
}
}];
我还有一个 pyobjc / py2app Mac 应用程序需要使用这个帮助工具的功能。我已经将该工具内置到 pyobjc 应用程序包中,通过 SMJobBless 进行签名和授权,但看起来有几个问题使实际使用此 API 不受支持:
1) 似乎不支持桥接 runCommand:withReply:^ 的调用 - 如果我理解正确,块仅支持 NS* 框架方法调用而不是“自定义”(即用户定义)方法?请注意,如果这是唯一的阻塞问题,我可以制作没有返回码的方法版本,但尝试并没有成功,因为......
2)为了以Objective-C的方式使用API,我需要创建一个@selector对runCommand的引用:它实际上没有任何python函数实现——它只需要一个定义签名的函数对象将由动态创建的 remoteProxy 提供的功能。我没有在 python 中定义 remoteProxy 实现。这似乎不受支持 - 如果没有 python 函数,我无法通过 objc.selector() 获得选择器声明。
3) 我不确定即使我可以让 2) 工作,正式协议的构造也会按照预期的方式工作,作为 interfaceWithProtocol: 的参数,来自 python - 它需要成为原生自定义 @protocol NSXPCInterface 可以在其工厂方法中使用来创建 remoteProxy。
感谢您提供任何提示,如果您已经知道如何在 pyobjc 中执行此操作,或者根据您对它的了解,任何明确的确认这些东西是不可能的。
解决方案
前两个子问题很容易回答:可以使用块调用 API,即使是那些在非 Apple 框架的库中的 API。这确实需要在 python 代码中做更多的工作,因为 Objective-C 运行时没有公开足够的信息来完全自动地做正确的事情。
对于这个特定的示例,您可以执行以下操作:
objc.registerMetaDataForSelector(b'NSObject', b'runCommand:withReply:', {
'arguments': {
3: {
'callable': {
'retval': {'type': b'@'},
'arguments': {
0: {'type': b'^v'},
1: {'type': b'i'},
},
},
}
}
})
这为方法“-[NSObject runCommand:withReply:]”注册了附加信息。block 参数是数字 3:计数从 0 开始,Objective-C 方法的前两个参数是“self”和“_sel”(后者不暴露给 Python)。
您通常使用实现该方法的实际类,但我希望这是一个甚至可能动态生成的隐藏类。只要不与其他类发生冲突,只需在 NSObject 上注册元数据就应该是安全的。
在 Python 中创建协议也是可能的:
MyProtocol = objc.formal_protocol('MyProtocol', (), [
objc.selector(None, b"runCommand:withReply:", signature=b"v@:@@?"),
])
并使用以下命令创建 XPC 接口:
mySvcIF = Foundation.NSXPCInterface.interfaceWithProtocol_(MyProtocol)
遗憾的是,后一步不起作用,因为 NSXPCInterface 引发了异常:NSInvalidArgumentException - NSXPCInterface: Unable to get extended method signature from Protocol data (MyProtocol / runCommand:withReply:). Use of clang is required for NSXPCInterface.
.
我在 PyObjC 的跟踪器中为此提出了一个问题:https ://bitbucket.org/ronaldoussoren/pyobjc/issues/256/enable-using-xpcinterface-with-protocols 。
此问题的解决方法是创建一个 Python 扩展,其中包含协议定义以及使用该协议的未使用函数(参见例如https://bitbucket.org/ronaldoussoren/pyobjc/src/default/pyobjc-framework- Cocoa/Modules/_AppKit_protocols.m用于后半部分)。导入扩展后,您可以使用它objc.protocolNamed("MyProtocol")
来访问协议,然后它将引用由 clang 创建的完整协议对象,并且应该与 NSXPCInterface 一起使用。
PS我很少访问stackoverflow,通过邮寄到pyobjc-dev@lists.sourceforge.net(PyObjC邮件列表)通常更容易引起我的注意。
推荐阅读
- python - FailedPreconditionError: 发现 2 个根错误
- javascript - 无法播放音频
- html - 更改 div 内容
- c# - 即使 Firefox 未打开,Firefox cookies.sqlite 文件是否也有锁定?
- php - 注册时如何在wordpress中添加多个角色
- javascript - 未捕获的类型错误:无法设置未定义、vue.js、diff-match-patch、veu-diff-match-patch 的属性“diff_match_patch”
- json - 在 Docker Windows 上的 Keycloak 中添加领域时出现意外的服务器错误
- date - MySQL按时间戳差异分组
- kubernetes - 分析 kubernetes pod 网络流量
- android - iPhone 屏幕 DPI 等效于 Android 分辨率