EventKitでカレンダー・リマインダー連携を実装してつまずいた話

EventKitでカレンダー・リマインダー連携を実装してつまずいた話 トラブルシューティング

Core Bluetoothで周辺機器とBLE通信を実装した後、アプリの予定をカレンダーに登録できるようにしたいと考え、EventKitによるカレンダー連携に挑戦しました。

1. 権限リクエストなしでアクセスできると思っていた

最初、他の多くのフレームワークと同様に、アクセス時に自動で権限ダイアログが出るものだと思い込んでいました。

let eventStore = EKEventStore()
let events = eventStore.events(matching: predicate)

このコードを実行しても、権限ダイアログが表示されないまま空の結果が返ってきました。調べてみると、EventKitでは明示的にrequestFullAccessToEventsを呼び出して許可を得ないと、アクセスそのものが失敗する仕組みになっていることが分かりました。

2. iOSバージョンによって権限APIが異なることに気づかず苦労した

権限リクエストの実装を調べていたところ、参考にしたサンプルコードによって使われているAPIが異なっており、混乱しました。

違い:
iOS17以降は requestFullAccessToEvents
それ以前は requestAccess(to:)

iOS17でカレンダーの権限モデルが変更され、新しいAPIが追加されていたことが原因でした。古いAPIも引き続き使えるものの、対応OSのバージョンに応じて呼び分ける必要があると分かり、条件分岐を入れて両方に対応させました。

3. デフォルトカレンダーがnilで保存に失敗した

権限を取得しイベントを作成しようとしたところ、保存処理でエラーが発生しました。

エラー内容:
calendar プロパティが未設定

新規に作成したEKEventにはカレンダーが自動で設定されず、保存前に明示的にeventStore.defaultCalendarForNewEventsを指定する必要があることが分かりました。この設定を追加したところ、正しくカレンダーにイベントが保存されるようになりました。

4. アプリで作成したイベントの削除・更新がうまくいかなかった

イベントの保存はできるようになったものの、後からアプリ内でそのイベントを更新・削除する処理がうまく動きませんでした。

let identifier = event.eventIdentifier

原因は、保存時に発行されるeventIdentifierをアプリ側で保持しておらず、後から対象のイベントを正しく特定できていなかったことでした。保存が成功した時点でこの識別子をアプリのデータとして保存しておくことで、後からの更新・削除が正しく行えるようになりました。

まとめ

  • EventKitはアクセス前に明示的な権限リクエストが必要で、リクエストなしでは空の結果しか返らない
  • iOS17以降は新しい権限APIが追加されており、対応OSに応じた呼び分けが必要
  • 新規イベントの保存にはdefaultCalendarForNewEventsなど保存先カレンダーの明示的な指定が必要
  • 後からイベントを更新・削除するには、保存時のeventIdentifierをアプリ側で保持しておく必要がある

カレンダーという身近な機能だからこそ、権限まわりやOSバージョンごとの違いを丁寧に扱う必要があると実感した実装でした。


本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。

コメント

タイトルとURLをコピーしました