Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
name: Android Release

# A release is a signed arm64 APK built from a vX.Y.Z tag on main. The same build
# A release is a signed arm64 APK built from a vX.Y.Z or vX.Y.Z-beta.N tag on main
# (a beta is published as a GitHub pre-release and never as "latest"). The same build
# and verification script (scripts/release_build.sh) is rehearsed with a throwaway
# key on manual runs and on pull requests that touch the release pipeline, so the
# first real release is not the first time it runs. See docs/RELEASE.md.
on:
push:
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'
- 'v[0-9]+.[0-9]+.[0-9]+-beta.[0-9]+'
workflow_dispatch:
pull_request:
branches: [main]
Expand Down Expand Up @@ -233,13 +235,20 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
channel_flags=()
latest_flag=--latest
if [[ "$GITHUB_REF_NAME" == *-beta.* ]]; then
channel_flags=(--prerelease)
latest_flag=--latest=false
fi
gh release create "$GITHUB_REF_NAME" \
release-files/openIME-*-arm64-release.apk \
release-files/SHA256SUMS.txt \
release-files/THIRD_PARTY_NOTICES.release.md \
--repo "$GITHUB_REPOSITORY" \
--verify-tag \
--draft \
"${channel_flags[@]}" \
--title "openIME $GITHUB_REF_NAME" \
--notes-file release-files/RELEASE_NOTES.md

Expand All @@ -248,4 +257,4 @@ jobs:
echo "::error::Expected 3 release assets, found $count; the draft was left unpublished."
exit 1
fi
gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --draft=false --latest
gh release edit "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" --draft=false "$latest_flag"
82 changes: 42 additions & 40 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,60 @@
[Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循
[语义化版本](https://semver.org/lang/zh-CN/)。每个 `## [版本] - 日期` 小节就是该版本
GitHub Release 的发布说明;版本与发布流程见 [docs/RELEASE.md](docs/RELEASE.md)。
1.0.0 之前的开发期记录见 [docs/CHANGELOG_PRE_1.0.md](docs/CHANGELOG_PRE_1.0.md)。
首个公开版本之前的开发期记录见 [docs/CHANGELOG_PRE_1.0.md](docs/CHANGELOG_PRE_1.0.md)。

## [Unreleased]

## [1.0.0] - 2026-10-02
## [0.0.1-beta.1] - 2026-10-03

首个正式版。openIME 是独立的 Android 系统输入法:拼音候选、用户学习和语音识别都在设备内运行,应用不声明 `INTERNET` 权限。
openIME 的首个公开测试版。功能已经可以日常试用,但稳定性和兼容性还在验证,请不要把它作为唯一的输入法;欢迎在 Issues 反馈问题。

### 亮点
- 拼音、用户词库学习和语音识别全部在设备本地完成,应用没有 `INTERNET` 权限。
- 九键拼音一个字选一个音节:左栏列出下一个字的拼音,选定后自动移到下一个字。
- 长按空格说话,松手识别并上屏,使用内置的中英双语模型。
- 在终端、远程桌面、游戏、外接键盘、平板与折叠屏、大字号等环境下都能输入;键盘出现崩溃或卡死时自动进入安全模式。

### 输入
- 键盘:26 键拼音、九键拼音、英文 26 键、数字与符号;不提供英文九键。
- 拼音引擎:基于 librime 的全拼、简拼、显式分词、候选读取(上限 96 项)、用户学习和 OpenCC 简繁转换;内置约 90 万条 Rime Ice 词典记录(固定版本,含 8105 字表)。首次部署完整词典期间,高频快速词库即时提供候选。
- 九键:输入时左栏变成拼音列表,一个字一个拼音——每项是下一个字的一个音节(`ni`、`mi`),点选即锁定,列表随即移到下一个字;锁定的音节在继续输入时保持不变,退格先解锁。预编辑跟随首选词的读法(`9694264244326` → `wo'xiang'chi'fan`「我想吃饭」),数字刚好拼得出的词排在预测词之前。做法与取舍见 [九键参考](https://github.com/Slacker-LLC/openIME/blob/main/docs/NINE_KEY_REFERENCE.md)。
- 选词只覆盖一部分输入时只上屏该词,剩余输入继续作为预编辑;不会把没选过的整句写进用户词库。
- 空格提交首选候选,回车(确定)提交已输入的拼音原文;提交后统一清除拼音、候选与 Rime composition,随后删除键只处理目标输入框。上屏后的联想栏为「‹ 联想词 ∨」。
- 删除键:长按连续删除;上滑 ≥ 32dp 松手清空,清空后 5 秒内下滑撤回。清空与撤回在自绘、Compose、Web 等没有「全选」也没有完整 ExtractedText 的输入框里同样可用,提示统一为一个气泡,清空后顶栏显示「已清空 · 撤销」。
- 键盘:26 键拼音、九键拼音、英文 26 键、数字与符号。
- 拼音引擎基于 librime:全拼、简拼、手动分词、候选展开(最多 96 项)、用户学习、OpenCC 简繁转换;内置约 90 万条 Rime Ice 词典记录。首次部署完整词典期间,由高频快速词库提供候选。
- 九键:点选拼音即锁定该音节,继续输入时保持,退格先解锁;预编辑跟随首选词读法(`9694264244326` → `wo'xiang'chi'fan`「我想吃饭」)。设计取舍见 [九键参考](https://github.com/Slacker-LLC/openIME/blob/main/docs/NINE_KEY_REFERENCE.md)。
- 选词只覆盖一部分输入时,只上屏该词,其余输入继续作为预编辑,不会把没选过的整句写进用户词库。
- 空格提交首选,回车提交拼音原文。
- 删除键:长按连续删除;上滑清空,5 秒内下滑撤回(在自绘、Compose、Web 等输入框里同样可用)。

### 语音
- 长按空格(达到系统长按时长)开始本地语音输入,松手识别并上屏,上滑取消。使用 APK 内置的 sherpa-onnx 与中英双语模型,没有网络语音服务。
- 输入框出现时后台预热模型,隐藏 10 秒后释放;预热期间的语音先录音缓存;支持动态热词与本地纠错学习。
- 麦克风权限被拒绝时可恢复,不影响普通输入;本地模型使用前校验完整性。
- 长按空格开始本地语音输入,松手识别并上屏,上滑取消。
- 输入框出现时后台预热模型,隐藏 10 秒后释放;支持热词与本地纠错学习。
- 麦克风权限被拒绝时可恢复,不影响普通打字。

### 面板与外观
- Emoji、符号、剪贴板与常用语、文本编辑、浮动键盘和设置面板。
- 按输入法窗口实际可用宽度计算布局,宽屏限制内容最大宽度并居中;系统底部区域通过 WindowInsets 处理。
- 强调色可选可自定义,界面里的强调元素统一从它推导;设置页分段控件、剪贴板清除按钮等可点区域保持 48dp 触控目标;安装引导页的卡片对读屏软件是一个整体,不再逐个朗读装饰元素。
- 手写目前只保留笔迹采集界面,识别引擎尚未接入,入口默认隐藏。
### 界面
- Emoji、符号、剪贴板与常用语、文本编辑、浮动键盘、设置面板;强调色可自定义,可点区域保持 48dp 触控目标。
- 布局按输入法窗口的实际宽度计算,宽屏限制最大宽度并居中。

### 兼容性
- 物理键盘(平板、折叠屏键盘套、Chromebook、桌面模式)可以打中文:字母组成拼音,空格选首选,1–9 选候选,回车保留拼音,Esc 取消,`,` `.` 等输出全角标点,数字后的 `,` `.` `:` 保持 ASCII;快捷键、大写字母原样交给应用。
- 终端、游戏、远程桌面这类没有文本类型(TYPE_NULL)的输入框:默认英文,字母立即送出,退格改用按键事件(此前什么也删不掉);日期时间输入框默认数字键盘。
- 一次提交超大文本(大段粘贴)会分块,不会因超过 Binder 事务上限而崩溃。
- 横屏不再进入全屏「提取」模式:应用自己的输入框不会被盖住,键盘始终是底部面板。
- 横屏、平板和折叠屏上按键行宽度现在跟随内容区,不会再被裁掉一部分;布局在测量前就按可用宽度计算。
- 系统字体放大到 200% 时按键字符不再变成省略号,「中/英」不再缺字:按键标签最多跟随系统字体放大到 1.3 倍,功能键标签会自动缩小以放入按键。
- 竖屏、横屏、字体 130% / 200%、深色、小屏、窄屏、平板(竖 / 横)和折叠屏内屏都由 `scripts/display_matrix_regression.py` 逐一验证。
- 外接键盘(平板、折叠屏键盘套、Chromebook、桌面模式)可以打拼音:空格选首选,1–9 选候选,回车保留拼音,Esc 取消,快捷键交给应用。
- 终端、游戏、远程桌面这类无文本类型的输入框:默认英文、按键直接送出、退格可用;日期时间输入框默认数字键盘。
- 横屏不再进入全屏「提取」模式;横屏、平板、折叠屏的按键行宽度跟随内容区;系统字体放大到 200% 时按键字符完整显示。
- 超大文本粘贴会分块提交,不会因超过 Binder 事务上限而崩溃。
- 逐环境的处理方式和验证范围见 [兼容性说明](https://github.com/Slacker-LLC/openIME/blob/main/docs/COMPATIBILITY.md)。

### 稳定性
- 一次按键处理失败不会让键盘退出;崩溃、原生崩溃和卡死(ANR)会记录在本机(只含异常类型和代码位置,不含输入内容),10 分钟内三次进入安全模式(关闭原生词库与语音预加载),「关于与数据」里可以复制诊断信息或退出安全模式。
- librime 启动时进程原生崩溃会逐级自愈:清理编译产物、备份并重建用户词库、最后不再启动原生引擎。
- 语音输入静音媒体音量期间进程意外退出,下次启动会恢复音量,并带两分钟看门狗。
- 词库和九键解码器改在后台线程构建,冷启动不再卡住主线程。
- 单次按键处理失败不会让键盘退出。崩溃、原生崩溃和卡死会记录在本机(只含异常类型和代码位置,不含输入内容);10 分钟内三次进入安全模式(关闭原生词库与语音预加载),可在「关于与数据」复制诊断信息或退出安全模式。
- librime 启动时原生崩溃会逐级自愈:清理编译产物、备份并重建用户词库、最后不再启动原生引擎。
- 语音输入静音媒体音量期间进程意外退出,下次启动会恢复音量。
- 词库和九键解码器在后台线程构建,冷启动不再卡住主线程。

### 隐私与安全
- 不声明 `INTERNET` 权限;`allowBackup=false`。
- 密码输入框不写入候选、剪贴板历史或日志(允许从剪贴板粘贴);语音 PCM 只在当前会话的内存缓冲区中处理,结束、取消或失败时清空。
- 「设置 → 关于与数据」可导出 / 合并导入用户数据,剪贴板历史不导出;卸载会清除本机全部数据,包括学习的用户词库。
- 测试用 Activity 与 E2E 接收器只存在于 debug 变体,release APK 不导出。
- 以 GPL-3.0-only 许可证发布,见仓库根目录 `LICENSE`。

### 工程
- 版本号单一来源(根目录 `VERSION`),`versionCode = 主 × 10000 + 次 × 100 + 修订`。
- 发布 APK 为固定签名的 `arm64-v8a`,随附 SHA-256 校验和与第三方许可清单;CI 在 API 29 / 31 上运行全部仪器测试。

[Unreleased]: https://github.com/Slacker-LLC/openIME/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/Slacker-LLC/openIME/releases/tag/v1.0.0
- 不声明 `INTERNET` 权限,`allowBackup=false`。
- 密码输入框:不组合拼音、不学习词库和纠错、不读取输入框内容、不写日志;剪贴板历史和语音输入可用。语音只在结束时把最终结果一次性上屏,不显示中间结果;来源应用标记为敏感的剪贴板内容和要求关闭个性化学习的输入框仍不进入历史。
- 语音音频只在内存中处理,结束、取消或失败时清空。
- 「设置 → 关于与数据」可导出和合并导入用户数据(剪贴板历史不导出);卸载会清除本机全部数据。
- 测试用 Activity 与 E2E 接收器只存在于 debug 变体。

### 许可证与发布
- 以 GPL-3.0-only 发布,见仓库根目录 `LICENSE`。
- 发布包为固定签名的 `arm64-v8a` APK,随附 SHA-256 校验和与第三方许可清单;版本号规则见 [发布与版本管理](https://github.com/Slacker-LLC/openIME/blob/main/docs/RELEASE.md)。

[Unreleased]: https://github.com/Slacker-LLC/openIME/compare/v0.0.1-beta.1...HEAD
[0.0.1-beta.1]: https://github.com/Slacker-LLC/openIME/releases/tag/v0.0.1-beta.1
Loading
Loading