可以将pyobjc与特权XPC帮助程序工具和XPCInterface API一起使用吗?

时间:2018-09-11 20:56:10

标签: macos cocoa pyobjc xpc nsxpcconnection

我相信这个问题的答案是“否”,但我将其发布给社区,以防万一有人比我更成功。

我有一个特权的帮助程序工具,客户端可可应用程序将其与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 *框架方法调用不支持块,而'custom'(即用户定义)方法不支持块?请注意,如果这是唯一的阻塞问题,那么我可以制作一个没有返回代码的方法版本,但是尝试并没有成功,因为...

2)为了以Objective-C的方式使用API​​,我需要创建对runCommand的@selector引用:实际上没有任何python函数实现-它只需要是一个定义了函数的对象动态创建的remoteProxy将提供的功能的签名。我没有在python中定义remoteProxy实现。似乎不支持此功能-如果没有python函数通过objc.selector()工作,我将无法获得选择器声明。

3)我不是很肯定即使我可以工作2),正式协议的构造也可以按预期的方式作为interfaceWithProtocol的参数来工作:来自python-它需要成为本机自定义NSXPCInterface可以在其工厂方法中使用的@protocol来创建remoteProxy。

如果您已经找到了如何在pyobjc中执行此操作的方法,则需要任何提示,或者根据您的知识确定是否确实无法使用此方法。

1 个答案:

答案 0 :(得分:1)

前两个子问题很容易回答:可以使用带有块的API来调用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一起使用。

P.S。我很少访问stackoverflow,通常可以通过发送至pyobjc-dev@lists.sourceforge.net(PyObjC邮件列表)来吸引注意力。