You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中如何为NSXPCInterface配置自定义类白名单

XPC 嵌套自定义类集合白名单 Swift 实现方案

问题根因

NSXPC 基于NSSecureCoding做跨进程序列化校验,默认仅解码显式加入白名单的类。当自定义类嵌套在NSArray/NSDictionary这类集合类型中传递时,即使外层自定义类实现了安全编码协议,集合内部的自定义类如果没有加入对应位置的解码白名单,就会触发解码失败,抛出你遇到的「允许类仅包含NSArray、unexpected class PartialSnapshot」类型的运行时错误。

正确的 NSXPCInterface 白名单配置

你之前的setClasses调用存在参数错误:该方法第一个参数需要传入对应参数位置允许解码的所有类组成的集合,第二个参数必须严格匹配协议定义的目标方法selector,不能传入无关类的selector。
正确的连接初始化配置代码如下:

let connection = NSXPCConnection(machServiceName: SecurityProxyConstants.domain, options: .privileged)
let xpcInterface = NSXPCInterface(with: SecurityProxyProtocol.self)

// 为回复块的第0位参数(即ReadAllSnapshotsRpcReturnType?)配置允许解码的类白名单
xpcInterface.setClasses(
    NSSet(array: [
        NSArray.self,
        ReadAllSnapshotsRpcReturnType.self,
        PartialSnapshot.self,
        NSString.self // Swift String桥接为Foundation的NSString,需加入白名单
    ]) as! Set<AnyHashable>,
    for: #selector(SecurityProxyProtocol.ReadAllSnapshotsRpc(then:)),
    argumentIndex: 0,
    ofReply: true
)

connection.remoteObjectInterface = xpcInterface

配置注意事项:

  • 传入的selector必须和协议中定义的方法完全匹配
  • 所有嵌套层级出现的类,包括集合类型、自定义类、Swift基础类型桥接的Foundation类(如String对应NSString、数值类型对应NSNumber)都要加入类集合,不能遗漏
  • 如果是方法入参(非回复块参数)包含嵌套自定义类的集合,将ofReply参数设为false,对应调整argumentIndex到参数的位置即可
  • 如果服务端侧也需要接收主应用传入的嵌套自定义类集合,需要对服务端的exportedInterface做完全一致的配置

修正自定义类的安全解码实现

你当前自定义类内的解码逻辑存在疏漏:调用decodeObject(of:)解码集合属性时,仅传入了NSArray.self,没有声明集合内部允许的类,即使接口层配置了白名单,类内部解码时依然会被安全校验拦截。
修正后的解码初始化代码:

// PartialSnapshot类的init?(coder:)实现
public required init?(coder: NSCoder) {
    guard
        let rawPaths = coder.decodeObject(of: [NSArray.self, NSString.self], forKey: "rawPaths") as? [String]
    else {
        NSLog("PartialSnapshot: returning nil from init?(coder: NSCoder)")
        return nil
    }
    self.rawPaths = rawPaths
}

// ReadAllSnapshotsRpcReturnType类的init?(coder:)实现
public required init?(coder: NSCoder) {
    guard
        let partials = coder.decodeObject(of: [NSArray.self, PartialSnapshot.self], forKey: "partials") as? [PartialSnapshot]
    else {
        NSLog("ReadAllSnapshotsRpcReturnType: returning nil from init?()")
        return nil
    }
    self.partials = partials
}

内容的提问来源于stack exchange,提问作者fsctl

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:15:41