macOS 13 Focus系统扩展perform()函数未执行及功能疑问
Focus系统扩展perform()函数问题排查与功能说明
一、perform()函数未执行的排查方案
- 检查Info.plist配置
确认NSExtension字典内的关键配置:NSExtensionPointIdentifier必须设为com.apple.focus-filter- 如果关联特定专注模式,
NSExtensionAttributes下的FocusBundleIdentifiers或FocusFilterModeIdentifiers要和目标模式的ID完全匹配,自定义模式需确保ID一致。
- 验证沙箱权限
沙箱化扩展需配置必要权限:- 确保
com.apple.security.app-sandbox设为YES - 添加
com.apple.security.temporary-exception.apple-events权限并包含com.apple.systempreferences,保证扩展能响应系统专注状态变更。
- 确保
- 核对方法签名
perform()必须是异步方法且返回正确类型,签名错误会导致系统不调用:override func perform(context: FocusFilterContext) async -> FocusFilterResult { // 业务逻辑 return .allow } - 更换调试方式
NSLog和NSSound在系统扩展环境中无法正常工作,改用os_log输出日志,在Console.app中通过子系统和类别过滤查看:import os.log private let logger = OSLog(subsystem: "com.yourteam.yourextension", category: "FocusFilter") override func perform(context: FocusFilterContext) async -> FocusFilterResult { os_log("perform() triggered", log: logger, type: .info) return .allow }
二、perform()函数的功能范围与实践示例
核心功能定位
perform()是Focus扩展的核心回调,当关联的专注模式激活、变更时触发,主要用于实现内容过滤逻辑(比如拦截通知、调整应用显示内容),通过返回.allow或.deny控制内容是否放行。
写入文件的实现
沙箱化扩展仅能写入自身容器目录或用户授权的路径,通过应用组可与宿主应用共享文件:
// 需先配置应用组权限(com.apple.security.application-groups) let groupContainerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.yourteam.yourapp")! let logFileURL = groupContainerURL.appendingPathComponent("focus_log.txt") try "Focus mode activated: \(context.mode.identifier)".write(to: logFileURL, atomically: true, encoding: .utf8)
与宿主应用通信的两种方式
- 应用组+UserDefaults
// 扩展中写入状态 let sharedDefaults = UserDefaults(suiteName: "group.com.yourteam.yourapp")! sharedDefaults.set(Date(), forKey: "LastFocusActivationTime") // 宿主应用中监听变更 NotificationCenter.default.addObserver(forName: UserDefaults.didChangeNotification, object: sharedDefaults, queue: .main) { _ in if let activationTime = sharedDefaults.object(forKey: "LastFocusActivationTime") as? Date { // 处理逻辑 } }
- 分布式通知中心
// 扩展中发送通知 DistributedNotificationCenter.default().post( name: NSNotification.Name("FocusExtensionDidTrigger"), object: nil, userInfo: ["modeID": context.mode.identifier.rawValue], deliverImmediately: true ) // 宿主应用中监听 DistributedNotificationCenter.default().addObserver( forName: NSNotification.Name("FocusExtensionDidTrigger"), object: nil, queue: .main ) { notification in if let modeID = notification.userInfo?["modeID"] as? String { // 处理逻辑 } }
注:使用分布式通知需在沙箱权限中添加
com.apple.security.temporary-exception.apple-events。
内容的提问来源于stack exchange,提问作者John M.
相关产品推荐
相关产品推荐

