一个运行在 Android 上的 考研英语单词定时推送 桌面小组件 + App。 每天按计划推送一组单词(桌面小组件 + 通知),并根据距离初试的天数自动倒推每日新学词量。
📖 详细说明见 docs/项目说明.md —— 功能、算法、状态字段、构建方式、版本历史都在里面。
⚠️ 本项目由 AI 辅助构建 本仓库的源码、构建脚本与文档均经由 AI(大语言模型) 辅助,经人工测试与调试后开源。 仅供学习交流使用,请自行评估(尤其是定时/通知/权限相关行为)后再安装使用。
最新版本见 Releases:
- v1.3.2-repair:kaoyan-widget-v1.3.2-repair.apk
- v1.3.2:kaoyan-widget-v1.3.2.apk
- v1.3.1:kaoyan-widget-v1.3.1.apk
- v1.3:kaoyan-widget-v1.3.apk
- v1.2.1:kaoyan-widget-v1.2.1.apk
- v1.2:kaoyan-widget-v1.2.apk
- v1.1.1:kaoyan-widget-v1.1.1.apk
# 安装 / 覆盖升级
pm install -r -d kaoyan-widget-v1.3.2-repair.apk| 开屏提醒(每日首次打开) | 权限引导(首次启动) | 主界面 · 今日单词 | 仅英文(自测模式) | 设置 |
|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
截图为实机运行效果(OnePlus / ColorOS)。首次启动会申请通知权限,并弹窗引导开启自启动、关闭电池优化。
- 单词显示模式切换(v1.3.2):主页「回到顶部」圆钮正上方多了一个只写一个字的小圆钮,尺寸与「回到顶部」一致(44×44), 点一下在 双语 → 仅英文 → 仅中文 → 双语 之间循环(圆钮上的字同步变成「双」/「英」/「中」)。 切到「仅英文」只留单词 + 音标、藏掉释义;切到「仅中文」只留释义(音标一起藏)—— 合上中文就能自测默写。 切换只影响「今日单词」页面:通知推送、学习弹幕、桌面小组件照旧显示中英双语; 选择写进 state.json 的 view_mode,下次打开 App 仍是上次那档。
- 每日开屏提醒(v1.3.1):每天第一次打开 App 时全屏弹一次「距离初试还剩 N 天」动画
(数字滚动 + 当天随机 2 个单词),2 秒自动淡出,点任意处或右上角
×可立即关闭;每天只弹一次。 - 首次启动设置向导:第一次打开时引导设置初试日期,未设置前不会推送到通知。
- 初试日期可配置:默认
2027-12-20,可在 App 内随时修改。 - 按剩余天数自动倒推每日词量:
dailyNew = ceil((词库总数 - 已学)/剩余天数),并夹在1 ~ 300之间;- 复习上限
reviewCap = max(40, dailyNew)。
- 词库可替换:内置考研词表(5398 词),支持导入自定义
txt(#注释、多分隔符),也支持一键恢复内置词库。 - 定时推送:通过
AlarmManager定时触发,桌面小组件刷新 + 通知栏推送。 - 推送时段可自定义:在「设置」里可设置每天的推送起止时间(默认
08:00–22:00),单词会在该时段内分批随机推送。 - 一次推送、两种呈现:闹钟到点推送一批单词时,同一批词既进通知、也按同样顺序以弹幕划过 (批次比日常频率略快,最多 2.5 秒一个);其余时间按设定频率随机弹。
- 单服务单通知:推送调度与学习弹幕合并进同一个前台服务
BotService, 通知栏只保留一条常驻通知(原来「推送运行中」+「学习弹幕已开启」两条)。 - 学习弹幕(悬浮窗,v1.2):使用手机时,从屏幕右侧向左划过一条「单词 + 释义」。
全天生效,不受推送时段限制(推送时段只管通知批次)。
- 弹出频率按 个/秒 自定义,亮屏 / 熄屏独立(熄屏默认
0= 不弹); - 样式可调:字体(默认 / 衬线 / 等宽)、字号、颜色、加粗;
- 选词与你当天的学习对齐:随机弹幕从「今天计划内的词」里抽,
并补上「已到期、但被
reviewCap挤出今天计划」的复习词; 其中复习词权重 3×、新词 1×,所以弹幕更像复习提醒。 只有当天计划尚未生成时才退回全词库兜底。 - 多条弹幕同时存在(最多 12 条),每条独占一条纵向「泳道」,绝不复用; 没有空泳道时宁可不弹,也不会让两条叠在同一行(叠字会造成「单词频闪」);
- 每条都完整飞到出屏才消失,不会「刚动一点就被下一条挤掉」;
- 需要「悬浮窗」权限,首次开启时 App 会引导授权。
- 弹出频率按 个/秒 自定义,亮屏 / 熄屏独立(熄屏默认
- 深色模式(v1.2):全部界面(含设置页与对话框)自动跟随系统深浅色。
- 开机自恢复:
BootReceiver在开机后重新注册闹钟;若弹幕处于开启状态,会一并恢复弹幕服务。 - 弹幕心跳自愈:每批推送闹钟都会顺带对齐一次弹幕服务,被系统冻结/杀进程后无需重新打开 App 即可恢复。
- 随剩余天数动态调整:每天根据已学进度重新推算当天计划。
kaoyan-widget/
├─ AndroidManifest.xml
├─ build.sh # 构建脚本(密码/密钥由环境变量传入,仓库不含密钥)
├─ assets/words.txt # 内置考研词表(5398 词)
├─ res/ # 资源(布局 / 图标 / 字符串 / 小组件信息)
└─ src/com/kaoyan/widget/
├─ MainActivity.java # App 主界面入口
├─ HtmlView.java # 基于 WebView 的界面与设置向导
├─ SplashView.java # 每日开屏提醒(倒计时 + 随机词,纯 Java 拼 HTML)
├─ Bridge.java # JS 与原生交互桥(定时任务用命名静态内部类)
├─ Engine.java # 学习计划推算核心(天数/每日词量/复习上限)
├─ Words.java # 词库加载(内置 / 自定义)
├─ Store.java # 本地状态存储(state.json)
├─ Scheduler.java # 定时调度(AlarmManager)
├─ Notifier.java # 通知
├─ WidgetProvider.java # 桌面小组件
├─ BatchReceiver.java # 定时批量推送接收器(兼作弹幕心跳)
├─ BootReceiver.java # 开机自恢复
├─ BotService.java # 唯一的常驻前台服务(推送调度 + 学习弹幕)
├─ DanmakuOverlay.java # 弹幕悬浮层(普通类:泳道 / 动画 / 批次队列)
└─ Perms.java # 权限申请与首次启动引导
环境要求:Termux(或 Linux)+ 可用的 aapt2 / javac / d8 / zipalign / apksigner,
以及 Android SDK 的 android.jar;Python3 用于把 classes.dex 注入 APK。
注意:需使用本机 OS 的 shell 内置
>>读取 heredoc;d8建议使用不针对匿名内部类报错的版本(本项目源码已避免使用匿名内部类)。
若
ANDROID_JAR是只有 class、没有资源表的android.jar(例如 App 自带的$HOME/android.jar),aapt2 link会报Theme.Material.Light.NoActionBar not found。build.sh会自动检测并改用/system/framework/framework-res.apk做资源链接(可用AAPT_I手动指定)。
# 1) 指定 android.jar 与你的签名密钥(密钥请自行生成,勿提交到仓库)
export ANDROID_JAR=$HOME/sdk/ex/android-34/android.jar
export KS=/path/to/your.jks
export KS_PASS=你的密钥库口令
export KEY_PASS=你的密钥口令
# 2) 构建
bash build.sh
# 产物:out/app.apk安装(示意):
adb install -r -d out/app.apk
# 或手机本地:
pm install -r -d out/app.apk本仓库不包含任何签名密钥、口令、Token 或用户数据:
- 签名密钥(
*.jks/*.keystore等)与口令一律 不提交(已列入.gitignore); - 运行数据(
state.json、history.jsonl、自定义词库等)不提交; - 仓库中不含任何账号、Token、API Key、个人身份信息。
- v1.3.2-repair
- 修复多音标词的中英文划分(issue #1):
pretend[priˈtend, priː-]这类给两个读音、音标里带空格的词, 原来按第一个空格切单词,正好切在音标中间 —— 单词带走半截音标、释义带走另一半,加粗范围和 「仅英文 / 仅中文」的隐藏全跟着串位。现在先按[定界、把音标整段吃到]再分释义。 - 内置词库里 553 条带空格音标的词全部修正;顺手修掉没有音标的词「单词+释义」粘在一起的问题
(
approximatea.近似的→approximate a.近似的)。 - 老记录自动还原:已经推出去的粘连行(history.jsonl 里的历史数据)在渲染时按当前词库反查还原, 不用等下一次推送、也不用清数据。
- 修复多音标词的中英文划分(issue #1):
- v1.3.2
- 单词显示模式切换:主页「回到顶部」正上方新增一个只写一个字的圆钮 —— 尺寸与「回到顶部」一致(44×44), 点一下在 双语 → 仅英文 → 仅中文 → 双语 之间循环,圆钮文字同步变「双」/「英」/「中」。
- 仅英文只留「单词[音标]」,仅中文只留释义(音标一起藏):合上中文就能自测默写。
- 切换即时生效(不重载页面),只影响「今日单词」页面:通知推送、学习弹幕、桌面小组件照旧双语; 选择存进 state.json 的 view_mode,重开 App 仍是上次那档。
- v1.3.1
- 每日开屏提醒:每天第一次打开 App 时全屏弹一次开屏动画 —— 紫渐变背景上 「距离初试」大数字从 0 滚到实际天数,再按阶段给一句鼓励语;同时从当天要学的词里随机挑 2 个 展示「单词 / 音标 / 释义」。
- 2 秒后自动淡出,点屏幕任意处或右上角
×可立即关闭;一天只弹一次(state.json的splash_day), 第二天自动恢复,首次设置日期前不弹;深色模式单独配色,读屏可识别为对话框。 - 每天第一次打开顺便记两个词,比纯倒计时多一点用处;
- 每次想更新日志怎么写总是头疼,于是看了看国民级的软件:修复了一些已知问题。
- v1.3
- 侧边栏改为底部 Dock:原来左侧抽屉的 5 个菜单项拆成 Dock 的两项 —— 「今日单词」(回主页 / 回顶部)和「设置」。 原抽屉里的「立即推送一批」「刷新数据」移到设置页的「快捷操作」卡片; 原「设置 / 换词库」就是 Dock 的「设置」本身。
- 回到顶部改为悬浮按钮:位于 Dock 上方,只在页面不在顶部时出现且可点击, 滚回顶部后自动隐藏。
- 设置页标题改为「设置」:去掉首次向导时期的「欢迎使用 · 考研单词」和那段引导语。
- 首页精简:去掉「推送时段 / 初试 / 每日词量」那一行, 初试倒计时改为标题行最右侧的斜体小字。
- Dock 两项加了
role="button"/aria-current,读屏(TalkBack)能正确识别为按钮。 - 新增 docs/项目说明.md:功能、学习计划算法、弹幕渲染、状态字段、构建与版本历史。
- v1.2.1
- 弹幕弹出频率改成「分档滑条」:原来是数字输入框(手机上要弹键盘、还能填出 0.37 这种无意义值),
现在是滑条 + 实时数值 + 刻度标签,固定 7 档:
0(不弹)/ 0.05 / 0.1 / 0.2 / 0.5 / 1 / 2,亮屏 / 熄屏各一条。 - 弹幕动画改为全局共享的 ~60fps 循环。原来用
ViewPropertyAnimator,它跟 Choreographer 走, 在本机 120Hz 屏上跑到约 91fps,同屏 1 条弹幕就吃掉约 30% 单核。 改为所有在飞弹幕共用一个固定帧间隔的循环后:帧率 91→42fps,动画期间进程 CPU 30.6%→17.9%。 - 弹幕关闭时定时器完全停下:原来即使关掉弹幕也每 5 秒空转一次(读 state.json + 查亮屏), 一天约 1.7 万次无谓唤醒。现在实测0 帧 / 0.00% CPU。
- 调度:推送一批不再重排当天全部闹钟(原来每次推送都会把 20+ 个精确闹钟 cancel + 重新 set 一遍)。已排好的闹钟本来就是「醒来推下一批」,不依赖当前进度。
- 调度:当天计划推完后撤销剩余批次闹钟(保留每日 ROLL 闹钟),不再白唤醒设备。
- 弹幕弹出频率改成「分档滑条」:原来是数字输入框(手机上要弹键盘、还能填出 0.37 这种无意义值),
现在是滑条 + 实时数值 + 刻度标签,固定 7 档:
- v1.2
- 新增 学习弹幕:使用手机时从屏幕右侧向左划过「单词 + 释义」, 全天生效、不受推送时段限制(推送时段只管通知批次)。
- 弹幕频率按 个/秒 自定义,亮屏 / 熄屏分别独立(
0= 不弹); 样式(字体 / 字号 / 颜色 / 加粗)可调,用描边阴影保证任意背景可读。 - 推送与弹幕整合:两者合并进唯一的常驻前台服务
BotService, 通知栏从两条常驻通知并为一条;推送一批单词时,同一批词既进通知、也按同样顺序以弹幕划过。 - 弹幕选词对齐当天学习:随机词池 = 今天计划内的词 + 已到期但被
reviewCap挤出计划的复习词 (复习词权重 3×、新词 1×),当天计划尚未生成时才退回全词库兜底,不再从 5398 词纯随机。 - 新增 深色模式:全部界面(含设置页与对话框)自动跟随系统深浅色。
- 多条弹幕同时存在(最多 12 条),每条独占一条纵向「泳道」且绝不复用, 没有空泳道时宁可不弹;各自飞完才消失。
- 新增首次开启弹幕时的「悬浮窗」权限引导。
- 修复:高频「单词频闪」——泳道 8→12 且不再复用已占泳道,并去掉「新弹幕一来就删掉半路那条」的淘汰。
- 修复:弹幕被「推送时段」闸掉(设好频率却因时段已过而完全不弹,且界面无任何提示)。
- 修复:弹幕服务被系统杀进程后静默停摆(要重新打开 App 才恢复)。
- 修复:在设置页点「保存并开始」时,若初试日期没变不再清空当天计划。
- v1.1.1
- 新增「每日推送时段」自定义:设置页可调整起止时间(默认
08:00–22:00),按新时段重排当天剩余批次。 - 修复:重复点击通知进入 App 后,返回键会停留在旧推送、无法回到桌面的问题。改为单实例(
singleTask)+ 返回键直接退出;再次点击通知自动刷新到最新推送。
- 新增「每日推送时段」自定义:设置页可调整起止时间(默认
- v1.1
- 首次启动申请通知权限,并引导开启自启动 / 关闭电池优化。
- README 增加实机截图。
MIT License,详见 LICENSE。
本项目(含代码与文档)由 AI 生成。




