钱迹强制周一 (Qianji Force Monday)

libxposed API 102 LSPosed 模块 —— 强制钱迹记账(com.mutangtech.qianji)每周第一天为周一 状态:✅ 已成功(用户实测打开钱迹即周一);v1.1.0 已重构为 api102 架构

🎯 解决的问题

钱迹记账 在一加手机(以及其他设备)上有个烦人的 bug:设置里允许用户选择"每周起始日:周一 / 周六 / 周日", 但选择永远固定不住——设置了周一,过段时间/重新打开又变回周日,烦不胜烦。

官方多次反馈未修复,于是自己动手,用 LSPosed Hook 强制锁定周一。

📦 下载 / 构建产物

  • GitHub Releases 提供官方签名的 APK(发布者 keystore,私钥不公开)
  • 源码自行构建./build.sh,默认 Android debug 签名,任何人开箱即用
版本 文件 说明
v1.1.0 (20) QianjiForceMonday_1.1.0(20).apk api102 重构版
v1.0.15 (17) QianjiForceMonday_v1.0.15(17).apk 传统 Xposed API 版(旧,仅 GitHub Releases;源码备份于 dev-guide/legacy-traditional-api/)

🔑 签名策略(FAQ:别人没有我的签名 / 没有 MT Manager 怎么办?)

  1. 想自己构建使用 → 直接 ./build.sh,脚本自动生成 debug keystore(CN=Android Debug) 签名, 不需要 MT Manager、不需要任何证书,clone 下来即可构建安装。
  2. 想发布给公众 → 用自己的 keystore 签名:./build.sh -k /path/to/my.keystore, 私钥永不公开,公众通过 GitHub Releases 下载你签名好的 APK。
  3. 升级时提示"签名冲突"? → 因为两版 APK 签名不同(debug 版 vs 官方版)。 解决办法:先卸载旧版再安装,或始终保持同一 keystore 构建。 这是 Android 系统的签名机制,与模块本身无关。

官方 Release 版(MT/自定义签名)与本地 debug 构建版 签名不同,无法互相覆盖安装; 如需无缝升级,请始终使用同一 keystore,或直接卸载重装。

🧠 原理

week 值语义(关键!)

钱迹使用 java.util.Calendar 标准

  • 1 = 周日
  • 2 = 周一 ← 我们要强制返回的值
  • 7 = 周六

读取链

getWeekStart()                          → L1 hook(直接返回 2)
  └─ c("week", 2)                       → L2 hook(key=week 返回 2)
       ├─ 已登录: va/c.l("apiconfu_week")  → va/d.getInt
       └─ 未登录: va/c.g("week")            → va/d.getInt
                                            → L3 hook(key=week/apiconfu_week 返回 2)

三重 Hook

目标 方法 逻辑
L1 qe.c.getWeekStart() 静态无参 直接返回 2(周一)
L2 qe.c.c(String,int) 静态 key="week" 返回 2(周一)
L3 va.d.getInt(String,int) 实例 key="week"/"apiconfu_week" 返回 2(周一)

只 hook 底层 va.d.getInt 不够:已登录时走 va/c.l() 且启动早期登录检查返回 false 时直接返回默认值, 根本不会到达 getInt。因此必须三重覆盖。

写入链(不拦截,数据安全)

CalendarHubPage.onMenuItemClick
  → qe.c.setWeekStart(I)Z
    → qe.c.d("week", I)Z  (登录时写入 apiconfu_week)

设置写入真实发生(MMKV 键值),模块只在读取时把值覆盖成周一。 不影响账单数据库,停用/卸载模块后设置恢复原始行为,完全可逆。

📁 项目结构

com.hook.qianji.weekstart/
├── AndroidManifest.xml            # minSdk=26;api102 无需 xposed meta-data
├── version.properties             # 版本管理(build.sh 自动递增)
├── build.sh                       # 构建: smali→aapt→打包(META-INF)→zipalign→apksigner
├── dev-guide/                      # 🧠 开发指南(技术架构 / 踩坑记录 / 环境信息)
│   ├── architecture.md            # 读取链、写入链、三重 hook 原理
│   ├── lessons.md                 # Smali 开发踩坑记录(签名 / OR逻辑 / 日志 / 混淆)
│   ├── environment.md             # 目标应用信息 / LSPosed 环境 / 混淆映射表
│   └── legacy-traditional-api/    # 旧版传统 Xposed API 源码备份
├── res/values/arrays.xml          # 资源(作用域数组,保留兼容)
├── src/
│   ├── meta-inf/META-INF/xposed/  # 📌 api102 模块声明
│   │   ├── java_init.list         # 入口类: com.hook.qianji.weekstart.MainHook
│   │   ├── module.prop            # minApiVersion=101 / targetApiVersion=102 / staticScope / autoHotReload
│   │   └── scope.list             # 作用域: com.mutangtech.qianji
│   └── smali/com/hook/qianji/weekstart/
│       ├── MainHook.smali         # api102 入口 (extends XposedModule) + 生命周期 + 热重载
│       ├── MainHook$WeekStartHooker.smali  # L1: qe.c.getWeekStart() 回调
│       ├── MainHook$QeCCHooker.smali       # L2: qe.c.c(String,int) 回调
│       └── MainHook$GetIntHooker.smali     # L3: va.d.getInt(String,int) 回调
└── release/                       # 构建产物

🔧 安装使用

  1. 下载 APK 安装
  2. LSPosed 管理器 → 模块 → 启用「钱迹强制周一」
  3. 勾选作用域:钱迹记账(com.mutangtech.qianji)
  4. 强制停止钱迹记账 → 重新打开
  5. 打开日历页(CalendarHubPage),确认周一起始 ✅

📜 日志确认

api102 版(v1.1.0+)日志 tag 为 QianjiWeekStart

QianjiWeekStart: 钱迹强制周一 api102 v1.1.0 loaded              ← onModuleLoaded
QianjiWeekStart: 三重hook已安装(getWeekStart/qe.c.c/getInt)      ← onPackageReady

api102 架构下 Hooker 回调无 log 通道(见 dev-guide/lessons.md C2), 拦截是否命中以界面效果为准(日历页周一起始 = 生效)。

旧版 v1.0.15(传统 API)日志格式:

钱迹强制周一 v1.0.15: 已加载到钱迹
钱迹强制周一 v1.0.15: 已注册三重hook(getInt/qe.c.c/getWeekStart)
钱迹强制周一 v1.0.15: ★拦截getWeekStart→周一(2)

🧱 本地构建(可选)

chmod +x build.sh
./build.sh                          # 默认 debug 签名, 开箱即用
./build.sh -k my.keystore           # 自定义 keystore (发布者)

依赖:aaptsmalizipalignapksignerkeytool

支持的环境变量:KEYSTORE_FILE / KEYSTORE_ALIAS / KEYSTORE_STORE_PASS / KEYSTORE_KEY_PASS


📖 附言:一段漫长的反馈史

这个 bug 困扰了我大半年,向官方反馈了多次,始终没有修复:

  • 2025.12.30 第一次向官方反馈
  • 2026.02.02 第二次向官方反馈
  • 2026.08.11 第三次向官方反馈
  • 期间还在公众号文章下反馈过几次

一直没修复,没处理,没招了。 自己上了。

如果你也深受"周起始日设置不生效"困扰,希望这个模块能帮到你。 也欢迎通过 Issues / PR 贡献代码。

特别感谢 LSPosed 团队 —— 没有这个优秀的框架,就没有这个模块。🙏

⚠️ 免责声明

  • 本模块仅供学习交流,请遵守软件许可协议
  • 模块强制锁定周一,设置界面中的"周六/周日"选项将不生效(预期行为)
  • 钱迹更新(类名混淆变化)可能导致模块失效,届时可参考本项目原理适配新版本

Releases