7

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

另一方面,我会有一个 Finder 同步扩展,它会显示同步状态图标覆盖。它还将有一个文件上下文菜单项“共享”,它将显示一个共享对话框,用户可以在其中选择与谁共享文件。

问题:

  1. FinderSyncExtension 和 MainApp 应该如何通信?是否应该使用 XCP,如果是,是否可以使用两种方式进行通信?例如 MainApp 通知 Finder 它应该刷新,因为一些文件已经同步,Finder 通知 MainApp 它应该执行“共享”操作。

  2. 谁应该展示“分享”对话框?单击 FinderSyncExtension 的“共享”菜单项时,应显示共享表单。这应该由 finder 扩展程序或 MainApp 显示(假设 FinderExtension 通知它单击了“共享”项)。

如果 Finder 扩展应该呈现表单,那么 FinderExtension 还应该从服务器检索数据(例如用于共享的联系人和组),我不确定 Finder 扩展是否应该对服务器执行任何网络调用。

研究这个话题,我发现了几种方法:

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

2 回答 2

7

我设法通过CFMessagePortAPI 做到了这一点。为了让沙盒扩展程序和主应用程序进行通信,需要在 Xcode 功能中启用 AppGroups。此外,需要使用带有后缀(由您选择)的 app-group 密钥作为消息端口标识符。

主应用

在主应用程序的某处,这种代码将侦听消息端口:

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");
}

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

于 2016-12-15T13:55:47.570 回答
0

关于沙盒马赫进程间通信的 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 信号量和共享内存名称必须以应用程序组标识符开头,后跟斜杠 (/),然后是您选择的名称。Mach 端口名称必须以应用程序组标识符开头,后跟句点 (.),然后是您选择的名称。

  • 例如,如果您的应用程序组的名称是Z123456789.com.example.app-group,您可能会创建两个名为Z123456789.myappgroup/rdyllwflg和的信号量Z123456789.myappgroup/bluwhtflg。您可以创建一个名为Z123456789.com.example.app-group.Port_of_Kobe.

注意:POSIX 信号量名称的最大长度只有 31 个字节,所以如果您需要使用 POSIX 信号量,您应该保持您的应用程序组名称简短。

于 2018-10-19T04:55:27.740 回答