Expo Calendarで繰り返しイベントを取得するときの不具合に対応した
Expo Calendarで繰り返しイベントを取得しようとすると、iOS版で正常に動作しなかったです。
仕様なのか、バグなのかは分かりませんが、Issueはありましたが、特に対応はされず閉じられていました。
プルリクを送るか悩みましたが、正直なところ、Expoほどの巨大リポジトリで、コンテキストもあまり理解していない状態で、英語でコミュニケーション取りながらやる自信がなかったので、パッチを当てることにしました。
不具合の内容
以下のようにgetEventAsync
を使って、繰り返しイベントを取得しようとすると、引数に指定したinstanceStartDate
の値を無視して、繰り返しイベントの最初のインスタンスの情報を取得してしまいます。
コード例
const event = await Calendar.getEventAsync(eventId, {
instanceStartDate: "2025-03-02T07:00:00.000Z",
});
期待する動きは、繰り返しイベントの内、引数に指定したinstanceStartDate
の値と同じstartDate
を持つイベントが取得できることです。が、そうはなっていません。
実行結果
前述のコードを実行した場合、次のような結果が返ってきます。
{"alarms": [], "allDay": false, "availability": "notSupported", "calendarId": "28982EB5-F6F1-4FD0-B91B-E3E07D6B0EB8", "creationDate": "2025-03-01T07:54:02.743Z", "endDate": "2025-03-01T08:00:00.000Z", "id": "2750D93A-D17B-458C-A611-0B8CB8D67644", "isDetached": false, "lastModifiedDate": "2025-03-01T07:54:02.743Z", "originalStartDate": "2025-03-01T07:00:00.000Z", "recurrenceRule": {"frequency": "daily", "interval": 1}, "startDate": "2025-03-01T07:00:00.000Z", "status": "none", "timeZone": "JST", "title": "繰り返しイベント", "url": ""}
startDate
が2025-03-02T07:00:00.000Z
ではなく、2025-03-01T07:00:00.000Z
になっています。
取得処理の修正
今回はpnpm patch
を使ってパッチを当てることにしました。
パッチを当てる前の処理は、次の通りです。
Expo Calendarのバージョン13.0.5
や執筆時点で最新の14.0.6
でも問題があるのを確認しています。
private func getEvent(with id: String, startDate: Date?) -> EKEvent? {
guard let firstEvent = eventStore.calendarItem(withIdentifier: id) as? EKEvent else {
return nil
}
guard let startDate else {
return firstEvent
}
// 問題があるのはここ。
// firstEvent.startDate = 繰り返しイベントの最初のインスタンスのstartDate
// startDate = instanceStartDate
// この2つが異なる場合、最初のインスタンスを返すという処理になっている
guard let firstEventStart = firstEvent.startDate, firstEventStart.compare(startDate) == .orderedSame else {
return firstEvent
}
let endDate = startDate.addingTimeInterval(2_592_000)
let events = eventStore.events(
matching: eventStore.predicateForEvents(withStart: startDate, end: endDate, calendars: [firstEvent.calendar])
)
for event in events {
if event.calendarItemIdentifier != id {
break
}
if let eventStart = event.startDate, eventStart.compare(startDate) == .orderedSame {
return event
}
}
return nil
}
ちなみに、元々Objective-Cで書かれていたのをSwiftに移行したときに、guard文に変えたようです。
Objective-Cのコードは、以下の通りです。
パッチについて
ということで、パッチです。
diff --git a/ios/CalendarModule.swift b/ios/CalendarModule.swift
index 96cb1b74f636871b048c6b3bc666b86b08ff87a0..705b6328837c10591753146ea2678b8fcf98dd97 100644
--- a/ios/CalendarModule.swift
+++ b/ios/CalendarModule.swift
@@ -501,7 +501,7 @@ public class CalendarModule: Module {
return firstEvent
}
- guard let firstEventStart = firstEvent.startDate, firstEventStart.compare(startDate) == .orderedSame else {
+ if let firstEventStart = firstEvent.startDate, firstEventStart.compare(startDate) == .orderedSame {
return firstEvent
}
簡単にいうと
「guard
をif
に変える」
これだけです。
あとは、パッチを当てるだけです。
pnpm patch expo-calendar
# .pnpm-patch/にファイルが展開されるので、編集してpatch-commitを実行
pnpm patch-commit 'path/to/expo-calendar@13.0.5'
Swiftのコードへの変更なので、ビルドが必要なのでお忘れなく。
おわりに
Expo Calendarのパッチを当てることで、iOS版で繰り返しイベントを扱うときの不具合に対応できました。
どこかでExpo側で対応されたら良いなと思いつつ、その場合はおそらく最新のExpoへの適用になると思うので、Expo本体のバージョンアップが必要になり…という未来が見えるので、なんとも言い難いです。
参考になれば幸いです。それでは。
Discussion