Finder Sync Extension和主应用程序应如何通信?

时间:2016-12-07 11:41:41

标签: synchronization nsnotifications xpc findersync

我的用例:我有一个' MainApp'它用于同步文件。 我希望那个' MainApp'处理有关同步和其他REST API调用的所有服务器调用,例如文档共享等。

另一方面,我会有一个Finder Sync Extension,它会显示同步状态图标叠加层。 它还有一个文件上下文菜单项'分享'这将显示一个“共享”对话框,用户可以选择与谁共享文件。

问题:

  1. FinderSyncExtension和MainApp应如何通信?应该使用XCP,如果是,那么通信是双向的吗?例如,MainApp通知Finder它应该刷新,因为一些文件已经同步,Finder通知MainApp它应该执行“共享”。操作

  2. 谁应该出席'分享'对话?当FinderSyncExtension'分享'单击菜单项,应显示共享表单。这应该由Finder扩展程序还是由MainApp显示(假设FinderExtension告知它已经点击了“共享项目”)。

  3. 如果Finder扩展程序应该显示表单,那么FinderExtension还应该从服务器检索数据(例如联系人和组以进行共享),并且我不确定Finder Extension是否应该对服务器执行任何网络调用。 / p>

    研究这个主题,我找到了几种方法:

    1. FinderSyncExtension和MainApp无法直接通信。相反,FinderExtension从数据库中读取数据以正确显示徽章。在这种情况下,目前还不清楚FinderExtension在同步完成时应该如何更新,或者它应该如何通知MainApp执行某些操作。
    2. XPC通讯。我猜FinderExtension可以启动对MainApp的调用,但预期方向相反吗?
    3. macOS进程之间是否存在某种NotificationCenter?我尝试使用NSWorkspace.sharedWorkspace.notificationCenterNSDistributedNotificationCenter.defaultCenter,但他们似乎无法在MainApp中发送通知。
    4. mach_ports和Seafile项目一样?

2 个答案:

答案 0 :(得分:5)

我设法通过CFMessagePort API执行此操作。为了使沙盒扩展和主应用程序进行通信,需要在Xcode功能中启用AppGroup。此外,需要将带有后缀的应用程序组密钥(根据您的选择)用作消息端口标识符。

主要应用

在主应用程序的某个地方,这种代码会监听消息端口:

CFMessagePortRef port = CFMessagePortCreateLocal(nil, CFSTR("group.com.yourapp.mach_or_something"), Callback, nil,
                                                 nil);
CFRunLoopSourceRef runLoopSource = CFMessagePortCreateRunLoopSource(nil, port, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);

Callback是一种实现方式:

static CFDataRef Callback(CFMessagePortRef port, SInt32 messageID, CFDataRef data, void* info)
{
    NSData* objcData = (__bridge NSData*) data;
    NSLog(@"Message received: %@", [NSString.alloc initWithData:objcData encoding:NSASCIIStringEncoding]);
    return data;
}

Finder同步扩展程序

然后,在扩展中的某个地方(即当用户点击菜单项时):

CFDataRef data = CFDataCreate(NULL, (const UInt8*) "somedata", 8);
SInt32 messageID = 0x1111; // Arbitrary
CFTimeInterval timeout = 1;

CFMessagePortRef remotePort = CFMessagePortCreateRemote(nil, CFSTR("group.com.yourapp.mach_or_something"));

SInt32 status = CFMessagePortSendRequest(remotePort, messageID, data, timeout, timeout, NULL, NULL);
if (status == kCFMessagePortSuccess)
{
    NSLog(@"SUCCESS STATUS");
}
else
{
    NSLog(@"FAIL STATUS");
}

这将向主应用程序发送消息。

答案 1 :(得分:0)

有关沙盒式Mach进程间通信的Apple文档:

https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW24

  

IPC和POSIX信号量和共享内存

     

通常,沙盒应用程序不能使用Mach IPC,POSIX信号和共享内存或UNIX域套接字(有用)。但是,通过指定请求应用程序组成员身份的权利,应用程序可以使用这些技术与该应用程序组的其他成员进行通信。

     

您希望在沙盒应用程序中访问的任何信号量或Mach端口必须根据特殊约定进行命名:

     
      
  • POSIX信号量和共享内存名称必须以应用程序组标识符开头,后跟斜杠(/),然后是您选择的名称。   马赫端口名称必须以应用程序组标识符开头,后跟一个句点(。),然后是您选择的名称。

  •   
  • 例如,如果您的应用程序组的名称为Z123456789.com.example.app-group,则可以创建两个名为Z123456789.myappgroup/rdyllwflgZ123456789.myappgroup/bluwhtflg的信号灯。您可以创建一个名为Z123456789.com.example.app-group.Port_of_Kobe的马赫端口。

  •   
     

注意:POSIX信号灯名称的最大长度仅为31个字节,因此,如果需要使用POSIX信号灯,则应使应用程序组名称简短。