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

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

问题:

  • FinderSyncExtension和MainApp应该如何通信?应该使用XCP吗?如果可以,双向通信是否可以?例如,MainApp通知Finder应该刷新,因为某些文件已经同步,而Finder通知MainApp它应该执行“共享”操作。
  • 谁应该显示“共享”对话框?单击FinderSyncExtension的“共享”菜单项时,应显示一个共享表单。应该通过finder扩展程序还是MainApp进行显示(假设FinderExtension通知它单击了“共享”项)。

  • 如果Finder Extension应该显示该表单,则FinderExtension也应该从服务器检索数据(例如用于共享的联系人和组),并且我不确定Finder Extension是否应该对服务器执行任何网络调用。

    研究该主题后,我发现了几种方法:
  • FinderSyncExtension和MainApp不直接通信。取而代之的是,FinderExtension从数据库读取数据以正确显示徽章。在这种情况下,不清楚同步完成后如何更新FinderExtension或如何通知MainApp执行某些操作。
  • XPC通讯。我猜FinderExtension可以启动对MainApp的调用,但是预期方向相反吗?
  • macOS进程之间是否存在某种NotificationCenter?我尝试使用NSWorkspace.sharedWorkspace.notificationCenterNSDistributedNotificationCenter.defaultCenter,但它们似乎未在MainApp中传递通知。
  • 像在Seafile项目中一样
  • mach_ports?
  • 最佳答案

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

    主要应用程式

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

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

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

    10-04 12:26