Repository navigation
Releases: CangWeiohh/KeywordSMSAlert
Release list
v1.4.2 稳定性专项修复
1.4.2 稳定性专项修复(14 项)
核心修复
ksactl restart不再 kill SpringBoard(仅重启 imagent)- 删除假桩
KSAHookInstallerDaemon.m与死代码/误导日志 KSAConfig.reloadIfNeeded加 mtime+size 快速路径_publishStatusWithConfig:节流 30ssqlite3_close_v2+@finallyfinalize +_noteError去重_baselineEstablished修复空库后首条短信漏报_readWatchTimer在stop()中正确取消 + 移除通知观察者- 状态通知改为在当前队列同步 post(不再依赖主 run loop)
postinst改用launchctl kickstart→ SIGTERM → SIGKILL 渐进重启controlDescription 更正- SpringBoard 过滤 plist 移入
Sources/Diagnostics/ - 新增
tests/verify_release_artifact.sh(49 项不变量断言) - 新增
tools/ksa-diagnose.sh(只读诊断脚本) %ctor全包@try/@catch+ safemode 早退 + 低频资源采样
1.4.1 - 已读停止改为提醒期间每 0.5 秒检查(不再受 5 秒轮询限制)
1.4.1:把"已读停止"从 5 秒轮询里解耦 —— 提醒期间每 0.5 秒检查一次
你问的问题:对,会有延迟
is_read 的检查原先搭在检测轮询的同一拍上,所以:
- 你的
PollInterval = 5秒 → 停止延迟 0~5 秒(平均约 2.5 秒); - 另外数据库若被占用,
sqlite3_busy_timeout(500)最多再加 0.5 秒; - 极端情况下(轮询间隔恰好被重新排定)还会多跳一拍。
修法:同一条通道,只改节奏(不引入任何新子系统)
提醒播放期间另起一个 0.5 秒的定时器,只做那一句主键查询:
SELECT is_read FROM message WHERE ROWID = ?- 仅在提醒进行中运行(由提醒引擎的状态变化通知触发启动/停止),空闲时零开销、零唤醒;
- 检测轮询本身仍是
PollInterval(你的 5 秒)—— 因为它只管"有没有新短信",与停止无关; - 仍然是只读同一个数据库连接:无 HID、无 Darwin 观察者、无 Hook、无额外进程。
新的停止延迟:约 0~0.5 秒(平均 0.25 秒),数据库忙时再加最多 0.5 秒。
核验(发布产物逐项检查)
启动安全不变量(必须不存在,均确认 False):IOHIDEventSystemClientCreate、notify_register_dispatch、com.apple.springboard.lockstate、com.apple.iokit.hid.displayStatus、SBLockScreenManager、MSHookMessageEx。
功能(必须存在,均确认 True):SELECT is_read FROM message WHERE ROWID、fast read check started、com.keyword.smsalert.alertStateChanged、SELECT MAX(ROWID) FROM message。
链接库与 1.3.1/1.4.0 完全一致(Foundation / CoreFoundation / AudioToolbox / sqlite3 / libroothide,无 AVFoundation);host 单测 48 passed / 0 failed。
备注
如果你的 PollInterval 设得更大(例如 10 秒),停止延迟不受影响(仍然是 0.5 秒级);它只影响"新短信被发现的延迟"。
1.4.0 - 打开短信即停止提醒(复用只读轮询,零新增子系统)
1.4.0:把"打开短信(标记已读)"作为停止方式 —— 复用已有的只读轮询,不引入任何新子系统
思路
1.3.1 已经证明"只轮询 + 提醒引擎"能稳定启动。既然轮询 sms.db 是本插件唯一被长期验证的通道,那就继续只用它来实现停止:
iOS 在你打开那条短信(或对它的通知执行打开动作)时,会把
message.is_read置为 1。我们本来就在轮询这个库,于是多查一个主键字段就能知道"用户已经看到了"。
实现(KSASMSWatcher):
- 记录最近触发过提醒的
ROWID(最多 8 条); - 仅在提醒进行中,每次轮询对这几条做一次
SELECT is_read FROM message WHERE ROWID = ?(主键查找,极便宜); - 一旦为 1 → 立即
stopAlertWithReason:@"SMS marked as read"。
这条路径不需要:HID 客户端、Darwin 观察者(notify_register_dispatch)、SpringBoard 注入、任何额外进程 —— 因此启动安全性等同于已验证的 1.3.1。
使用方式
- 收到提醒 → 在通知上点开(或直接打开「信息」里那条短信)→ 提醒立即停止;
- 不打开的话,仍然到设定时长自动结束(
SoundDuration/VibrationDuration,可自行调短)。
核验(发布产物逐项检查)
必须不存在(启动安全不变量,均确认 False):
IOHIDEventSystemClientCreate / notify_register_dispatch /
com.apple.springboard.lockstate / com.apple.iokit.hid.displayStatus /
SBLockScreenManager / MSHookMessageEx
必须存在(功能,均确认 True):
SELECT is_read FROM message WHERE ROWID (新的停止检查)
SELECT MAX(ROWID) FROM message (原有轮询)
AudioServicesPlaySystemSound (震动 + 铃声通道)
链接库与 1.3.1 完全一致:Foundation / CoreFoundation / AudioToolbox / sqlite3 / libroothide(无 AVFoundation)。host 单测 48 passed / 0 failed。
如果这样还不够"随手静音"
还有一个单变量的候选方案:把解锁/锁定状态再作为停止条件(1.2.7 的行为,当时能正常启动,但 1.3.0 那个版本恰好也带着它并且黑屏过,所以我不敢默认开启)。若你需要"不打开短信也能静音",我可以把它做成设置里的开关、默认关闭,你先当实验开启验证一次启动是否正常 —— 一次只加一个变量,不再一次塞三样。
1.3.1 - 最小稳定版(仅保留已实机验证内容)
1.3.1 稳定版:只保留"已实机验证过"的内容
先说一个反常事实
1.2.8 能正常启动,而 1.3.0 持续黑屏 —— 但 1.2.8 的代码比 1.3.0 多。
我对比了两个版本的发布产物:
| 版本 | detector 里的 IOHID 代码 | 启动 |
|---|---|---|
| 1.2.8 | 有 IOHIDEventSystemClientCreate |
正常(你读到了设置里的状态行) |
| 1.3.0 | 没有(已全部删除) | 持续黑屏 |
三个版本的包内容完全一致(detector dylib + filter plist + 设置面板 + ksactl;无 LaunchDaemon、无 SpringBoard 组件)。也就是说 1.3.0 是 1.2.8 的真子集,反而黑屏了。
这说明黑屏很可能不是(至少不只是)本插件代码造成的,而是设备状态相关。最可疑的是电话助手:它的 root LaunchDaemon 里写着硬编码的 jbroot 路径(.jbroot-2ED827453A76B860)。每次"强制重启 + 重新越狱"都会生成新的随机 jbroot,于是它的守护进程再也起不来,而它的 SpringBoard 组件还在跑 —— 这正好会表现为"系统活着、屏幕不亮"。这也解释了最早的现象:只装电话助手时它自己就有约 1 秒黑屏。
1.3.1:最小稳定版(安不安全,一测便知)
已移除:IOHID 观察器、显示/锁定状态观察器(notify_register_dispatch)、所有 Hook、SpringBoard 相关代码、独立进程/守护进程。
产物核验(逐项确认不存在):
IOHIDEventSystemClientCreate -> False
com.apple.springboard.lockstate -> False
com.apple.iokit.hid.displayStatus -> False
notify_register_dispatch -> False
SBLockScreenManager -> False
MSHookMessageEx -> False
保留(都已实机验证过):
- 只读轮询
sms.db+ 关键词匹配(1.1.x 起长期验证); - 提醒引擎:震动 + 铃声/提醒通道声音(1.2.0 验证可正常响);
- 设置面板、
ksactl、boot-quiet(启动后 10 秒才开始工作)。
功能变化(明确告知):提醒不再响应电源键,而是到设定时长自动结束(SoundDuration / VibrationDuration,默认 10 秒声音、5 秒震动)。这是唯一一个"只保留已验证内容"后仍能让功能成立的做法。
建议的验证顺序(先确认责任方)
- 强制重启:音量 + → 音量 − → 长按侧边键,直到出现 Apple 标志;
- 在 Sileo 里卸载 KeywordSMSAlert → 重启用户空间:
- 仍然持续黑屏 → 与本插件无关(几乎可以确定是电话助手的 jbroot 路径失效/设备状态)→ 若如此,在 Sileo 里把电话助手也重装一次(让它按当前 jbroot 重写守护进程路径)再重启;
- 恢复正常 → 责任在本插件,那就装 1.3.1(已是最小集合)。
- 装 1.3.1 后再重启一次,确认启动正常。
核验
- host 单测 48 passed / 0 failed
- 包内容:detector dylib + filter plist + 设置面板 bundle +
ksactl(无其它二进制、无 LaunchDaemon) - detector 依赖:Foundation / CoreFoundation / AudioToolbox / sqlite3 / libroothide(无 AVFoundation)
1.3.0 - 彻底移除 IOHID 监听(未生效且引发启动黑屏)
1.3.0:彻底移除 IOHID 监听(它从未生效,并且 1.2.9 的探测把启动黑屏带回来了)
先说结论
1.2.9 的 IOHID 相关新增是这次黑屏的嫌疑源头,因此 1.3.0 把整个 IOHID 观察器从发布构建里彻底删除。
理由很直接:它从来没有真正生效过 —— 1.2.8 第一次给它加计数后,实测是"零事件"。一个从未生效的功能,不值得拿设备启动去冒险。
1.2.9 相对 1.2.8 只多了这些(都在 imagent 里、启动后 10 秒执行):
IOHIDEventSystemClientCopyServices探测"能看见多少 HID 服务";- 同时创建 3 个 客户端(主 run loop / dispatch queue / 独立线程 run loop);
- 新增一个独立线程跑
CFRunLoopRun()。
而 1.2.7(1 个客户端 + 主 run loop)与 1.2.8(1 个客户端 + dispatch queue)都能正常启动。所以增量里最可疑的是对 HID 服务做查询与多客户端/新线程:HID 事件系统同时驱动着显示唤醒链路,与它"较劲"在这个环境下显然不安全。
1.3.0 的内容
- 发布构建里不再包含任何 IOHID 代码(产物已核验:
IOHIDEventSystemClientCreate/CopyServices/IOHIDEventGetType等符号全部不存在); - 提醒的停止方式回到只依据锁定状态(1.2.7 已验证可正常启动的形态):
- 解锁(密码 / Face ID)→ 停止;
- 锁定(用手机时按电源键,或自动锁定)→ 停止;
- 通知点亮屏幕、点击屏幕、抬手唤醒、自动熄屏 —— 都不会停止提醒;
- 保留 boot-quiet(启动窗口内零活动)、铃声通道提醒、关键词检测、设置面板。
请这样恢复设备
- 强制重启:按一下「音量 +」→ 按一下「音量 −」→ 长按侧边电源键,直到出现 Apple 标志;
- 重启后系统是未越狱状态,Sileo 可正常使用;
- 在 Sileo 里安装本版本(或先卸载 KeywordSMSAlert 再决定);
- 需要时再用 Dopamine 越狱。
抱歉又让你经历一次黑屏 —— 这次我不再在 HID 这条路上继续试探了:证据是它从未生效,继续迭代只会重复拿启动安全冒险。
核验
- host 单测 48 passed / 0 failed
- 发布 detector:零 IOHID 符号、零 Hook、未链接 AVFoundation、无 SpringBoard 组件与 LaunchDaemon
- 包内仍只有 detector dylib + 设置面板 +
ksactl
1.2.9 - 更正上一轮结论:HID 客户端能建但事件从未到达;一次安装问清原因
1.2.9:更正上一轮的结论,并把 HID 的"为什么收不到"一次性问清楚
先更正我上一轮的错误
我说"1.2.7 显示 已启动 · 电源键监听(HID) 就证明事件到达了"——这是错的。查 git 历史确认:
- 1.2.7 的那行逻辑只有
if (HIDAvailable) → "电源键监听(HID)",而HIDAvailable仅仅表示 "客户端创建成功"; - "收不到事件"这个区分是 1.2.8 才加进去的。
所以你 1.2.7 看到的文案只证明客户端能创建,不证明有事件。而 1.2.8 第一次真正测量了它,结果是你看到的:零事件。
也就是说:客户端能在 imagent 里创建成功,但事件从来没到过。真正的原因只可能是"沙箱/权限不允许事件投递",或者"投递方式不对"。
1.2.9:一次安装把这两个问题都问清楚
- 能看见多少 HID 服务:调用
IOHIDEventSystemClientCopyServices数一下 imagent 到底能看到几个 HID 服务。如果是 0,说明沙箱直接封死了 HID 事件系统,任何投递方式都不可能成功——那样我就不会再让你折腾这条路了。 - 三种投递方式依次自动尝试(每次一个独立客户端,互不干扰):
- A
main-runloop:挂 imagent 主 run loop(1.2.7 用的方式,但当时没测过是否真有事件); - B
dispatch-queue:IOHIDEventSystemClientSetDispatchQueue(1.2.8 用的,实测 0 事件); - C
thread-runloop:独立线程 + 自己的 run loop。
每 8 秒如果还没有任何事件,就启动下一种;哪种先收到事件就会记录下来,并显示在设置里。
- A
- 匹配仍然放宽(
Consumer 0x0C/0x30、AppleVendor 0xFF01/0x0B、Keyboard 0x07/0x66),键盘事件仍会把真实的 page/usage/down 记录下来。
设置里现在会显示什么
- 有事件:
已启动 · 电源键监听(HID)· 事件 N/键盘 M · 末次 0x<page>/0x<usage>↓<策略> - 没事件:
已启动 · HID 已注册但收不到事件(可见 HID 服务 N · <当前策略>)
请这样测(一次就够)
- 安装 1.2.9,重启一次用户空间(旧的 boot-quiet 延迟 10 秒生效,属正常);
- 进「诊断 → 提醒服务状态」,按一下音量键,看计数与"可见 HID 服务"的数字;
- 整行发我(含括号内内容)。
结果怎么解读
| 看到的现象 | 结论与下一步 |
|---|---|
可见 HID 服务 0 |
沙箱封死,HID 这条路走不通 → 保留"锁定/解锁"兜底,不再折腾 |
| 服务 > 0 但仍无事件,且三种策略都试过 | 事件投递被拦(可能只差一个 entitlement,而它无法追加)→ 同样放弃 HID |
有事件、键盘 M 增长、末次 显示某个 page/usage |
有救:把 page/usage 发我,我加进匹配表即可 |
有事件且 末次 是 0xC/0x30 或 0xFF01/0xB |
那说明匹配本身没问题,问题在别处,我继续查 |
核验
- host 单测 48 passed / 0 failed(matcher 覆盖 3 种候选 usage)
- detector 产物确认含服务探测、三条投递策略、零 Hook、未链接 AVFoundation、无 SpringBoard 组件与 LaunchDaemon
- 两个
Localizable.strings均通过plutil -lint
1.2.8 - HID 收得到事件,真正的问题是 usage 匹配(已放宽)+ 设置里显示计数
1.2.8:HID 事件其实收得到 —— 真正的问题是"匹配不到电源键"
你给的那行状态是决定性证据
你看到的是 已启动 · 电源键监听(HID)。这行文案只在 HID 事件真的到达时才会显示(收不到事件时显示的是「HID 已注册但收不到事件」)。所以:
imagent 完全有权接收 HID 事件,客户端也真的在被喂数据 —— 我之前担心的 entitlement / 沙箱拦截并不存在。
那按电源键为什么没反应?只剩一个解释:这台设备的电源键事件不是我匹配的那个 usage。1.2.7 只接受 Consumer 页 0x0C / usage 0x30,而 iPhone 的锁屏/电源键在很多机型上是以 AppleVendor 页 0xFF01 / usage 0x0B(Screensave) 上报的。
1.2.8 的修改
- 放宽匹配:现在接受三种候选 usage,其余按键(音量、Home、媒体键等)仍然一律不匹配,不会误停:
Consumer 0x0C / 0x30(Power)AppleVendor 0xFF01 / 0x0B(Screensave,iPhone 锁屏键常见上报方式)Keyboard 0x07 / 0x66(Power)
- 事件投递更可靠:1.2.7 把客户端挂到 imagent 的主 run loop 上,而没人保证主线程在跑默认模式。现在优先使用
IOHIDEventSystemClientSetDispatchQueue(完全不依赖 run loop),没有该符号时改用独立线程 + 自己的 run loop。 - 把原始计数显示在设置里(这样下一次测试就能直接读出答案,无需终端):
已启动 · 电源键监听(HID)· 事件 N/键盘 M · 末次 0x<page>/0x<usage>↓事件一直涨 → 客户端在被喂数据;键盘 M在你按电源键/音量键后 +1;末次 0x…/0x…就是这颗设备真实的 page/usage —— 如果电源键不是上面三种之一,把这两个值发我,我直接加进匹配表即可。
顺带修掉一个真 bug
英文 Localizable.strings 里少了一个分号("RuntimeHIDLast" = "…%@;"),导致设置面板 bundle 编译失败、一直用旧二进制——这也是为什么 1.2.7 里看不到计数。现已修复并加了 plutil -lint 验证。
请这样测
- 安装 1.2.8;
- 进「诊断 → 提醒服务状态」,先按一下音量键(故意产生一个键盘事件)→ 看
事件/键盘是否增长、末次 0x…/0x…出现什么值; - 触发一次提醒(「立即测试提醒」),提醒中按电源键 → 应从 1.2.8 起能停止;
- 若仍不能停止,把状态行整行(含
末次与括号内容)发我。
核验
- host 单测 48 passed / 0 failed(新增 4 项 usage 匹配用例:AppleVendor/Screensave 接受、Keyboard/Power 接受、Screensave 抬起忽略、Consumer/Menu 不误判)
- detector:投递改为 dispatch-queue/独立 run loop、键盘事件带 page/usage/down 日志、零 Hook、未链接 AVFoundation、无 SpringBoard 组件与 LaunchDaemon
- 两个
.strings均通过plutil -lint
1.2.7 - 不再用屏幕状态停止提醒;真正的电源键监听 + 锁定/解锁兜底
1.2.7:屏幕状态不再停止提醒;改为「真正的电源键监听」+「锁定/解锁」兜底
你这次的现象说明了根本问题
自动熄屏后提醒正常(1.2.6 有效)→ 点击屏幕亮屏 → 提醒立刻停止
因为"点击屏幕亮屏"和"按电源键亮屏"在显示状态层面完全一样(都是 熄屏 → 亮屏)。我上一版把"亮屏"当成按了电源键,所以点一下屏幕就把提醒停了。
结论:用显示状态推断电源键,原理上就做不到。 显示状态的每一次变化都有好几个来源:
| 显示变化 | 可能的来源 |
|---|---|
| 熄屏 → 亮屏 | 按电源键、点击屏幕、抬手唤醒、短信通知点亮锁屏 |
| 亮屏 → 熄屏 | 按电源键、自动熄屏、通知唤醒超时、自动锁定 |
前两版我每修掉一个误判源,下一次实测就冒出下一个(先被通知唤醒停、再被通知超时停、再被点击屏幕停)。所以这次彻底不再用显示状态停止提醒。
1.2.7 的两条停止途径
-
真正的电源键监听(首选):直接在 imagent 内用 IOKit 的
IOHIDEventSystemClient只观察物理电源键事件(Consumer 页 / Power 用法 / 按下沿)。事件从不派发、从不消费、从不改写,不影响锁屏/唤醒/SOS。- 这是唯一能精确区分"电源键"与"点屏幕"的信号;
- 但 imagent 没有 HID entitlement,是否放行只能靠实测——所以做了兜底并把它显示在设置里。
-
锁定 / 解锁(兜底,一定有效):通知、点击屏幕、抬手唤醒都不会改变锁定状态,所以这两个动作可以安全地作为停止条件:
- 锁定(用手机时按电源键,或自动锁定)→ 停止;
- 解锁(输密码 / Face ID)→ 停止(你已经看到提醒了)。
屏幕状态现在只用于诊断
它仍会被记录(设置面板可查),但永不停止提醒。
请在设置里看这一行判断 HID 是否生效
设置 → KeywordSMSAlert → 诊断 →「提醒服务状态」:
- 显示
已启动 · 电源键监听(HID)→ 精确按键监听生效:按电源键立即停止,点屏幕/抬手/通知都不会误停; - 显示
已启动 · 停止方式:锁定/解锁手机→ HID 未放行,退化为"锁定/解锁停止"(按电源键点亮屏幕不会停;解锁手机或按电源键锁屏会停)。
括号里还会带上 HIDStatus,把失败原因(例如缺少 entitlement / IOHID 符号)直接写出来。
请这样测
- 安装 1.2.7(旧包是 boot-quiet,imagent 启动后约 10 秒才开始工作,属正常);
- 发短信 → 等提醒响 → 点一下屏幕亮屏 → 提醒应继续;
- 等到自动熄屏 → 提醒仍应继续;
- 然后看「提醒服务状态」显示的是哪一种,再按提示的停止方式验证一次。
核验
- host 单测 44 passed / 0 failed
- detector:HID 观察代码已编入、显示状态停止规则已确认移除、锁定/解锁停止路径存在;零 Hook、未链接 AVFoundation、包内无 SpringBoard 组件与 LaunchDaemon
1.2.6 - 自动熄屏不再中断提醒
1.2.6:手机自动熄屏后提醒不再中断
现象与根因
收到短信 → 通知点亮锁屏 → 震动 + 响铃正常 → 几秒后手机自动熄屏 → 震动和声音一起停了。
根因还是"按电源键停止"的实现方式:它用屏幕状态推断按键,而我把 亮屏 → 熄屏 无条件当成"按了电源键"。系统自己也会产生这个切换——通知点亮锁屏后,几秒内会自己再熄掉——于是提醒刚响几秒就被自己停掉了(震动和声音同时消失正是 stopAlert 的行为)。
1.2.6 的判定规则(逐条明确)
| 事件 | 处理 |
|---|---|
| 熄屏 → 亮屏,且在提醒开始 4 秒内 | 判为短信通知唤醒 → 忽略,并记住这次是通知唤醒的 |
| 熄屏 → 亮屏,在 4 秒之后 | 停止(睡着的手机上按电源键唤醒) |
| 锁屏状态变为已锁定 | 停止(真正的锁定动作;通知唤醒不改变锁定状态,不会误判) |
| 亮屏 → 熄屏,且刚才是那条"通知唤醒"息的 | 忽略(通知自己的超时)→ 提醒继续 |
| 亮屏 → 熄屏,且设备当前锁定 | 忽略(通知超时/自动熄屏)→ 提醒继续 |
| 亮屏 → 熄屏,且设备未锁定(正在用手机) | 停止(按电源键锁屏) |
净效果:通知点亮屏幕、以及它几秒后的自动熄屏,都不再打断提醒。
怎么停止提醒
- 屏幕是黑的:按一下电源键(点亮)→ 停止;
- 你正在用手机(未锁定):按一下电源键(锁屏)→ 停止;
- 屏幕上正显示锁屏界面:第一下会被判为"通知超时"忽略,再按一下即停止。
另外:抬手唤醒(拿起手机)也会被识别为用户操作而停止提醒 —— 系统层面它和"按电源键唤醒"完全无法区分。若不希望拿起手机就停,可以去掉"熄屏→亮屏"这一条,只保留锁定与未锁定熄屏两种判定。
核验
- host 单测 44 passed / 0 failed
- detector:三条新判定路径的日志字符串已在产物中确认;零 Hook、未链接 AVFoundation、包内无 SpringBoard 组件与 LaunchDaemon
1.2.5 - 启动窗口内不做任何事(boot-quiet)
1.2.5:启动窗口内本插件不做任何事(boot-quiet)
先回答"为什么重启用户空间后先亮屏、再黑 7 秒"
这个包里没有任何能控制屏幕的代码。 1.2.0 起提醒引擎和检测都在 imagent 内,包内既没有 SpringBoard 组件、也没有背光/锁屏相关调用;对屏幕它只做两件事:只读两个 Darwin 通知(com.apple.iokit.hid.displayStatus / com.apple.springboard.lockstate),用来在提醒时判断"是否按了电源键"。观察状态不会改变状态,所以它不可能把屏幕关掉。
那么"黑 7 秒"只可能来自两处:
- 用户空间重启本身的时序:Dopamine 重启用户空间时,backboardd/SpringBoard 要整体重启,屏幕本来就会熄一下再亮;这段时间长短取决于系统负载与已装插件数量(电话助手本身也会造成约 1 秒黑屏)。
- imagent 被拖慢:注入到 imagent 的 dylib 会在启动窗口内被 dyld 加载并开始运行。与"你确认正常"的 Diagnostic B 相比,1.2.x 多了提醒引擎、AudioToolbox 依赖和两个 Darwin 通知注册——如果 imagent 因此晚就绪,依赖它的启动流程也会晚,屏幕就晚亮。
1.2.5 的做法
把运行期工作整体延后:%ctor 只做进程判定和一行日志,10 秒后才真正启动轮询、提醒引擎和状态监听。也就是说在"重启用户空间"这段最敏感的窗口里,本插件除了被 dyld 加载之外什么都不做:不打开 sms.db、不注册通知、不初始化引擎。
代价:imagent 启动后最初约 10 秒内到达的短信不会被提醒(基线在此之前建立)。这个数字可以按你的需要调整。
请帮我做一次判定(只有你能测)
- 先装 1.2.5,重启用户空间,掐表记录黑屏秒数,连做 2 次;
- 再卸载 KeywordSMSAlert(Sileo 卸载即可),重启用户空间,同样掐表 2 次;
- 把 4 个数字告诉我。
如果卸载后仍然是 7 秒左右 → 与我们无关,是电话助手/Dopamine 的重启时序;如果卸载后回到 1 秒、装 1.2.5 是 7 秒 → 说明确实是我们拖慢了 imagent,我再把 AudioToolbox 改成首次提醒时才动态加载(让本插件的依赖集合与已验证正常的版本完全一致)。
核验
- host 单测 44 passed / 0 failed
- detector:boot-quiet 标记存在、零 Hook、未链接 AVFoundation、屏幕状态监听仍在