最近接到一个需求,要为用户增加一些日历提示信息。感觉不是很难的一个需求,也折腾了一天,记录一些关键步骤,以资来者。
申请日历权限
APP想要操作用户的日历,需要有读写日历的权限:android.permission.READ_CALENDAR
,android.permission.WRITE_CALENDAR
。上述权限读取和写入可以分别申请,即如果需求只是写入日历提醒功能,则不需要申请READ_CALENDAR权限。此外,由于此权限是高危权限,需要进行动态申请
写入日历提醒
Android的日历系统对外暴露是通过provider机制进行的,即每次操作都要拼装对应的URI。这里比较关键的是三个URL为:
private static String CALENDAR_URL = "content://com.android.calendar/calendars"; // 日历账户
private static String CALENDAR_EVENT_URL = "content://com.android.calendar/events"; // 事件表
private static String CALENDAR_REMINDER_URL = "content://com.android.calendar/reminders"; // 提醒表
首先我们需要获得用户日历的账户id,这个值是我们所有日历操作的基础;然后向events表插入对应的日程,包括起止时间(ms)、标题、事件描述;最后向reminders表插入对应的提醒事件,包括日程填入后的eventId,提醒时间以及提醒方式。
核心代码:
public static boolean insertCalendarEvent(Context context, String title, String description,
long beginTimeMillis, long endTimeMillis) {
if (context == null || TextUtils.isEmpty(title) || TextUtils.isEmpty(description)) {
return false;
}
int calId = checkCalendarAccount(context); // 获取日历账户的id
if (calId < 0) { // 获取账户id失败直接返回,添加日历事件失败
return false;
}
try {
/** 插入日程 */
ContentValues eventValues = new ContentValues();
eventValues.put(CalendarContract.Events.DTSTART, beginTimeMillis); // 事件起始时间
eventValues.put(CalendarContract.Events.DTEND, endTimeMillis); // 事件结束时间
eventValues.put(CalendarContract.Events.TITLE, title); // 事件标题
eventValues.put(CalendarContract.Events.DESCRIPTION, description); // 事件描述
eventValues.put(CalendarContract.Events.CALENDAR_ID, 1); // 使用默认日历目录
eventValues.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID()); // 获取默认时区
Uri eUri = context.getContentResolver().insert(Uri.parse(CALENDAR_EVENT_URL), eventValues);
long eventId = ContentUris.parseId(eUri);
if (eventId == 0) { // 插入失败
return false;
}
/** 插入提醒 - 依赖插入日程成功 */
ContentValues reminderValues = new ContentValues();
reminderValues.put(CalendarContract.Reminders.EVENT_ID, eventId);
reminderValues.put(CalendarContract.Reminders.MINUTES, 10); // 提前10分钟提醒
reminderValues.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT); // 提示方式提醒
Uri rUri = context.getContentResolver().insert(Uri.parse(CALENDAR_REMINDER_URL),
reminderValues);
if (rUri == null || ContentUris.parseId(rUri) == 0) {
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
查看日历
查看日历一种方式是通过qurey的方式进行provider查询,这种方式有很大可能会读取到用户其他的日历信息,不是很友好(主要是没需求,都懂得~)。这里推荐另一种查看日历的方式,直接拉起系统日历来查看具体信息。具体代码如下:
private void gotoCalendar() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_APP_CALENDAR);
startActivity(intent);
}
TODO
需求虽然做完且交付了,还有两个问题需要继续学习解决,记录下来,省的忘了。
- 日历的账户操作很重要,能有效解决多个应用日程污染问题;
- 如何过滤本APP插入日程,如果日程被修改过如何识别出来。