一、背景
传统上,应用往日历读取或写入日程,需通过权限弹窗,向用户申请日历读取、修改权限android.permission.READ_CALENDAR、android.permission.WRITE_CALENDAR,由用户主动授权后,应用才可往日历中读取或写入日程信息。该方案存在诸多痛点,举例如下:
- 应用仅需实现写入预约日程、读取自己写入的日程,却可通过权限读取、修改用户日历中的所有日程信息,对用户隐私带来极大困扰。
- 应用获取权限后,可在用户不知情情况下写入频繁的日程提醒,造成用户打扰。
为解决以上问题,系统将谨慎开放日历读写权限,为有写入预约日程需求的应用提供日历写入服务,写入日程时需用户手动确认。后期将支持:应用可查询、删除自己成功写入的日程。
二、功能介绍
1. 应用场景介绍
应用需往日历写入日程时,拉起系统级的日历写入服务,并传入标题、提醒时间等参数(如图一)。在用户手动确认后,可成功往日历中写入日程,用户可在日历APP中查看(如图二),并由日历APP做后续日程提醒。
图一:

图二:

2. 日历写入服务功能介绍
利用ACTION_INSERT,您的应用可将事件插入任务转由日历应用执行。借助此方法时,您的应用甚至无需在其清单文件中加入WRITE_CALENDAR权限。
当用户运行使用此方法的应用时,该应用会跳转至日历,以便用户完成事件添加操作。
ACTION_INSERT 利用 extra 字段为表单预填充日历中事件的详细信息。然后,用户可以取消活动、根据需要修改表单或将活动保存到日历中。
三、 适用范围
适用于Andriod16及以上版本。此时若系统日历APP被卸载,将引导安装。安装完成后,用户需重新回到应用页拉起日历写入服务页面。
在Andriod16以下版本,可能存在系统日历APP被卸载且系统中无其他相关action,写入服务启动将会失败,这个时候可考虑使用权限进行兼容。
四、使用说明
以下详细说明适配日历写入服务的接口。
1. 获取Intent,并判断是否支持
val intent = Intent(Intent.ACTION_INSERT)
intent.setData(CalendarContract.Events.CONTENT_URI)
val support = intent.resolveActivity(packageManager)2. Intent携带参数
如果不传入或传入格式异常,系统会使用自身定义的默认值。
| 功能 | Intent Extra | value类型 | value说明/举例 | 是否支持开发者控制 |
| 事件名称 | CalendarContract.Events.TITLE | String | 限制1000字 | 支持 |
| 事件开始时间,以从公元纪年开始计算的毫秒数表示 | CalendarContract.EXTRA_EVENT_BEGIN_TIME | long | 举例:System.currentTimeMillis(),开始为当前时间 | 支持 |
| 事件结束时间,以从公元纪年开始计算的毫秒数表示 | CalendarContract.EXTRA_EVENT_END_TIME | long | System.currentTimeMillis() | 支持 |
| 事件是否属于全天事件 | CalendarContract.EXTRA_EVENT_ALL_DAY | boolean | 举例:true或false | 支持 |
| 事件描述 | CalendarContract.Events.DESCRIPTION | String | 限制1000字 | 支持 |
| 事件的重复规则 | CalendarContract.Events.RRULE | String | 举例:FREQ=DAILY;COUNT=10;表示每天发生一次,重复10次; 详细内容参考下发重复规则详情。 | 支持 |
| 事件颜色 | CalendarContract.Events.EVENT_COLOR | - | - | 暂不支持 |
| 事件的地点 | CalendarContract.Events.EVENT_LOCATION | - | - | 暂不支持 |
| 日历账户 | - | - | - | 暂不支持 |
| 提醒时间 | - | - | - | 暂不支持 |
| 是否闹钟提醒 | - | - | - | 暂不支持 |
- 重复规则详情
| 参数 | 释义 |
| FREQ | 重复规则的类型, 是重复规则中必须定义的一条属性。FREQ=DAILY 表示以天为间隔单位进行重复;FREQ=WEEKLY 表示以周为间隔单位进行重复;FREQ=MONTHLY 表示以月为间隔单位进行重复;FREQ=YEARLY 表示以年为间隔单位进行重复。 |
| INTERVAL | 表示重复规则的间隔, 必须为正整数。 默认值为1。对应不同的FREQ就是如每一天, 每一周。 |
| UNTIL | 定义了一个日期-时间值,用以限制重复规则。这个日期-时间值表示这个重复规则的最后一次事件的发生时间。 |
| COUNT | 定义重复事件的发生次数来限制重复规则 |
| BYSECOND | 取值范围 0 - 59 |
| BYMINUTE | 取值范围 0 - 59 |
| BYHOUR | 取值范围 0 - 23 |
| BYWEEKNO | 取值范围 1 - 53 或者 -53 - -1, 表示一年的第几周。 |
| BYMONTY | 取值范围 1 - 12, 表示一年的第几个月。 |
| WKST | 取值范围 MO, TU, WE, TH, FR, SA, SU。 默认值为 MO。 |
| BYSETPOS | 取值范围 1 - 366 或者 -366 - -1, 表示规则指定的事件集合中的第n个事件。 |
| 更多详细参数 | https://datatracker.ietf.org/doc/html/rfc5545 |
常见重复规则举例:
- 每天重复:FREQ=DAILY;INTERVAL=1;
- 每周当天重复:FREQ=WEEKLY;INTERVAL=1;
- 每月当天重复:FREQ=MONTHLY;INTERVAL=1;
- 每年12 月当天重复 :FREQ=YEARLY;INTERVAL=1;BYMONTH=12。
3. 启动
if (support) {
startActivity(intent)}五、调用示例
kotlin:
val intent = Intent(Intent.ACTION_INSERT).apply {
data = CalendarContract.Events.CONTENT_URI
putExtra(CalendarContract.Events.TITLE, "我的标题")
putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true)
putExtra(CalendarContract.Events.DESCRIPTION, "我的描述")
putExtra(CalendarContract.Events.RRULE, "FREQ=DAILY;COUNT=10")
putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, System.currentTimeMillis())
putExtra(CalendarContract.EXTRA_EVENT_END_TIME,System.currentTimeMillis() + AlarmManager.INTERVAL_DAY)}if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)}java:
Intent intent = new Intent(Intent.ACTION_INSERT);
intent.setData(CalendarContract.Events.CONTENT_URI);
intent.putExtra(CalendarContract.Events.TITLE, "我的标题");
intent.putExtra(CalendarContract.EXTRA_EVENT_ALL_DAY, true);
intent.putExtra(CalendarContract.Events.DESCRIPTION, "我的描述");
intent.putExtra(CalendarContract.Events.RRULE, "FREQ=DAILY;COUNT=10");
intent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, System.currentTimeMillis());
intent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME,System.currentTimeMillis() + AlarmManager.INTERVAL_DAY);if (intent.resolveActivity(packageManager) != null) {
startActivity(intent);}六、 Android开发者适配文档参考
https://developer.android.google.cn/identity/providers/calendar-provider?hl=zh-cn#intent-insert
该适配指南与金标联盟官网适配指南一致,您也可查阅金标联盟官网中公示适配指南。
金标联盟官方文档地址:https://www.itgsa.com/doc/6631953378231296