如何允许我的 Xcode 源代码编辑器扩展使用 XPC?

How do I allow my Xcode Source Editor Extension to use XPC?

在这篇关于 Xcode 源代码编辑器扩展的文章中,它提到 XPC 是一种绕过应用程序沙箱的方法:

The extension must be sandboxed just to be loaded by Xcode, whereas calls to SourceKit needs to be un-sandboxed, which of course won’t fly in the App Store. We could distribute independently and use an un-sandboxed XPC service embedded in the extension.

但是,我不确定如何将所有内容结合在一起以使用 XPC 服务。

如何将我的 Xcode 源代码编辑器扩展绑定到 XPC 服务?

感谢 LinuxSupportForXcode extension

我能够解决这个问题

我将假设您遵循 tutorial on creating an Xcode Extension Editor,并将主项目设为 macOS 应用程序。您的目标结构应该类似于:

  • MyApp(macOS 应用目标)
  • MyAppExtension(Xcode 源代码编辑器扩展目标)

将 XPC 与源代码编辑器扩展一起使用:

  1. 文件 > 新建 > 目标... > XPC 服务。

    为了示例目的,我们假设它被称为 MyAppXPCService 并且它的包标识符是 com.example.MyAppXPCService.

  2. 将XPC服务依赖从App移至Extension:

    如果不执行此步骤,您可能会 运行 遇到扩展程序未执行 XPCService 的问题。例如。您调用了一个应该启动 XPCService 的命令,但是在 Xcode Debug Navigator 中,您的 XPCService 永远不会出现。

    1. 转到您应用的目标。
    2. 从框架和库中删除 MyAppXPCService.xpc。
    3. 转到您的扩展目标。
    4. 将 MyAppXPCService.xpc 添加到 Frameworks and Libraries,方法是从项目导航器的产品文件夹中将其拖入。保留默认的“不签名嵌入”。
  3. 在XPC Service中,转换为Swift,mainly following the instructions here:

    注意: 如果您不想转换为 Swift,而是使用混合目标,只需创建一个 Swift 文件,然后根据提示,选择创建桥接 header,然后在桥接 header.

    中包含 #import "MyAppXPCServiceProtocol.h"
    1. 正常创建main.swiftMyService.swiftMyServiceDelegate.swiftMyServiceProtocol.swift

    2. 设置以下构建设置:

      • 安装Objective-C兼容性HeaderNO
      • Objective-C 生成的接口 Header 名称: ``(空白)
    3. 在构建设置中选择您想要的Swift语言版本

    4. 在构建设置中,添加(不要替换):@loader_path/../../../../Frameworks运行时搜索路径.

      如果您不小心替换,并使用embedded framework, XPC will crash on launch.

  4. 在您的扩展目标中:

    1. import MyAppXPCService 以便它可以看到协议。

    2. 创建连接,使用 XPC 目标的包标识符 serviceName:

      private let connection = { () -> NSXPCConnection in
        let connection = NSXPCConnection(serviceName: <#"com.example.MyAppXPCService"#>)
        connection.remoteObjectInterface = NSXPCInterface(with: MyAppXPCServiceProtocol.self)
        return connection
      }()
      
    3. 调用您的 XPC 服务:

      private func xpcUpperCase(input: String) {
        connection.resume()
        defer { connection.suspend() }
        guard let xpcService = connection.remoteObjectProxy as? MyAppXPCServiceProtocol else {
          throw NSError()
        }
      
        xpcService.upperCaseString(input) { output in
          print(output)
        }
      }
      

创建连接的好处是它会自动启动您的 XPC 服务,而不需要 UI 应用 运行ning。