fix(keyboard): close librime on every hide to avoid 0xdead10cc kills
Hiding the keyboard on the typing surface kept librime's LevelDB userdb LOCK open in the App Group, so RunningBoard killed the suspended extension. Finalize the runtime on every hide (and when schema selection fails); viewWillAppear re-prepares Rime in about 30-50 ms.
This commit is contained in:
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- **Host-only analytics recording**: the keyboard extension no longer opens the analytics or keyboard-usage SQLite queues. The host app is the only process that records and uploads events, so hiding the keyboard cannot hold WAL locks and get killed as `0xdead10cc`. Keyboard-activated and per-keystroke usage events are no longer collected. / **仅主 App 记埋点**:键盘扩展不再打开统计与键盘用量 SQLite 队列;开库、记账与上传只在主 App 进行,收起键盘时不会因 WAL 锁被系统以 `0xdead10cc` 终止。不再采集「键盘激活」和逐次按键用量。
|
- **Host-only analytics recording**: the keyboard extension no longer opens the analytics or keyboard-usage SQLite queues. The host app is the only process that records and uploads events, so hiding the keyboard cannot hold WAL locks and get killed as `0xdead10cc`. Keyboard-activated and per-keystroke usage events are no longer collected. / **仅主 App 记埋点**:键盘扩展不再打开统计与键盘用量 SQLite 队列;开库、记账与上传只在主 App 进行,收起键盘时不会因 WAL 锁被系统以 `0xdead10cc` 终止。不再采集「键盘激活」和逐次按键用量。
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
- **Keyboard killed after hiding on pinyin**: hiding the keyboard while the pinyin/English typing surface was showing kept librime's user dictionary open, and its LevelDB `LOCK` file in the shared App Group got the suspended extension killed as `0xdead10cc` (about 30 kills in 3 days on one test device). The typing engine is now closed on every hide and reopened on the next show, which adds about 30–50 ms only when a still-running keyboard is reopened. / **拼音界面收起后键盘被系统终止**:在拼音/英文打字界面收起键盘时,librime 用户词库仍保持打开,其位于共享 App Group 的 LevelDB `LOCK` 文件导致挂起的扩展被系统以 `0xdead10cc` 终止(一台测试机 3 天约 30 次)。现在每次收起都会关闭打字引擎、下次弹出时重新打开,仅在复用仍存活的键盘进程时多约 30–50 毫秒。
|
||||||
- **Misleading edit hint after insertion**: stop showing “Hold to edit your last input” for 10 seconds after every insertion. Holding the microphone asks AI; editing the last input uses the pencil button beside it. / **插入后的误导性编辑提示**:每次插入后不再显示 10 秒的「长按编辑上一条」。长按麦克风是向 AI 提问,编辑上一条请使用旁边的铅笔按钮。
|
- **Misleading edit hint after insertion**: stop showing “Hold to edit your last input” for 10 seconds after every insertion. Holding the microphone asks AI; editing the last input uses the pencil button beside it. / **插入后的误导性编辑提示**:每次插入后不再显示 10 秒的「长按编辑上一条」。长按麦克风是向 AI 提问,编辑上一条请使用旁边的铅笔按钮。
|
||||||
- **Saving invitation posters**: declare add-only Photos access in the built app and preflight the privacy description before calling PhotoKit, preventing Save Image from terminating the app when the generated project configuration is stale. / **保存邀请海报**:在 App 构建配置中声明“仅添加照片”权限,并在调用 PhotoKit 前检查权限说明,避免生成的工程配置过期时点击“保存图片”导致 App 被系统终止。
|
- **Saving invitation posters**: declare add-only Photos access in the built app and preflight the privacy description before calling PhotoKit, preventing Save Image from terminating the app when the generated project configuration is stale. / **保存邀请海报**:在 App 构建配置中声明“仅添加照片”权限,并在调用 PhotoKit 前检查权限说明,避免生成的工程配置过期时点击“保存图片”导致 App 被系统终止。
|
||||||
- **Invitation redemption retrying forever**: an invitation the server permanently rejected (unknown code, self-referral, already bound, or binding window expired) stayed stored and was retried on every sign-in. These rejections now show a specific message and drop the stored code; network failures still retry. / **邀请兑换无限重试**:服务器明确拒绝的邀请(邀请码无效、邀请自己、已绑定或超出绑定期限)会一直保留并在每次登录时重试。现在这些情况会给出具体提示并清除暂存的邀请码;网络失败仍会重试。
|
- **Invitation redemption retrying forever**: an invitation the server permanently rejected (unknown code, self-referral, already bound, or binding window expired) stayed stored and was retried on every sign-in. These rejections now show a specific message and drop the stored code; network failures still retry. / **邀请兑换无限重试**:服务器明确拒绝的邀请(邀请码无效、邀请自己、已绑定或超出绑定期限)会一直保留并在每次登录时重试。现在这些情况会给出具体提示并清除暂存的邀请码;网络失败仍会重试。
|
||||||
|
|||||||
@@ -269,9 +269,11 @@ public final class KeyboardViewController: UIInputViewController {
|
|||||||
if !preserve {
|
if !preserve {
|
||||||
prepareSurfaceForNextPresentation()
|
prepareSurfaceForNextPresentation()
|
||||||
}
|
}
|
||||||
if state.surface != .typing {
|
// Always finalize librime on hide, even on the typing surface: its
|
||||||
|
// LevelDB userdb holds `Rime/UserData/*.userdb/LOCK` in the App Group,
|
||||||
|
// and RunningBoard kills a suspended extension holding that lock
|
||||||
|
// (0xdead10cc). `viewWillAppear` re-prepares Rime (~30–50 ms).
|
||||||
deactivateTypingSurface()
|
deactivateTypingSurface()
|
||||||
}
|
|
||||||
if preserve {
|
if preserve {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,9 @@ public final class LibrimeEngine: RimeEngineBridging {
|
|||||||
let configured = configurationProvider()
|
let configured = configurationProvider()
|
||||||
schema = configured.schema
|
schema = configured.schema
|
||||||
guard runtime.selectSchema(schema.rawValue) else {
|
guard runtime.selectSchema(schema.rawValue) else {
|
||||||
runtime.stopSession()
|
// `start()` already initialized the shared runtime; finalize it so
|
||||||
|
// no user dictionary stays open without an owning bridge.
|
||||||
|
runtime.finalizeRuntime()
|
||||||
throw LibrimeEngineError.schemaUnavailable(schema.rawValue)
|
throw LibrimeEngineError.schemaUnavailable(schema.rawValue)
|
||||||
}
|
}
|
||||||
_ = runtime.setASCIIMode(language == .english)
|
_ = runtime.setASCIIMode(language == .english)
|
||||||
|
|||||||
Reference in New Issue
Block a user