更新记录
1.4.0(2025-09-26)
添加异步调用,同时将方法挂载在 uni 上,通过 uni.* 进行使用;从而达到良好的提示
1.3.1(2025-09-26)
更新 readme.md ,优化插件使用方法
1.3.0(2025-09-26)
日历事项查询、删除、新增功能
查看更多平台兼容性
uni-app(4.76)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | 5.0 | - | - |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|
| - | - | - | - | - | - | - | - | - | - | - |
uni-app x(4.76)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| - | - | - | - | - | - |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
uni-calendar
一个基于 UTS 开发的 uni-app 日历插件,支持在 Android 平台获取系统日历信息。
功能特性
- 📅 获取系统日历账户信息
- 🔐 支持访问级别查询
- 🎨 支持日历颜色和显示名称
- ⚙️ 支持同步和可见性设置
- 📝 新增日历事项(支持提醒、位置、访问级别等)
- 🔍 查询日历事项(支持时间范围、关键词搜索)
- 🗑️ 删除日历事项(支持按时间范围批量删除)
- 📱 专为 Android 平台优化
安装
- 在 uni-app 项目中,通过 uni_modules 安装
- 确保 HBuilderX 版本 >= 4.7.0
挂载在 uni 上
// #ifdef APP-PLUS
import {
getCalendarInfo,
setCalendarInfo,
deleteCalendarInfo,
queryCalendarEvents,
createCalendarEvent,
deleteCalendarEvent,
getCalendarInfoAsync,
setCalendarInfoAsync,
deleteCalendarInfoAsync,
queryCalendarEventsAsync,
createCalendarEventAsync,
deleteCalendarEventAsync,
} from "@/uni_modules/xl-calendar-info";
const u: any = uni;
u.getCalendarInfo ??= getCalendarInfo as any;
u.setCalendarInfo ??= setCalendarInfo as any;
u.deleteCalendarInfo ??= deleteCalendarInfo as any;
u.queryCalendarEvents ??= queryCalendarEvents as any;
u.createCalendarEvent ??= createCalendarEvent as any;
u.deleteCalendarEvent ??= deleteCalendarEvent as any;
u.getCalendarInfoAsync ??= getCalendarInfoAsync as any;
u.setCalendarInfoAsync ??= setCalendarInfoAsync as any;
u.deleteCalendarInfoAsync ??= deleteCalendarInfoAsync as any;
u.queryCalendarEventsAsync ??= queryCalendarEventsAsync as any;
u.createCalendarEventAsync ??= createCalendarEventAsync as any;
u.deleteCalendarEventAsync ??= deleteCalendarEventAsync as any;
// #endif
// #ifndef APP-PLUS
const notSupport = (name: string) => (options?: any) => {
const err = { errMsg: `${name}:fail not support on current platform` };
options?.fail?.(err);
options?.complete?.(err);
};
const u2: any = uni;
u2.getCalendarInfo ??= notSupport("getCalendarInfo");
u2.setCalendarInfo ??= notSupport("setCalendarInfo");
u2.deleteCalendarInfo ??= notSupport("deleteCalendarInfo");
u2.queryCalendarEvents ??= notSupport("queryCalendarEvents");
u2.createCalendarEvent ??= notSupport("createCalendarEvent");
u2.deleteCalendarEvent ??= notSupport("deleteCalendarEvent");
u2.getCalendarInfoAsync ??= notSupport("getCalendarInfoAsync");
u2.setCalendarInfoAsync ??= notSupport("setCalendarInfoAsync");
u2.deleteCalendarInfoAsync ??= notSupport("deleteCalendarInfoAsync");
u2.queryCalendarEventsAsync ??= notSupport("queryCalendarEventsAsync");
u2.createCalendarEventAsync ??= notSupport("createCalendarEventAsync");
u2.deleteCalendarEventAsync ??= notSupport("deleteCalendarEventAsync");
// #endif
- 然后在
main.ts引入使用即可
import "./plugins/calendar-bridge";
使用方法
获取日历账户信息
uni.getCalendarInfo({
success: (res) => {
console.log("获取日历信息成功:", res);
// res.Calendars 包含所有日历账户信息
res.Calendars.forEach((calendar) => {
console.log("日历ID:", calendar.calendarId);
console.log("账户名:", calendar.accountName);
console.log("显示名称:", calendar.displayName);
console.log("是否可见:", calendar.visible);
console.log("访问级别:", calendar.accessLevel);
});
},
fail: (err) => {
console.error("获取日历信息失败:", err);
},
complete: (res) => {
console.log("操作完成:", res);
},
});
设置日历账户
uni.setCalendarInfo(
{
ACCOUNT_NAME: "com.maimai.international",
ACCOUNT_TYPE: "com.maimai",
OWNER_ACCOUNT: "com.maimai.international",
NAME: "MaiMai International",
CALENDAR_DISPLAY_NAME: "买买国际",
CALENDAR_TIME_ZONE: "Asia/Shanghai",
VISIBLE: 1,
SYNC_EVENTS: 1,
CALENDAR_ACCESS_LEVEL: 700,
},
{
success: (res) => {
console.log("设置成功:", res.Calendars);
},
fail: (err) => {
console.error("设置失败:", err);
},
complete: (res) => {
console.log("操作完成:", res);
},
}
);
删除日历账户(deleteCalendarInfo)
uni.deleteCalendarInfo(
{ calendarId: 12 },
{
success: (res) => {
console.log("删除成功", res.deletedCount);
},
fail: (err) => {
console.error("删除失败", err);
},
complete: (res) => {
console.log("操作完成", res);
},
}
);
// 按账户名批量删除(遍历该 ACCOUNT_NAME 下的所有 ACCOUNT_TYPE)
uni.deleteCalendarInfo(
{ ACCOUNT_NAME: "your_account_name" },
{
success: (res) => {
console.log("按账户名删除完成", res.deletedCount);
},
fail: (err) => {
console.error("删除失败", err);
},
}
);
配置项 DeleteConfigOptions
calendarId?: number:指定要删除的日历 ID。ACCOUNT_NAME?: string:按账户名删除该账户名下的所有类型(会遍历匹配到的ACCOUNT_TYPE并逐个删除)。
返回数据结构
interface DeleteCalendarResult {
errMsg: string; // 'deleteCalendarInfo:ok' | 错误信息
deletedCount: number; // 实际删除的条目数
}
错误码(删除)
1001:getAppContext 为 null。1002:参数不合法或删除失败。
重要注意事项
- 类型要求:
calendarId必须是数字类型(例如12),不要传字符串(例如'12')。 - 可删除范围:Android 的日历账户有所有权/适配器限制。通常只有“你通过本插件
setCalendarInfo创建的日历”(或你 App 自己的 SyncAdapter 管理的账户)才允许删除。第三方/系统日历(如厂商/Google/其他 App 创建的,如BOSS直聘账户)通常不可由你的 App 删除,resolver.delete(...)会返回0。 accessLevel=700表示该日历对其“所属账户”的权限级别,不是你 App 的系统权限,不代表你的 App 可以删除它。- 运行时权限:执行删除前需授予
WRITE_CALENDAR权限;仅读取需READ_CALENDAR。 - 设备差异:不同 ROM/设备对第三方删除系统/他人账户的策略可能更严格,出现
deletedCount=0属正常受限行为。
常见问题与排查
deletedCount = 0- 检查该日历是否由你 App 创建;第三方/系统账户通常不可删。
- 确认已授权
WRITE_CALENDAR;未授权会失败或返回 0。 - 若你本地定制过删除实现,请确认删除逻辑已启用并正确执行(未被注释、已重新打包到 App)。
配置项 ConfigOptions
- ACCOUNT_NAME: 账户名。标识日历所属账户。
- ACCOUNT_TYPE: 账户类型。标识账户的类型。
- OWNER_ACCOUNT: 所有者账户。通常与
ACCOUNT_NAME相同。 - NAME: 日历名称。内部名称。
- CALENDAR_DISPLAY_NAME: 日历显示名。展示给用户看的名称。
- CALENDAR_TIME_ZONE: 日历时区。如
Asia/Shanghai。 - VISIBLE: 是否可见。
1可见,0不可见。 - SYNC_EVENTS: 是否同步事件。
1同步,0不同步。 - CALENDAR_ACCESS_LEVEL: 访问级别。见下表。
访问级别(CALENDAR_ACCESS_LEVEL)
- 0: CAL_ACCESS_NONE(无)
- 100: CAL_ACCESS_FREEBUSY(仅忙闲)
- 200: CAL_ACCESS_READ(只读)
- 300: CAL_ACCESS_RESPOND(可响应)
- 400: CAL_ACCESS_OVERRIDE(可覆盖)
- 500: CAL_ACCESS_CONTRIBUTOR(贡献者)
- 600: CAL_ACCESS_EDITOR(编辑)
- 700: CAL_ACCESS_OWNER(所有者,默认)
- 800: CAL_ACCESS_ROOT(Root)
返回数据结构
interface InsertCalendarResult {
calendarId: number;
accountName: string;
accountType: string;
ownerAccount: string | null;
name: string | null;
displayName: string | null;
visible: boolean;
syncEvents: boolean | null;
accessLevel: number | null;
timeZone: string | null;
}
interface SetCalendarResult {
errMsg: string;
Calendars: InsertCalendarResult;
}
错误码
- 1001: getAppContext 为 null。
- 1002: 参数不合法或插入失败(如账号/类型为空、系统限制等)。
新增日历事项(createCalendarEvent)
// 创建国庆节事项
uni.createCalendarEvent(
{
calendarId: 11,
title: "国庆节",
description: "国庆节放假内容",
dtStart: 1759276800000, // 开始时间(毫秒时间戳)
dtEnd: 1759327200000, // 结束时间(毫秒时间戳)
eventTimeZone: "Asia/Shanghai",
location: "天安门广场",
hasAlarm: true,
reminderMinutes: 90, // 提前90分钟提醒
accessLevel: 0, // 访问级别:0=公开, 1=机密, 2=私密
availability: 0, // 忙闲状态:0=忙碌, 1=空闲, 2=待定
},
{
success: (res) => {
console.log("新增事项成功", res);
console.log("事项ID:", res.eventId);
},
fail: (err) => {
console.error("新增事项失败", err);
},
complete: (res) => {
console.log("操作完成", res);
},
}
);
配置项 CreateEventConfig
- calendarId:
number- 日历 ID(必填) - title:
string- 事项标题(可选) - description:
string- 事项描述(可选) - dtStart:
number- 开始时间,毫秒时间戳(必填) - dtEnd:
number- 结束时间,毫秒时间戳(必填) - allDay:
boolean- 是否全天事件(可选,默认 false) - eventTimeZone:
string- 时区(可选,默认设备时区) - location:
string- 地点(可选) - hasAlarm:
boolean- 是否设置提醒(可选) - reminderMinutes:
number- 提醒提前分钟数(可选,默认 10 分钟) - accessLevel:
number- 访问级别(可选,默认 0)-1: 默认0: 公开1: 机密2: 私密
- availability:
number- 忙闲状态(可选,默认 0)0: 忙碌1: 空闲2: 待定
返回数据结构
interface CreateEventResult {
errMsg: string; // 'createCalendarEvent:ok' | 错误信息
eventId: number; // 创建的事项ID
}
错误码(新增事项)
- 2001: getAppContext 为 null
- 2002: 参数不合法或创建失败
查询日历事项(queryCalendarEvents)
// 查询指定日历的所有事项
uni.queryCalendarEvents(
{
calendarId: 11,
},
{
success: (res) => {
console.log("获取事项成功", res);
res.events.forEach((event) => {
console.log("事项ID:", event.eventId);
console.log("标题:", event.title);
console.log("开始时间:", new Date(event.dtStart));
console.log("结束时间:", new Date(event.dtEnd));
console.log("地点:", event.location);
console.log("提醒分钟:", event.reminderMinutes);
});
},
fail: (err) => {
console.error("获取事项失败", err);
},
complete: (res) => {
console.log("操作完成", res);
},
}
);
// 按时间范围查询
uni.queryCalendarEvents(
{
calendarId: 11,
start: 1759276800000, // 开始时间戳
end: 1759327200000, // 结束时间戳
},
{
success: (res) => {
console.log("时间范围内的事项:", res.events);
},
fail: (err) => {
console.error("查询失败", err);
},
}
);
// 按关键词搜索
uni.queryCalendarEvents(
{
calendarId: 11,
search: "国庆", // 搜索标题或描述中包含"国庆"的事项
},
{
success: (res) => {
console.log("搜索结果:", res.events);
},
fail: (err) => {
console.error("搜索失败", err);
},
}
);
配置项 QueryEventConfig
- calendarId:
number- 日历 ID(可选,不指定则查询所有日历) - start:
number- 开始时间戳(可选) - end:
number- 结束时间戳(可选) - search:
string- 搜索关键词(可选,在标题和描述中搜索)
返回数据结构
interface QueryEventResult {
errMsg: string; // 'queryCalendarEvents:ok' | 错误信息
events: CalendarEvent[]; // 事项列表
}
interface CalendarEvent {
eventId: number; // 事项ID
calendarId: number; // 日历ID
title: string | null; // 标题
description: string | null; // 描述
dtStart: number; // 开始时间(毫秒时间戳)
dtEnd: number; // 结束时间(毫秒时间戳)
allDay: boolean; // 是否全天
eventTimeZone: string | null; // 开始时区
eventEndTimeZone: string | null; // 结束时区
location: string | null; // 地点
hasAlarm: boolean | null; // 是否有提醒
availability: number | null; // 忙闲状态
accessLevel: number | null; // 访问级别
reminderMinutes?: number | null; // 提醒分钟数
}
错误码(查询事项)
- 2001: getAppContext 为 null
- 2002: 查询失败
删除日历事项(deleteCalendarEvent)
// 按时间范围删除事项
uni.deleteCalendarEvent(
{
calendarId: 11,
start: 1759276800000, // 开始时间戳
end: 1759327200000, // 结束时间戳
},
{
success: (res) => {
console.log("删除事项成功", res);
console.log("删除数量:", res.deletedCount);
},
fail: (err) => {
console.error("删除事项失败", err);
},
complete: (res) => {
console.log("操作完成", res);
},
}
);
配置项 DeleteEventConfig
- calendarId:
number- 日历 ID(必填) - start:
number- 开始时间戳(必填) - end:
number- 结束时间戳(必填)
注意: 删除功能目前仅支持按时间范围批量删除,不支持按单个 eventId 删除。
返回数据结构
interface DeleteEventResult {
errMsg: string; // 'deleteCalendarEvent:ok' | 错误信息
deletedCount: number; // 实际删除的事项数量
}
错误码(删除事项)
- 2001: getAppContext 为 null
- 2002: 参数不合法或删除失败
完整使用示例
以下是一个完整的日历事项管理示例,展示如何组合使用所有功能:
// 1. 首先获取现有日历信息
uni.getCalendarInfo({
success: (res) => {
console.log("现有日历:", res.Calendars);
// 如果没有合适的日历,创建一个新的
if (res.Calendars.length === 0) {
createNewCalendar();
} else {
// 使用第一个日历
const calendarId = res.Calendars[0].calendarId;
manageEvents(calendarId);
}
},
fail: (err) => {
console.error("获取日历失败:", err);
},
});
// 2. 创建新日历
function createNewCalendar() {
uni.setCalendarInfo(
{
ACCOUNT_NAME: "com.example.myapp",
ACCOUNT_TYPE: "com.example",
OWNER_ACCOUNT: "com.example.myapp",
NAME: "MyApp Calendar",
CALENDAR_DISPLAY_NAME: "我的应用日历",
CALENDAR_TIME_ZONE: "Asia/Shanghai",
VISIBLE: 1,
SYNC_EVENTS: 1,
CALENDAR_ACCESS_LEVEL: 700,
},
{
success: (res) => {
console.log("创建日历成功:", res.Calendars);
manageEvents(res.Calendars.calendarId);
},
fail: (err) => {
console.error("创建日历失败:", err);
},
}
);
}
// 3. 管理日历事项
function manageEvents(calendarId) {
// 创建事项
const now = new Date();
const startTime = now.getTime();
const endTime = now.getTime() + 2 * 60 * 60 * 1000; // 2小时后
uni.createCalendarEvent(
{
calendarId: calendarId,
title: "重要会议",
description: "与客户的重要会议",
dtStart: startTime,
dtEnd: endTime,
eventTimeZone: "Asia/Shanghai",
location: "会议室A",
hasAlarm: true,
reminderMinutes: 30,
accessLevel: 0,
availability: 0,
},
{
success: (res) => {
console.log("创建事项成功:", res);
// 查询所有事项
queryAllEvents(calendarId);
},
fail: (err) => {
console.error("创建事项失败:", err);
},
}
);
}
// 4. 查询所有事项
function queryAllEvents(calendarId) {
uni.queryCalendarEvents(
{ calendarId: calendarId },
{
success: (res) => {
console.log("所有事项:", res.events);
// 按时间范围查询
const today = new Date();
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
uni.queryCalendarEvents(
{
calendarId: calendarId,
start: today.getTime(),
end: tomorrow.getTime(),
},
{
success: (res) => {
console.log("今天的事项:", res.events);
// 搜索特定事项
searchEvents(calendarId);
},
fail: (err) => {
console.error("查询今天事项失败:", err);
},
}
);
},
fail: (err) => {
console.error("查询事项失败:", err);
},
}
);
}
// 5. 搜索事项
function searchEvents(calendarId) {
uni.queryCalendarEvents(
{
calendarId: calendarId,
search: "会议",
},
{
success: (res) => {
console.log("搜索结果:", res.events);
// 删除事项(示例:删除今天的所有事项)
deleteTodayEvents(calendarId);
},
fail: (err) => {
console.error("搜索失败:", err);
},
}
);
}
// 6. 删除事项
function deleteTodayEvents(calendarId) {
const today = new Date();
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
uni.deleteCalendarEvent(
{
calendarId: calendarId,
start: today.getTime(),
end: tomorrow.getTime(),
},
{
success: (res) => {
console.log("删除事项成功,删除数量:", res.deletedCount);
},
fail: (err) => {
console.error("删除事项失败:", err);
},
}
);
}
Async 方法使用
以下演示六个 Async 方法(Promise 风格)的调用:
// 1) 获取日历账户(Promise)
uni
.getCalendarInfoAsync()
.then((res) => {
console.log("获取日历信息成功:", res);
})
.catch((err) => {
console.error("获取日历信息失败:", err);
});
// 2) 设置/创建日历账户(Promise)
uni
.setCalendarInfoAsync({
ACCOUNT_NAME: "com.example.myapp",
ACCOUNT_TYPE: "com.example",
OWNER_ACCOUNT: "com.example.myapp",
NAME: "MyApp Calendar",
CALENDAR_DISPLAY_NAME: "我的应用日历",
CALENDAR_TIME_ZONE: "Asia/Shanghai",
VISIBLE: 1,
SYNC_EVENTS: 1,
CALENDAR_ACCESS_LEVEL: 700,
})
.then((res) => {
console.log("设置成功:", res.Calendars);
})
.catch((err) => {
console.error("设置失败:", err);
});
// 3) 按ID或账户名删除日历账户(Promise)
uni
.deleteCalendarInfoAsync({ calendarId: 12 })
.then((res) => {
console.log("删除成功:", res.deletedCount);
})
.catch((err) => {
console.error("删除失败:", err);
});
// 4) 查询事项(可带条件)(Promise)
uni
.queryCalendarEventsAsync({ calendarId: 11, search: "会议" })
.then((res) => {
console.log("查询成功:", res.events);
})
.catch((err) => {
console.error("查询失败:", err);
});
// 5) 新增事项(Promise)
uni
.createCalendarEventAsync({
calendarId: 11,
title: "重要会议",
description: "与客户的重要会议",
dtStart: Date.now(),
dtEnd: Date.now() + 2 * 60 * 60 * 1000,
eventTimeZone: "Asia/Shanghai",
hasAlarm: true,
reminderMinutes: 30,
})
.then((res) => {
console.log("新增事项成功, 事项ID:", res.eventId);
})
.catch((err) => {
console.error("新增事项失败:", err);
});
// 6) 按时间范围删除事项(Promise)
const today = new Date();
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000);
uni
.deleteCalendarEventAsync({
calendarId: 11,
start: today.getTime(),
end: tomorrow.getTime(),
})
.then((res) => {
console.log("删除事项成功, 删除数量:", res.deletedCount);
})
.catch((err) => {
console.error("删除事项失败:", err);
});
返回数据结构
interface Calendar {
calendarId: number; // 日历ID
accountName: string; // 账户名称
accountType: string; // 账户类型
ownerAccount: string | null; // 所有者账户
name: string | null; // 日历名称
displayName: string | null; // 显示名称
visible: boolean; // 是否可见
syncEvents: boolean; // 是否同步事件
isPrimary: boolean | null; // 是否为主日历
accessLevel: number | null; // 访问级别
timeZone: string | null; // 时区
color: number | null; // 颜色
deleted: boolean | null; // 是否已删除
allowedReminders: string | null; // 允许的提醒方式
allowedAvailability: string | null; // 允许的可用性
allowedAttendeeTypes: string | null; // 允许的参与者类型
}
权限说明
本插件需要以下 Android 权限:
READ_CALENDAR- 读取日历数据(用于getCalendarInfo、queryCalendarEvents)WRITE_CALENDAR- 写入/创建日历(用于setCalendarInfo、createCalendarEvent、deleteCalendarEvent)
平台支持
- ✅ Android (API 21+)
- ❌ iOS (暂不支持)
- ❌ H5 (暂不支持)
- ❌ 小程序 (暂不支持)
注意事项
- 仅支持 Android 平台
- 使用
getCalendarInfo、queryCalendarEvents需授权读取权限;使用setCalendarInfo、createCalendarEvent、deleteCalendarEvent需授权读写权限 - 建议在用户交互后调用,避免权限弹窗被拦截
- 写入日历时需要提供有效的
ACCOUNT_NAME与ACCOUNT_TYPE。部分 ROM 对无对应同步适配器(SyncAdapter)的账户类型可能拒绝创建日历,属于系统行为差异 - 若未指定时区,将使用设备默认时区;
VISIBLE/SYNC_EVENTS取值为0/1 - 时间戳使用毫秒级时间戳,可通过
new Date().getTime()获取当前时间戳 - 删除事项功能目前仅支持按时间范围批量删除,不支持按单个 eventId 删除
- 提醒功能需要设备支持,部分 ROM 可能不支持自定义提醒时间
更新日志
v1.1.0
- 新增日历事项管理功能
- 支持创建日历事项(createCalendarEvent)
- 支持查询日历事项(queryCalendarEvents)
- 支持删除日历事项(deleteCalendarEvent)
- 支持提醒、位置、访问级别等高级功能
- 支持按时间范围和关键词搜索
v1.0.0
- 初始版本发布
- 支持获取 Android 系统日历信息
- 完整的类型定义和错误处理
许可证
MIT License

收藏人数:
购买源码授权版(
试用
赞赏(0)
下载 8
赞赏 0
下载 10694979
赞赏 1797
赞赏
京公网安备:11010802035340号