macOS Big Sur下Swift命令行工具使用EventKit获取日历权限异常问题
我正尝试在macOS Big Sur系统上使用Xcode 12.5.1开发一款Swift语言的命令行小工具,用于访问并展示日历事件。我已经查阅了EKEventStore官方文档,编写了最简测试代码:
import Foundation import EventKit var store = EKEventStore()
我已开启沙箱功能,添加了日历权限及沙箱对应的entitlement配置;也在Info.plist文件中补充了Privacy - Calendars Usage Description项并填写了对应说明值;同时在构建设置中将Create Info.plist Section in Binary设置为Yes。
但完成上述所有配置后,仅一行核心代码的应用始终无法成功初始化EKEventStore(),报出如下错误:
2021-09-17 23:39:24.609490-0700 nextzoom[51558:6213649] CoreData: XPC: Unable to load metadata: Error Domain=NSCocoaErrorDomain Code=134070 "An error occurred in the persistent store." UserInfo={Problem=request failed, insufficient permission} 2021-09-17 23:39:24.610959-0700 nextzoom[51558:6213649] [error] error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134070) CoreData: error: addPersistentStoreWithType:configuration:URL:options:error: returned error NSCocoaErrorDomain (134070) CoreData: annotation: userInfo: CoreData: annotation: Problem : request failed, insufficient permission CoreData: annotation: storeType: NSXPCStore CoreData: annotation: configuration: (null) CoreData: annotation: URL: file:///Users/%%%%%%/Library/Calendars/Calendar%20Cache CoreData: annotation: options: CoreData: annotation: NSMigratePersistentStoresAutomaticallyOption : 1 CoreData: annotation: agentOrDaemon : 1 CoreData: annotation: NSInferMappingModelAutomaticallyOption : 1 CoreData: annotation: serviceName : com.apple.CalendarAgent.database CoreData: annotation: NSPersistentHistoryTrackingKey : { NSPersistentHistoryTrackingEntitiesToExclude = ( ChangeRequest ); } Program ended with exit code: 0
当前问题表现为系统未弹出日历权限申请弹窗,但如果我添加通讯录权限entitlement及Privacy - Contacts Usage Description配置,运行时会正常弹出通讯录访问申请弹窗,应用也会出现在系统安全与隐私设置的通讯录权限列表中,唯独日历权限始终无法正常触发申请流程。
1. 补全权限申请逻辑,避免进程提前退出
你当前仅初始化了EKEventStore实例,没有主动触发权限申请流程,同时命令行工具执行完所有同步代码后会直接终止,异步的权限请求还未发出进程就已结束,这是弹窗无法弹出的核心原因。
修复方式:主动调用requestAccess(to:completion:)方法申请权限,同时使用信号量阻塞进程直到权限请求回调返回,示例代码如下:
import Foundation import EventKit let store = EKEventStore() let semaphore = DispatchSemaphore(value: 0) store.requestAccess(to: .event) { granted, error in if let error = error { print("权限申请失败: \(error.localizedDescription)") } else if granted { print("日历权限申请成功") // 后续日历操作逻辑可放在此处 } else { print("用户拒绝了日历权限") } semaphore.signal() } semaphore.wait() exit(0)
2. 校验沙箱权限配置
确认你的.entitlements文件中存在正确的macOS日历权限配置,不要误用iOS平台的权限键:
<key>com.apple.security.personal-information.calendars</key> <true/>
3. 校验Info.plist配置
确认Info.plist中的日历权限说明键为NSCalendarsUsageDescription,不要出现拼写错误,你已开启的Create Info.plist Section in Binary配置符合命令行工具嵌入Info.plist的要求,无需修改。
缓存清理(可选)
如果修改后依然无法触发弹窗,可先清理旧的权限缓存:
- 打开
系统偏好设置 > 安全与隐私 > 隐私 > 日历,删除列表中对应应用的条目 - 执行终端命令
tccutil reset Calendar清空所有日历权限缓存,之后重新运行项目即可
内容的提问来源于stack exchange,提问作者Simon

