用 React Native + Expo 开发一个大学生日程排程 App
前面我们已经介绍了如何用 AI 生成一份“AI 赋能大学生全流程计划”。但计划生成只是第一步,真正困难的是:这些任务到底怎么落到每天?怎么避开课表?怎么提醒自己?怎么和手机日历打通?
所以我做了一个配套 App:AI赋能大学生全流程计划。
这个 App 的目标不是做一个完整商业产品,而是练习如何用 React Native 实现一个带有以下能力的移动端工具:
- 解析 Markdown 表格任务
- 自动把任务排到未来 30 天
- 避开课程和手动添加的固定任务
- 设置本地提醒
- 同步到手机系统日历





技术栈主要使用:
React Native
Expo
expo-calendar
expo-notifications
AsyncStorage
一、创建 Expo 项目
先创建一个 Expo 项目:
npx create-expo-app ai-student-schedule-app
cd ai-student-schedule-app
安装需要的依赖:
npm install @react-native-async-storage/async-storage
npx expo install expo-calendar expo-notifications expo-status-bar
项目结构可以整理成这样:
src/
components/
Timeline.js
data/
sample.js
domain/
planImport.js
scheduler.js
services/
calendar.js
notifications.js
storage.js
App.js
app.json
二、设计任务数据结构
这个 App 里主要有三类数据。
第一类是 AI 计划任务:
{
id: "task-1",
title: "整理高数错题",
area: "学业提升",
durationMinutes: 35,
priority: 5,
preferredDay: 0,
window: "evening"
}
第二类是课程:
{
id: "course-1",
title: "高等数学",
weekday: 1,
startTime: "08:00",
endTime: "09:40",
weekRule: "full16",
location: "教学楼 A101"
}
第三类是手动任务:
{
id: "manual-1",
title: "社团会议",
date: "2026-04-27",
startTime: "19:00",
endTime: "20:00"
}
这里的 weekRule 用来处理大学课程常见的周次规则:
first8:前 8 周
second8:后 8 周
full16:1-16 周
三、解析 Markdown 任务表
为了让 App 能导入外部生成的计划,可以约定一种简单的 Markdown 表格格式:
| 天数 | 时段 | 任务 | 对应目标 | 优先级 | 时长 | 证据 |
| --- | --- | --- | --- | --- | --- | --- |
| 第1天 | 晚上 | 整理课程薄弱点 | 学业提升 | 必做 | 35 分钟 | 错题清单 |
...
| 第30天 | 晚上 | 月度复盘并生成下一轮计划 | 月度复盘 | 必做 | 60 分钟 | 复盘表 |
解析逻辑放在 src/domain/planImport.js 中,核心思路是:
- 先找 ```app-import 代码块
- 再解析 Markdown 表格
- 把中文字段转换成内部任务对象
- 把“第30天”转换成 preferredDay: 29
示例逻辑:
function parsePreferredDay(value) {
const match = String(value).match(/第?\s*(\d+)\s*天/);
if (!match) return 0;
return Number(match[1]) - 1;
}
时段可以这样转换:
function normalizeWindow(value) {
if (/上午|早上/.test(value)) return "morning";
if (/下午/.test(value)) return "afternoon";
if (/晚上|晚间/.test(value)) return "evening";
return "any";
}
四、实现自动排程
排程逻辑放在 src/domain/scheduler.js。
可以先定义每天可用的时间段:
const WINDOWS = {
morning: [["08:00", "12:00"]],
afternoon: [["14:00", "18:00"]],
evening: [["19:00", "22:30"]],
any: [["08:00", "12:00"], ["14:00", "18:00"], ["19:00", "22:30"]]
};
排程时需要判断时间是否冲突:
function overlaps(aStart, aEnd, bStart, bEnd) {
return aStart < bEnd && bStart < aEnd;
}
自动任务排入时,要避开:
课程时间
手动添加的固定任务
已经排进去的其他任务
基本流程是:
遍历 AI 任务
找到它偏好的日期
找到它偏好的时段
检查该时段是否有空位
如果冲突,就往后找下一个可用空位
如果 30 天内都找不到,就放入未排入列表
五、制作页面结构
主界面可以分成四个 Tab:
今日
计划
课表
手动
在 App.js 中定义:
const TABS = [
{ id: "today", label: "今日" },
{ id: "plan", label: "计划" },
{ id: "courses", label: "课表" },
{ id: "manual", label: "手动" }
];
“计划”页面负责粘贴任务表并导入。
“课表”页面负责添加固定课程。
“手动”页面负责添加某天某时段的固定事项。
“今日”页面展示当天和接下来几天的排程结果。
六、本地保存数据
用 AsyncStorage 保存课程、手动任务、导入任务和完成状态。
import AsyncStorage from "@react-native-async-storage/async-storage";
export async function saveAppState(state) {
await AsyncStorage.setItem("app-state", JSON.stringify(state));
}
export async function loadAppState(defaultState) {
const raw = await AsyncStorage.getItem("app-state");
return raw ? JSON.parse(raw) : defaultState;
}
这样关闭 App 后,已经导入的计划和课程不会丢失。
七、添加本地提醒
使用 expo-notifications。
import * as Notifications from "expo-notifications";
export async function scheduleTaskReminders(events) {
await Notifications.requestPermissionsAsync();
for (const event of events) {
const triggerTime = new Date(`${event.date}T${event.startTime}:00`);
triggerTime.setMinutes(triggerTime.getMinutes() - 5);
await Notifications.scheduleNotificationAsync({
content: {
title: "任务提醒",
body: event.title
},
trigger: triggerTime
});
}
}
这里设置的是任务开始前 5 分钟提醒。
八、同步系统日历
使用 expo-calendar 创建系统日历事件。
import * as Calendar from "expo-calendar";
export async function syncEventsToCalendar(events) {
const { status } = await Calendar.requestCalendarPermissionsAsync();
if (status !== "granted") {
throw new Error("没有日历权限");
}
const calendars = await Calendar.getCalendarsAsync(Calendar.EntityTypes.EVENT);
const calendarId = calendars[0]?.id;
for (const event of events) {
await Calendar.createEventAsync(calendarId, {
title: event.title,
startDate: new Date(`${event.date}T${event.startTime}:00`),
endDate: new Date(`${event.date}T${event.endTime}:00`),
notes: event.area
});
}
}
Android 真机测试时,需要在 app.json 中声明权限:
{
"android": {
"permissions": [
"READ_CALENDAR",
"WRITE_CALENDAR",
"POST_NOTIFICATIONS"
]
}
}
九、打包 Android APK
如果只调试,可以运行:
npx expo start
如果要生成 Android 安装包,可以使用本地构建或 EAS Build。
本地构建方式:
npx expo prebuild
cd android
gradlew assembleRelease
生成的 APK 通常在:
android/app/build/outputs/apk/release/
总结
这个 App 的开发重点不在复杂 UI,而在几个移动端开发常见能力:
文本解析
本地排程
冲突检测
本地存储
消息提醒
系统日历接入
Android 打包
通过这个项目,可以比较完整地练习 React Native 在真实工具类 App 中的开发流程。
更多推荐



所有评论(0)