はじめに
Flutterでデバイス標準のカレンダーにアクセスする方法について調べましたので共有します。
サンプルとなるプロジェクトをGithubに作成しましたので、UIも含めたサンプルが欲しい方のご参考になれば幸いです。
(画面遷移にgo_router
とriverpod
を使っているので、初学者の方には全体像が若干ややこしく感じるかもしれませんが、サンプルプロジェクトのdevice_calendar_page.dart
とadd_event_page.dart
を見ていただければ、内容わかりやすいかと思います)
目次
カレンダーにアクセスできるパッケージ
device_calendarというパッケージを使えば簡単にデバイスのカレンダーへとアクセスできます。
使う際の設定も、AndroidならAndroidManifest.xml、iOSならInfo.plistに設定を数行追加するだけです。
設定
共通の設定
まずpubspec.yamlにdevice_calendar
を追加して、pub getしてください。
Androidの場合
AndroidManifest.xmlに以下を追加してください
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
追加する場所は、manifestタグのすぐ下でOKです。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.xxxxxx">
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
・
・
iOSの場合
Info.plistに以下を追加します
<key>NSCalendarsUsageDescription</key>
<string>Access most functions for calendar viewing and editing.</string>
<key>NSContactsUsageDescription</key>
<string>Access contacts for event attendee editing.</string>
カレンダーの取得
device_calendar
を使用すると、スマホ内のすべてのカレンダーの取得ができ、それぞれに読み書きできるようになります。
本記事では、説明簡略化のため、スマホでデフォルトの設定となっているカレンダーのみに絞り、カレンダーにイベントを登録
してみたいと思います。
デフォルトのカレンダーを取得するメソッドは以下となります。
(メソッドの最後で、_defaultCalendar
に代入しているのはクラス内の他の場所で変数として使用したかったからです)
Future<Calendar> _getDefaultCalender() async {
var permissionsGranted = await _deviceCalendarPlugin.hasPermissions();
if (permissionsGranted.isSuccess && !permissionsGranted.data!) {
permissionsGranted = await _deviceCalendarPlugin.requestPermissions();
if (!permissionsGranted.isSuccess || !permissionsGranted.data!) {
throw Exception("Not granted access to your calendar");
}
}
final calendarsResult = await _deviceCalendarPlugin.retrieveCalendars();
final calendars = calendarsResult?.data;
if(calendars == null || calendars.isEmpty) {
throw Exception("Can not get calendars");
}
_defaultCalendar = calendars!
.firstWhere((element) => element.isDefault ?? false);
return _defaultCalendar!;
}
コードの解説を行います。
まず、スマホ内のカレンダーは以下の部分で取得しています。
final calendarsResult = await _deviceCalendarPlugin.retrieveCalendars();
final calendars = calendarsResult?.data;
つづいて、
カレンダーは上記で取得可能なのですが、取得の前にカレンダーのアクセス許可があるか確認し、なければ許可を得る必要があります。
そのためのコードが以下です。
var permissionsGranted = await _deviceCalendarPlugin.hasPermissions();
if (permissionsGranted.isSuccess && !permissionsGranted.data!) {
permissionsGranted = await _deviceCalendarPlugin.requestPermissions();
if (!permissionsGranted.isSuccess || !permissionsGranted.data!) {
throw Exception("Not granted access to your calendar");
}
}
そして、最後に取得したカレンダーにはisDefault
というデフォルト設定のカレンダーかどうかを判定するプロパティがあるのでそのプロパティを元にデフォルトのカレンダーを取得しています。
_defaultCalendar = calendars!.firstWhere((element) => element.isDefault ?? false);
カレンダーの取得に失敗する場合
Emulatorを使用している場合で、カレンダーを使用したことがない場合、取得に失敗します。
Emulatorからカレンダーアプリを開いて、ログインしてからコードを実行してください。
カレンダーにイベントを登録
カレンダーにイベントを登録するメソッドは以下となります。
(自分の環境では実際にカレンダーに表示されるまで時間がかかりました(1~2分くらい?))
Future<void> _addEvent() async{
final event = Event(
widget.defaultCalenderId,
title: _titleController.text,
start: TZDateTime.local(2022, 9, 28, 2),
end: TZDateTime.local(2022, 9, 28, 3),
);
final result = await DeviceCalendarPlugin().createOrUpdateEvent(event);
if(result == null) {
return;
}
if(result.isSuccess){
return;
}
if(!result.hasErrors){
return;
}
throw Exception(result.errors.join());
}
端的に説明すると、Event
インスタンスを作成し、DeviceCalendarPlugin().createOrUpdateEvent
メソッドの引数に渡すだけです。
私もすべて把握できていませんが、Event
クラスには場所やリマインダー、終日、出席者などといった設定もできるようです。
GoogleカレンダーやiOSのカレンダーをイメージしていただくとわかりやすいかと思います。
さいごに
DeviceCalendarPlugin
のメソッドを見ると、カレンダーの追加や、カレンダーに登録したイベントの取得や編集、削除といったことも行えそうです。大変便利なパッケージなので、カレンダーを実装する際は、一からカレンダーの作成をするのも一つの手段ですが、スマホに入っているデフォルトのカレンダーを使用するのもアリだと思いました。