探索日历集成:EventKit 与 EventKitUI 实战
Discover Calendar and EventKit
2023年6月5日
一句话判断
想让自己的 App 和系统日历打通?这场 Session 给出了从添加事件到实现虚拟会议扩展的完整路线图。
这场 Session 讲了什么
Adam 从 EventKit 和 EventKitUI 两个框架出发,详细讲解了 App 如何与系统日历集成。核心内容分成四个方向:
添加事件。最简单的方式是用 EKEventEditViewController,在 iOS 17 中它运行在独立进程里,不需要请求日历权限。你只需创建事件、填好属性、弹出编辑器,用户点”添加”就完事了。更轻量的方式是 Siri Event Suggestions API,适合餐厅预订、机票、演出票这类场景,事件会出现在日历的收件箱里。
读取和修改事件。需要 full access 权限。iOS 17 引入了新的权限模型,分为无权限、只写、完全访问三个级别。
虚拟会议扩展。如果你的 App 支持音视频通话,可以通过 Virtual Conference Extension 让日历 App 直接展示你的会议链接和品牌信息,还能从日历直接跳转到你的 App。
EventKitUI 的三个视图控制器。EKEventEditViewController(编辑事件)、EKEventViewController(查看事件详情)、EKCalendarChooser(选择日历),覆盖了日历交互的主要场景。
值得深挖的点
iOS 17 的进程隔离改动。EKEventEditViewController 现在在独立进程中运行,这意味着你不需要请求日历权限就能用它添加事件。这是一个重要的隐私改进——用户通过系统 UI 确认后事件才会被写入,App 本身无法直接访问日历数据。
日期计算的坑。Session 特别强调要用 Foundation 的 Calendar 和 DateComponents 来做日期运算,而不是手动计算秒数。夏令时切换会让简单的时间差计算出错,这是很多开发者踩过的坑。
三级权限模型。无权限 -> 只写 -> 完全访问,每一级对应不同的 API 能力。只写权限意味着你可以添加事件但不能读取已有事件,这对于预订类 App 来说恰到好处。
代码片段
// 使用 EventKitUI 添加事件(iOS 17 无需请求权限)
let eventStore = EKEventStore()
let event = EKEvent(eventStore: eventStore)
event.title = "产品评审会"
event.startDate = Calendar.current.date(from: DateComponents(
year: 2024, month: 1, day: 15, hour: 14, minute: 0
))!
// 用 DateComponents 计算结束时间,避免手动加减秒数
event.endDate = Calendar.current.date(
byAdding: .hour, value: 2, to: event.startDate
)!
let editor = EKEventEditViewController()
editor.event = event
editor.eventStore = eventStore
editor.delegate = self
present(editor, animated: true)
// 使用 Siri Event Suggestions 添加预订事件
let reference = INSpeakableString(
vocabularyIdentifier: "reservation-123",
spokenPhrase: "今晚的晚餐预订"
)
let dateRange = INDateComponentsRange(
start: startDateComponents, end: endDateComponents
)
let location = CLPlacemark(
location: CLLocation(latitude: 39.9, longitude: 116.4),
name: "某餐厅"
)
let reservation = INRestaurantReservation(
itemReference: reference,
reservationNumber: "R-123",
bookingTime: Date(),
reservationStatus: .confirmed,
reservationDuration: dateRange,
partySize: 4,
restaurantLocation: location
)
最佳实践
- 事件标题要简洁,它会出现在小组件和通知中,过长的标题会被截断。
- 位置信息尽量提供完整地址或 MapKit handle,这样系统才能提供”出发时间”提醒和 Maps 建议。
- 如果只是添加事件,优先使用
EKEventEditViewController或 Siri Event Suggestions,避免直接请求日历权限。 - 每个 App 只应创建一个
EKEventStore实例,不要到处 new。 - 对于虚拟会议,实现 Virtual Conference Extension 可以让你的服务在日历 App 中获得品牌曝光。
还有什么值得关注
- “DropInLessons” 示例代码中的完整实现值得参考
- iOS 17 的进程隔离机制同样影响其他系统 UI 组件
- 如果你做的是旅行类 App,Siri Event Suggestions 的航班和租车支持可能直接用得上
EKCalendarChooser的多选模式适合自定义日历视图的场景