uni-app 系统日历 API 实战:uni.addPhoneCalendar 与 uni.addPhoneRepeatCalendar 完整指南
2026/9/20 8:01:47 网站建设 项目流程

uni-app 系统日历 API 实战:uni.addPhoneCalendar 与 uni.addPhoneRepeatCalendar 完整指南

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

uni-app 提供了uni.addPhoneCalendaruni.addPhoneRepeatCalendar两个系统日历 API,分别用于向设备系统日历写入单次事件与周期性重复事件(如提醒、日程、纪念日)。本文基于仓库文档 docs/api/calendar.md 展开,完整覆盖两个 API 的参数定义、兼容性矩阵、统一错误码、平台差异限制与可运行的调用示例,帮助读者在 App(Android / iOS / HarmonyOS)与微信小程序中快速实现"一键写入系统日历"能力。

一、API 总览与适用场景

系统日历 API 属于设备能力类接口,核心价值在于:应用无需自建日程存储,而是直接调用系统日历服务创建事件,事件会自动同步到设备自带日历应用、系统提醒中,用户可以在系统层面管理这些日程。

两个 API 的分工如下:

| API | 功能 | 典型场景 | | :- | :- | :- | |uni.addPhoneCalendar| 向系统日历添加单次事件| 会议提醒、航班行程、一次性待办 | |uni.addPhoneRepeatCalendar| 向系统日历添加重复事件| 每周例会、每月账单日、每年纪念日 |

两者参数高度一致,重复事件 API 额外增加repeatInterval(重复周期)与repeatEndTime(重复截止时间)两个字段,并需要借助startTime计算规则生效的起始时刻。文档给出的官方示例把两个 API 合并为一个可提交的表单:当"重复周期"选择"不重复"时调用单次事件 API,其余选项调用重复事件 API(详见本文第六章)。

注意:该 API不支持 Web 平台,请在 App 或微信小程序环境体验。

二、uni.addPhoneCalendar:添加单次日历事件

向系统日历添加一个事件。调用方式:

uni.addPhoneCalendar({ title: '团队周会', startTime: 1739520000, // unix 时间戳(秒) allDay: false, notes: '讨论季度规划', location: '会议室 A', endTime: 1739523600, alarm: true, alarmOffset: 900, success: (res) => { console.log('success', res.errMsg) }, fail: (error) => { console.log('fail', error.errCode, error.errMsg) } })

参数说明

options 类型为AddPhoneCalendarOptions,各属性定义如下:

| 名称 | 类型 | 必备 | 默认值 | 描述 | | :- | :- | :- | :- | :- | | title | string | 是 | - | 日历事件标题 | | startTime | number | 是 | - | 开始时间的 unix 时间戳(自 1970-01-01 起经过的秒数) | | allDay | boolean | 否 | false | 是否全天事件,默认 false | | notes | string | 否 | - | 事件说明 | | location | string | 否 | - | 事件位置 | | endTime | number | 否 | - | 结束时间的 unix 时间戳,默认与开始时间相同 | | alarm | boolean | 否 | - | 是否提醒,默认 true | | alarmOffset | number | 否 | 0 | 提醒提前量,单位秒,默认 0 表示开始时提醒 | | path | string | 否 | - | 跳转小程序路径,必须与 signature 一起使用,填入后会自动生成跳转链接拼接在事件说明中 | | signature | string | 否 | - | 仅微信小程序支持;App 平台保留该字段但不使用。跳转小程序路径签名,必须与 path 一起使用,值为hmac_sha256(session_key, path)| | success | (res: AddPhoneCalendarSuccess) => void | 否 | - | 接口调用成功的回调函数 | | fail | (res: AddPhoneCalendarFail) => void | 否 | - | 接口调用失败的回调函数 | | complete | (res: AddPhoneCalendarSuccess | AddPhoneCalendarFail) => void | 否 | - | 接口调用结束的回调函数(成功、失败都会执行) | | description | string | 否 | - | 事件说明(微信小程序 4.41+ 支持) |

三、uni.addPhoneRepeatCalendar:添加重复日历事件

向系统日历添加重复事件。与单次事件 API 相比,新增repeatInterval(必填)与repeatEndTime(可选)两个字段,其余参数含义完全相同:

| 名称 | 类型 | 必备 | 默认值 | 描述 | | :- | :- | :- | :- | :- | | title | string | 是 | - | 日历事件标题 | | startTime | number | 是 | - | 开始时间的 unix 时间戳(秒) | | allDay | boolean | 否 | false | 是否全天事件,默认 false | | notes | string | 否 | - | 事件说明 | | location | string | 否 | - | 事件位置 | | endTime | number | 否 | - | 结束时间的 unix 时间戳,默认与开始时间相同 | | alarm | boolean | 否 | - | 是否提醒,默认 true | | alarmOffset | number | 否 | 0 | 提醒提前量,单位秒,默认 0 表示开始时提醒 | | path | string | 否 | - | 跳转小程序路径(须与 signature 同用) | | signature | string | 否 | - | 微信小程序专用:hmac_sha256(session_key, path)| | repeatInterval | string | 是 | month | 重复周期,默认 month 每月重复 | | repeatEndTime | number | 否 | - | 重复周期结束时间的 unix 时间戳,不填表示一直重复 | | success / fail / complete | 回调 | 否 | - | 与单次事件 API 一致 | | description | string | 否 | - | 事件说明(微信小程序 4.41+ 支持) |

repeatInterval 合法值

| 合法值 | 描述 | | :- | :- | | 'day' | 每天重复 | | 'week' | 每周重复 | | 'month' | 每月重复,该模式下日期不能大于 28 日(避免 30/31 号在不足月的月份缺失) | | 'year' | 每年重复 |

调用示例:

uni.addPhoneRepeatCalendar({ title: '每月账单日提醒', startTime: 1739520000, repeatInterval: 'month', // day | week | month | year repeatEndTime: 1771056000, // 可选,不填表示一直重复 allDay: false, alarm: true, alarmOffset: 0, success: (res) => {}, fail: (error) => {} })

四、回调返回值与统一错误处理

成功回调 AddPhoneCalendarSuccess / AddPhoneRepeatCalendarSuccess

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | errMsg | string | 否 | 接口调用结果信息,形如addPhoneCalendar:ok|

失败回调 AddPhoneCalendarFail / AddPhoneRepeatCalendarFail

| 名称 | 类型 | 必备 | 描述 | | :- | :- | :- | :- | | errCode | number | 是 | 错误码 | | errSubject | string | 是 | 统一错误主题(模块)名称 | | data | any | 否 | 错误信息中包含的数据 | | cause | Error | 否 | 源错误信息,可包含多个错误,详见 SourceError;具体结构可参考仓库的 错误规范文档 中UniError的定义 | | errMsg | string | 是 | 错误描述信息 |

errCode 错误码表

| 合法值 | 描述(英文原义) | 中文说明 | | :- | :- | :- | | 601 | title is required | 标题不能为空 | | 602 | startTime is invalid | 开始时间无效 | | 603 | endTime is invalid | 结束时间无效(不能早于开始时间) | | 604 | alarmOffset requires alarm | 设置提醒提前量前需要先开启提醒 | | 606 | repeat rule is invalid | 重复规则无效 | | 607 | calendar service is unavailable | 当前设备的日历服务不可用 | | 608 | add calendar event failed | 写入日历失败 | | 609 | calendar creation canceled | 用户取消了系统日历创建 |

文档提供的官方示例中,通过describeCalendarError(errCode)函数对上述错误码做了统一的中文映射(switch 分支逐一对应),并拼接errSubject / errCode / errMsg输出到页面日志,是处理日历 API 失败回调的推荐写法(见第六章示例)。

五、平台兼容性与特殊限制

兼容性矩阵

| Web | 微信小程序 | Android | iOS | HarmonyOS | | :- | :- | :- | :- | :- | | x | 4.41 | 5.08(单次)/ 5.09(重复) | 5.08(单次)/ 5.09(重复) | 5.08(单次)/ 5.09(重复) |

表格含义:数字为 HBuilderX / uni-app x 的版本号;x表示不支持。titlestartTime等核心参数在微信小程序 4.41、Android/iOS/HarmonyOS 5.09+ 均可用;description参数仅微信小程序 4.41 支持。

iOS 平台注意(tips)

文档特别提示:iOS 平台因系统权限问题,需要iOS 17 及以上系统才能正常工作;5.08 版本在 iOS 17 以下的系统如需使用,必须先获取日历访问权限;5.09+ 版本会对 iOS 17 以下的系统做出兼容支持。在 App 端实现时,建议针对 iOS 版本做能力判断或引导用户授予日历权限。

微信小程序 path / signature 机制

  • path填入后会自动生成跳转链接并拼接在事件说明中,用户点击日历事件即可跳转到小程序指定页面;
  • path必须与signature成对使用,签名算法为hmac_sha256(session_key, path),其中session_key为小程序会话密钥;
  • signature仅微信小程序生效,App 平台保留该字段但不会使用;
  • 官方示例在微信小程序下将path默认留空("微信小程序填 path 必须签名,默认不填"),而在 App 端则预填演示链接。

六、完整可运行示例(表单化调用两个 API)

文档给出了覆盖全部可填参数的 uvue 表单示例(页面路径pages/API/calendar/calendar.uvue),核心设计是:repeatInterval是否等于'none'作为切换两个 API 的分支。以下保留关键逻辑,可直接迁移到自己的页面。

模板要点(结构示意)

<template> <!-- #ifdef APP --> <scroll-view style="flex: 1;padding: 6px;"> <!-- #endif --> <!-- 表单字段:title / startTime(日期+时间 picker) / allDay / notes / location / endTime / alarm / alarmOffset / path / signature / repeatInterval / repeatEndTime --> <button class="submit-button" type="primary" @tap="submitCalendar">添加日历</button> <!-- #ifdef APP --> </scroll-view> <!-- #endif --> </template>

要点说明:

  • 全天事件(allDay = true)时隐藏时间选择器,只保留日期;
  • alarmOffset输入框在alarm关闭时置灰(:disabled="!alarm"),对应错误码 604 的约束;
  • repeatInterval的选项标签为「不重复 / 每天 / 每周 / 每月 / 每年」,值映射为'none' / 'day' / 'week' / 'month' / 'year'
  • 表单默认值:开始时间为当前时间的下一个整点,结束时间顺延一小时,重复截止时间默认 30 天后。

时间戳构建核心函数

function pad2(value : number) : string { return value > 9 ? value.toString() : `0${value}` } // 下一个整点时间戳(毫秒) function createNextHourTimestamp() : number { const date = new Date() date.setMinutes(0) date.setSeconds(0) date.setMilliseconds(0) date.setHours(date.getHours() + 1) return date.getTime() } // 由 "YYYY-MM-DD" + "HH:mm" 拼接时间戳(毫秒) function buildTimestamp(dateValue : string, timeValue : string) : number { const dateParts = dateValue.split('-') const timeParts = timeValue.split(':') if (dateParts.length != 3 || timeParts.length != 2) { return 0 } const year = parseInt(dateParts[0]) const month = parseInt(dateParts[1]) - 1 const day = parseInt(dateParts[2]) const hour = parseInt(timeParts[0]) const minute = parseInt(timeParts[1]) const date = new Date() date.setFullYear(year); date.setMonth(month); date.setDate(day) date.setHours(hour); date.setMinutes(minute) date.setSeconds(0); date.setMilliseconds(0) return date.getTime() }

提交逻辑:分支调用两个 API

function submitCalendar() : void { const startTime = buildStartTimeForSubmit() // 全天用日期 0 点,否则用 buildTimestamp const endTime = buildEndTimeForSubmit() const alarmOffset = parseOffsetSeconds(alarmOffsetSeconds.value) const repeatValue = repeatIntervalValues[repeatIntervalIndex.value] // 'none'|'day'|'week'|'month'|'year' const baseOptions : AddPhoneCalendarOptions = { title: title.value, startTime: startTime, allDay: allDay.value, notes: notesText.value, location: location.value, endTime: endTime, alarm: alarm.value, alarmOffset: alarmOffset, path: path.value, signature: signature.value, success: (res) => handleAddPhoneCalendarSuccess('addPhoneCalendar', res), fail: (error) => handleAddPhoneCalendarFail('addPhoneCalendar', error) } // 不重复:调用单次事件 API if (repeatValue == 'none') { uni.addPhoneCalendar(baseOptions) return } // 重复:调用重复事件 API,追加 repeatInterval 与 repeatEndTime const repeatOptions : AddPhoneRepeatCalendarOptions = { title: baseOptions.title, startTime: baseOptions.startTime, allDay: baseOptions.allDay, notes: baseOptions.notes, location: baseOptions.location, endTime: baseOptions.endTime, alarm: baseOptions.alarm, alarmOffset: baseOptions.alarmOffset, path: baseOptions.path, signature: baseOptions.signature, repeatInterval: repeatValue as CalendarRepeatInterval, repeatEndTime: buildRepeatEndTimeForSubmit(), success: (res) => handleAddPhoneRepeatCalendarSuccess('addPhoneRepeatCalendar', res), fail: (error) => handleAddPhoneRepeatCalendarFail('addPhoneRepeatCalendar', error) } uni.addPhoneRepeatCalendar(repeatOptions) }

失败回调统一处理与错误码映射

function describeCalendarError(errCode : number) : string { switch (errCode) { case 601: return '标题不能为空' case 602: return '开始时间无效' case 603: return '结束时间不能早于开始时间' case 604: return '设置提醒提前量前需要先开启提醒' case 606: return '重复规则无效' case 607: return '当前设备的日历服务不可用' case 608: return '写入日历失败' case 609: return '用户取消了系统日历创建' default: return '未知错误' } } function handleCalendarFailResult(action : string, errSubject : string | null, errCode : number, errMsg : string | null) : void { const subject = errSubject != null ? errSubject : 'uni-calendar' const message = errMsg != null ? errMsg : '' const errorDescription = describeCalendarError(errCode) // 输出:`失败 (601); 标题不能为空; errSubject=uni-calendar; errCode=601; errMsg=...` updateResult(action, `失败 (${errCode})`, `${errorDescription}; errSubject=${subject}; errCode=${errCode}; errMsg=${message}`) }

示例中的describeCalendarError分支与文档错误码表严格对应(601~609),是理解各错误码实际语义的权威参考。运行示例时建议将项目运行到 App 平台(该 API 不支持 Web)。

七、源码与文档佐证

  • 本文全部参数、错误码、兼容性数据均出自 docs/api/calendar.md 的 UTSAPIJSON 定义(@addphonerepeatcalendar@addphonecalendar两节),是接口实现的唯一事实来源。
  • 失败回调中的cause(UniError / SourceError)结构可参阅仓库的 错误规范文档。
  • 仓库中另有日历 UI 组件实现可供参考(注意与系统日历 API 是不同主题):农历日历数据与算法 提供了 1900-2100 年农历闰月/大小月数据表与solar2lunar公农历转换实现,对应页面 使用getDrawableContext()绘制日历网格,测试用例 中通过process.env.uniTestPlatformInfo区分 Web / 小程序 / App 环境——这与系统日历 API"不支持 Web"的兼容性约束在测试策略上是同一套思路。

八、最佳实践小结

  1. 必填校验前置titlestartTime缺失分别对应错误码 601、602,提交前先做非空校验;alarmOffset依赖alarm开启(错误码 604),UI 上应联动禁用。
  2. 时间戳统一:参数使用unix 秒级时间戳(示例中buildTimestamp先得到毫秒值,可在构造 options 前除以 1000 换算),全天事件建议使用当地 0 点时间戳,避免时区偏差。
  3. 重复事件注意日期上限month模式日期不能大于 28 日,否则会因小月缺失导致规则无效(错误码 606)。
  4. 微信小程序跳转pathsignature必须成对出现,签名算法为hmac_sha256(session_key, path);App 端无需关心该字段。
  5. iOS 版本适配:iOS 17 以下需在 5.09+ 版本上运行,并建议先引导用户授予日历访问权限。
  6. 失败回调兜底:统一按errSubject / errCode / errMsg结构化记录日志,便于定位具体平台的日历服务异常(错误码 607/608/609 均属于系统层面的失败)。

通过以上两个 API,开发者可以在 uni-app x 项目中以极少的代码实现系统级日程写入,并借助重复事件能力覆盖周期性提醒场景;配合官方表单示例的分支调用模式,即可在一个页面中完整承载两个 API 的全部参数。

【免费下载链接】uni-appA cross-platform framework using Vue.js项目地址: https://gitcode.com/gh_mirrors/un/uni-app

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询