LASSIC Media らしくメディア
アプリにカレンダー・リマインダー連携を実装、外注
LASSIC IT事業部|元請(プライムベンダー)としてシステム保守・運用を受託
この記事のポイント
- アプリからカレンダー・リマインダーへ予定やタスクを登録するには、OS標準のAPIを使った権限設計が欠かせません。
- iOSはEventKitのEKEventStoreを、AndroidはCalendarProviderのCalendarContractを介して端末データにアクセスする仕組みです。
- iOS17ではEventKitの権限モデルが変わり、内製・外注どちらで進めるにせよ設計の見直しが必要になります。
目次
アプリのカレンダー・リマインダー連携とは、端末の予定・タスクを読み書きする実装
アプリのカレンダー・リマインダー連携とは、スマートフォンアプリから端末標準のカレンダーやリマインダーへ、予定やタスクの登録・読み取りを行う実装を指します。iOSはEventKit(カレンダー・リマインダーへのアクセスを提供するフレームワーク)、AndroidはCalendarProviderという公式APIをそれぞれ用意しています*1*5。
予約管理アプリやタスク管理アプリでは、アプリ内の予定を端末のカレンダーにも登録できると、利用者が普段使っているカレンダーアプリだけを見れば予定を把握できます。プッシュ通知やアプリ内のローカル通知だけで済ませる実装とは異なり、端末のカレンダー・リマインダーAppそのものにデータを書き込む点が本稿の対象です。
両OSとも、読み取りには何らかのアクセス許可が必要という点は共通しています。ただし許可の粒度や、書き込みのみで済むケースの扱いがOSごとに異なる点は見過ごせません。次章から実装の基盤となるAPIを順に見ていきます。
iOSの実装基盤——EventKitとEKEventStore
EKEventStore・EKEvent・EKReminder
EventKitは、カレンダーとリマインダーのデータへアクセスし、アプリ内で作成・取得・編集するための機能を提供するフレームワークです*1。中心となるのはEKEventStoreで、カレンダーイベントとリマインダーへのアクセス、新規イベントのスケジューリングをまとめて担うオブジェクトです*1。
EKEventStoreを初期化した後、実際にデータを取得・作成する前に、イベントまたはリマインダーへのアクセスを要求する設計になっています*3。カレンダー内の個々の予定はEKEventクラスが、単一のリマインダーはEKReminderクラスがそれぞれ表現します*1。両クラスともEKEventStore経由で保存・削除を行います。
UI表示にはEventKitUI(標準的なイベント編集・選択画面を提供する補助フレームワーク)を組み合わせる方法もあります。新規イベントの作成用画面だけを使う場合、EventKitUI側の画面ではフルアクセスの権限が不要になる場面もあると案内されています*3。
iOS17で変わった権限モデル——フルアクセスと書き込み専用アクセス
Xcode 15に含まれるiOS17・macOS14・watchOS10のSDKで、EventKitの権限モデルは大きく変わりました*2。従来の単純な許可・拒否の二択から、書き込み専用アクセス・フルアクセス・リマインダーへのフルアクセスという複数のアクセスレベルに分かれています*2。
従来のrequestAccess(to:completion:)は非推奨となり、iOS17以降では権限プロンプトを表示せずエラーとともに完了ハンドラを呼び出す動作に変わっています*4。代わりに用途別のメソッドを呼び分ける必要があり、イベントの読み書きにはrequestFullAccessToEvents(completion:)、書き込みのみならrequestWriteOnlyAccessToEvents(completion:)、リマインダーの読み書きにはrequestFullAccessToReminders(completion:)を使います*3*4。いずれもiOS17.0で導入されたメソッドです*3。なおリマインダーには書き込み専用の選択肢は用意されていません*3。
両者の違いを整理すると次の通りです。
| 項目 | iOS16以前 | iOS17以降 |
|---|---|---|
| 権限リクエストメソッド | requestAccess(to:completion:) iOS17以降は非推奨*4 |
requestFullAccessToEvents等の用途別メソッド*3 |
| 初回許可で得られる権限 | フルアクセス相当 | イベントは書き込み専用または任意でフルアクセス*2 |
| リマインダーの選択肢 | 許可・拒否の二択 | フルアクセスのみ。書き込み専用は無い*3 |
| Info.plistの用途説明キー | NSCalendarsUsageDescription等の従来キー | 用途別キーの追加が可能。未設定だと権限を要求できない*3 |
| 旧SDKビルドのアプリ | 該当なし | 書き込み専用アクセスとして扱われる*2 |
書き込み専用アクセスのままだと、アプリが自分で作成したイベントであっても読み取れません*2。sourcesプロパティは仮想的なソースを1つ返し、defaultCalendarForNewEventsも仮想カレンダーを返す挙動になります*2。events(matching:)などの検索系メソッドを初めて呼び出すと、フルアクセスへのアップグレードがユーザーへ自動的に要求されます*2。
Androidの実装基盤——CalendarProviderとCalendarContract
Events・Remindersテーブルの役割
CalendarProvider(カレンダープロバイダ)は、利用者のカレンダーイベントを保持するリポジトリで、カレンダー・イベント・出席者・リマインダーへの問い合わせや挿入・更新・削除を行うAPIをまとめて提供します*5。データモデルはCalendarContractクラスで定義され、Calendars・Events・Instances・Attendees・Remindersという主要テーブルで構成されます*5。
予定の登録にはEventsテーブルへCALENDAR_ID・DTSTART・EVENT_TIMEZONEなどを指定して挿入します*5。繰り返しのない予定はDTENDが必須で、繰り返し予定はRRULEまたはRDATEに加えてDURATIONの指定が必要です*5。リマインダー(通知)はRemindersテーブルにEVENT_ID・MINUTES・METHODを指定して追加し、指定した分数前にMETHOD_ALERT等の方法でアラートを発火させます*5。
権限設計——READ_CALENDARとWRITE_CALENDAR
カレンダーデータの読み書きには、マニフェストファイルへREAD_CALENDARとWRITE_CALENDARの権限を宣言する必要があります*5。READ_CALENDARは読み取りに、WRITE_CALENDARは挿入・更新・削除に、それぞれ必要な権限です*5。
Android開発者ガイドは、プライベートなユーザーデータへのアクセスを伴う権限には「dangerous」という保護レベルの実行時権限を割り当てると説明しています*6。カレンダーデータもこの枠組みに含まれるため、マニフェストへの宣言だけでなく、実行時に利用者へ許可を求める画面の設計もあわせて必要になります。
実装で見落としやすい落とし穴——権限拒否時の挙動とOS間の差
両OSを1本のアプリで対応する場合、権限モデルの粒度の違いがそのまま設計の分岐点になります。iOSはイベントに関して書き込み専用・フルアクセス・アクセスなしの3段階を区別しますが*2、Androidは READ_CALENDARとWRITE_CALENDARという2つの権限の組み合わせで表現します*5。同じUIフローを両OSへそのまま流用すると、想定した権限状態と実際の挙動がずれる場面が出てきます。
iOS側では、Info.plistに用途別の説明キーを設定していないと、対応するアクセスレベルの権限を要求できません*3。設定漏れのまま申請すると審査やテスト工程で差し戻しが発生し、リリース予定に影響します。書き込み専用アクセスのまま一覧表示機能を実装すると、アプリが登録した予定を読み戻せず、機能自体が成立しません*2。
この作業を内製で担うには、複数領域の知識が要ります。EventKitの権限モデルとInfo.plistの設定、CalendarContractのテーブル構造、Android側の実行時権限リクエストの実装などです*1*3*5。iOS16以前でビルドされたアプリがiOS17上でどう扱われるかまで含めて検証する体制が前提になります*2。
内製と外注の分かれ目——両OS対応に必要なスキルと工数
カレンダー・リマインダー連携そのものは、公式ドキュメントに手順が公開されているため、対応OSが一方だけであれば自社で実装できる場面もあります*1*5。判断が分かれるのは、iOS・Androidの両方に対応し、かつ既存ユーザーの権限状態を維持しながら移行する場合です。
専門パートナーに委託する場合は、依頼範囲の広さが選定の分かれ目になります。EventKitの権限モデル対応からCalendarContractを使った実装、Android側の実行時権限UI、双方の検証工程までを一括して依頼できるかどうかを確認します*2*5。内製では既存の開発担当者が通常業務と並行して対応することになり、OSごとの権限差分を洗い出す検証に割ける時間が限られる場合があります。
。対応するOSの範囲や既存ユーザーの権限状態によって必要な工数は変わってきます。現状のアプリ構成を確認したうえで、内製・外注の切り分けを検討することが実務的です。
まとめ:アプリのカレンダー・リマインダー連携で押さえる3つの判断軸
本稿ではアプリのカレンダー・リマインダー連携について、iOS・Androidの公式情報をもとに整理しました。要点は3つに集約できます。第一に、iOSはEventKitのEKEventStoreを、AndroidはCalendarProviderのCalendarContractを介して端末データにアクセスする仕組みです*1*5。第二に、iOS17ではEventKitの権限モデルが書き込み専用・フルアクセス・リマインダーへのフルアクセスという複数段階に変わり、旧SDKビルドのアプリも扱いが変わります*2。第三に、対応OSの範囲や既存ユーザーの権限状態によって検証工数は変わり、内製と外注の判断材料になります。
よくある質問
iOSとAndroidでカレンダー連携の権限モデルはどう違いますか。
iOSはEventKitでフルアクセス・書き込み専用・アクセスなしを区別する設計に変わりました*2。Androidは READ_CALENDARとWRITE_CALENDARの権限をマニフェストと実行時リクエストの両方で管理する仕組みです*5*6。
書き込み専用アクセスのままだとアプリ側で何ができなくなりますか。
アプリが自分で作成したイベントも読み取れず、sourcesプロパティは仮想的なソースを1つ返す挙動になります*2。イベントの内容を検索・一覧表示する機能を使う場合は、フルアクセスへのアップグレードが必要です*2。
iOS16以前向けにビルドされたアプリはiOS17でどう動きますか。
旧SDKでビルドされたアプリでも、requestAccess(to:completion:)を呼び出すと書き込み専用アクセスの許可を求める形で動作します*2*4。ユーザーが以前にフルアクセスを許可していた場合も、iOS17上では書き込み専用として扱われる点に注意が必要です*2。
Androidでリマインダー(通知)の登録にはどのテーブルを使いますか。
CalendarContract.RemindersテーブルにEVENT_ID・MINUTES・METHODを指定して登録します*5。登録すると、指定した分数前にMETHOD_ALERT等の方法でアラートが発生する仕組みです*5。
カレンダー連携の実装を外部に委託する場合、何を確認すればよいですか。
iOS17の権限モデルへの対応方針、Android側の実行時権限リクエストの設計、両OSでの検証範囲をまず確認します。契約前に対応OSバージョンの範囲を明確にしておくと、リリース後の想定外の挙動を抑えやすくなります。
著者:テレリモ総研編集部 鈴木 亮佑
ご不明な点はお問い合わせフォームからもご連絡いただけます。
- *1 出典:Apple Developer Documentation「EventKit」(https://developer.apple.com/documentation/eventkit)
- *2 出典:Apple Developer Documentation「TN3153: Adopting API changes for EventKit in iOS 17, macOS 14, and watchOS 10」(https://developer.apple.com/documentation/technotes/tn3153-adopting-api-changes-for-eventkit-in-ios-macos-and-watchos)
- *3 出典:Apple Developer Documentation「Accessing the event store」(https://developer.apple.com/documentation/eventkit/accessing-the-event-store)
- *4 出典:Apple Developer Documentation「requestAccess(to:completion:)」(https://developer.apple.com/documentation/eventkit/ekeventstore/1507547-requestaccess)
- *5 出典:Android Developers「Calendar Provider」(https://developer.android.com/guide/topics/providers/calendar-provider)
- *6 出典:Android Developers「Permissions on Android」(https://developer.android.com/guide/topics/permissions/overview)