Android开发:获取Google日历独立任务与提醒数据的方法
读取Google日历独立提醒与任务的实现方案
你之前的查询逻辑只能拿到普通日历事件,独立提醒、任务的存储逻辑和普通事件完全不同,具体实现方式如下:
独立提醒(Reminders)读取
独立提醒不是存储在CalendarContract.Reminders表中——该表仅存储普通事件关联的提醒规则,比如某会议提前10分钟弹通知的配置,不是独立存在的提醒条目。
独立提醒本质是特殊类型的日历事件,归属于系统专属的提醒日历,仍然存在CalendarContract.Events表中,你之前查不到是两个原因导致:
- 没有限定提醒专属日历的ID,查询范围没有覆盖到提醒数据
- 独立提醒大多不设置结束时间,
dtend字段常为null,你之前写的dtend < endAt条件会把这类条目全部过滤掉
具体实现步骤
- 先查询提醒专属日历的ID
Android 6.0(API 23)及以上版本的CalendarProvider在CalendarContract.Calendars表中提供了IS_REMINDERS_CALENDAR标识字段,值为1的日历就是存储独立提醒的专属日历,先查询拿到它的ID:
long remindersCalendarId = -1; String[] calendarProjection = new String[]{ CalendarContract.Calendars._ID, CalendarContract.Calendars.IS_REMINDERS_CALENDAR }; try (Cursor calendarCursor = contentResolver.query( CalendarContract.Calendars.CONTENT_URI, calendarProjection, CalendarContract.Calendars.IS_REMINDERS_CALENDAR + " = 1", null, null )) { if (calendarCursor != null && calendarCursor.moveToFirst()) { remindersCalendarId = calendarCursor.getLong(0); } }
- 调整查询条件拉取独立提醒
拿到提醒日历ID后,修改查询条件,处理dtend为null的场景,限定查询范围为提醒日历。另外你之前直接拼接SQL字符串的写法存在注入风险,建议改成参数化查询:
if (remindersCalendarId != -1) { String[] eventProjection = new String[]{ CalendarContract.Events.TITLE, CalendarContract.Events.DTSTART, CalendarContract.Events.DTEND }; String selection = CalendarContract.Events.DTSTART + " > ? " + "AND (" + CalendarContract.Events.DTEND + " < ? OR " + CalendarContract.Events.DTEND + " IS NULL) " + "AND " + CalendarContract.Events.DELETED + " != 1 " + "AND " + CalendarContract.Events.CALENDAR_ID + " = ?"; String[] selectionArgs = new String[]{ String.valueOf(startFrom.getTimeInMillis()), String.valueOf(endAt.getTimeInMillis()), String.valueOf(remindersCalendarId) }; try (Cursor reminderCursor = contentResolver.query( CalendarContract.Events.CONTENT_URI, eventProjection, selection, selectionArgs, CalendarContract.Events.DTSTART + " ASC" )) { if (reminderCursor != null) { while (reminderCursor.moveToNext()) { String title = reminderCursor.getString(0); long startTime = reminderCursor.getLong(1); // 无结束时间的提醒,结束时间取开始时间即可 long endTime = reminderCursor.isNull(2) ? startTime : reminderCursor.getLong(2); // 这里编写你的业务处理逻辑 } } } }
注意事项
- API 23以下的版本如果找不到
IS_REMINDERS_CALENDAR字段,可以退而求其次查询Calendars表中账户类型为com.google、显示名称匹配系统本地化“提醒”文案的日历,但这类方案兼容性差,部分定制ROM可能不适用。 - 读取日历需要声明
android.permission.READ_CALENDAR权限,你读取普通事件已经配置过的话不需要重复添加。
独立任务(Tasks)读取
独立任务数据无法通过CalendarProvider的ContentResolver接口获取,不要尝试在日历相关的库表中查找任务数据:
- 谷歌Tasks是独立于日历的服务,谷歌日历APP只是通过官方Tasks API拉取任务数据,和日历事件混合展示,任务数据本身不会写入CalendarProvider的存储中。
- 谷歌Tasks APP私有的ContentProvider不对第三方应用开放,强行查询会直接抛出
SecurityException,且这类私有API访问行为在Google Play上架审核时会被判定违反权限政策,直接拒审。
如果需要读取用户谷歌账号下的任务数据,唯一合规的官方方案是集成Google Tasks API:
- 接入Google Play服务授权体系,通过OAuth 2.0向用户申请Tasks数据的读取权限
- 授权通过后,调用对应API接口拉取指定时间范围的任务列表、截止时间、提醒配置等全量数据
内容的提问来源于stack exchange,提问作者patstevens
相关产品推荐
相关产品推荐

