面向官方 Telegram 的 LSPosed 模块,用于调整部分交互并扩展消息与资料页的常用能力。
| 功能 | 说明 |
|---|---|
| 🚫 禁用下拉跳转 | 在频道页下滑时不再跳转到下一个频道 |
| 🚫 禁用双击 reaction | 双击消息不再触发快速 reaction |
| 🚫 禁用 greeting sticker 发送 | 点击问候贴纸不再直接发送,仅保留展示 |
| 🔓 解除保护内容限制 | 允许在开启“限制保存内容”的会话中截图、复制等 |
| 💾 允许保存阅后即焚媒体 | 阅后即焚媒体按普通媒体处理:可保存到相册/下载,不会自动清空 |
➕ 消息 +1 重发 |
在消息菜单中新增 +1 选项,快速转发或直接按内容重发 |
| 💾 保存 sticker 到相册 | 聊天消息菜单与 sticker 预览菜单新增「保存到相册」 |
| 🆔 头像下显示 ID | 资料页头像区域下方显示用户 / 群组 / 频道 API ID,长按可复制 |
| ↩️ 回复引用转发者 | 回复转发消息时显示转发该消息的用户,而非原始来源 |
当当前会话允许发消息时,长按消息弹出的菜单中会多一个 +1 按钮:
- 点按:将消息以「带来源信息的转发」形式重新发送到当前会话;若原消息来自开启“限制保存内容”的会话,则改为直接发送一条内容相同的消息
- 长按:直接发送一条内容相同的消息(不带转发来源信息);若原消息是回复消息,则回复同一目标
参考 Nekogram 的菜单入口设计,通过 hook 为官方 Telegram 补上 sticker 下载能力:
- 聊天消息:长按 sticker 消息,菜单中会出现「保存到相册」
- sticker 预览:在 sticker 面板长按预览时,菜单中同样会出现「保存到相册」
- TGS 动态贴纸:渲染后导出为 Animated WebP(
.webp) - 其他格式:直接保存原始文件(如静态 WebP、WebM 等),不做转换
- 保存位置:所有 sticker 统一写入系统相册(图片目录)
模块默认只作用于官方 Telegram 包名:
org.telegram.messenger
如需支持其他 Telegram 变体,可修改:
app/src/main/resources/META-INF/xposed/scope.listTelegramHooksModule.kt中的TARGET_PACKAGE常量
- LSPosed — modern API 102
- Kotlin — AGP 9 内置支持,目标 Java 17
- Nix — Flake + direnv 提供可重现的开发环境
# 方式一:使用 direnv(推荐)
direnv allow
./gradlew assembleDebug
# 方式二:不进入 shell
nix develop -c ./gradlew assembleDebug产物路径:app/build/outputs/apk/debug/app-debug.apk
- 将 APK 安装到设备
- 在 LSPosed 中启用 MxGram 模块
- 将作用域勾选到 Telegram(
org.telegram.messenger) - 重启 Telegram 进程
.
├── app/
│ ├── build.gradle.kts
│ └── src/main/
│ ├── AndroidManifest.xml
│ ├── kotlin/dev/xyenon/mxgram/
│ │ ├── TelegramHooksModule.kt # 主 hook 入口
│ │ ├── PlusOneForwarder.kt # +1 转发逻辑
│ │ └── *Hooker.kt # 各 hook 实现
│ ├── res/values/strings.xml
│ └── resources/META-INF/xposed/ # Xposed 元数据
│ ├── java_init.list
│ ├── module.prop
│ └── scope.list
├── flake.nix
├── treefmt.nix
├── .envrc
├── gradlew
└── README.md
| Hook 位置 | 目的 | 策略 |
|---|---|---|
ChatActivity.animateToNextChat() |
禁用下拉跳转 | 直接短路 |
ChatPullingDownDrawable update 方法 |
兜底清除跳转目标 | 清空 nextChat/nextTopic |
ChatActivity.createView |
禁用双击 reaction | 替换监听,禁用 hasDoubleTap() |
ChatActivity.selectReaction |
双保险拦截双击 | fromDoubleTap 为 true 时拦截 |
ChatGreetingsView.setListener |
禁用 greeting sticker 发送 | 清空回调 |
ChatActivity.fillMessageMenu |
插入 +1 / 保存 sticker |
在菜单列表追加自定义选项 |
ChatActivity.processSelectedOption |
执行 +1 / 保存 sticker |
+1 走转发或重发;保存 sticker 走 MediaController.saveFile |
ContentPreviewViewer.getInstance |
sticker 预览菜单 | hook showSheetRunnable.run(),追加「保存到相册」项 |
ChatActivity.createMenu |
为 +1 追加长按逻辑 |
回复消息时保留回复关系重发 |
MessagesController noforwards 判断 |
解除保护内容限制 | 强制返回 false |
MessageObject 构造方法 |
解除保护内容限制 | 清除 messageOwner.noforwards |
MessageObject 构造方法 |
允许保存阅后即焚媒体 | 清除 messageOwner.media.ttl_seconds 等标记 |
ChatActivity.sendSecretMessageRead |
阻止自毁媒体打开后排队删除 | 保留已读上报,但不设置本地销毁 |
ChatActivity.sendSecretMediaDelete |
阻止一次性媒体关闭即焚 | 直接移除关闭时删除回调 |
MessagesController.markMessageAsRead* |
阻止自毁媒体补建删除任务 | 兜底禁用 createDeleteTask / TTL 删除任务 |
MessagesController show-once 删除任务 |
阻止一次性媒体落盘删除 | 直接短路 create/doDeleteShowOnceTask |
ProfileActivity.createView |
添加资料页 ID 文本 | 在头像容器追加只读 TextView |
ProfileActivity.updateProfileData |
刷新资料页 ID | 同步用户 / 群组 / 频道 API ID |
ProfileActivity 布局 / 展开方法 |
对齐资料页 ID | 跟随头像区域位置、颜色和透明度 |
ChatMessageCell.setMessageObjectInternal |
限定回复预览布局作用域 | 仅标记当前正在布局的 replyMessageObject |
MessageObject.getForwardedName |
回复引用显示实际转发者 | 回复预览内返回空值,复用 Telegram 的实际发送者名称回退逻辑 |
主实现文件:app/src/main/kotlin/dev/xyenon/mxgram/TelegramHooksModule.kt
若 Telegram 升级后 hook 失效,优先检查以下类 / 方法:
ChatActivity、ChatActivity.sendSecretMessageRead、ChatActivity.sendSecretMediaDelete、ChatPullingDownDrawable、ChatGreetingsView、MessagesController.markMessageAsRead2、ProfileActivity、ChatActivity.selectReaction、ChatMessageCell.setMessageObjectInternal、MessageObject.getForwardedName
Gradle 通过 Maven Central 引入 API 102 对应工件:
io.github.libxposed:api:102.0.0
direnv allow进入目录后自动加载。提供 JDK 21、Android SDK platform 35、build-tools 35/36。
build-tools 36 是必需的:AGP 构建时会请求该版本,若不预装会向只读 Nix Store 写入并失败。
nix develop在 Amp orb 中,.agents/setup 会将 Telegram 官方源码浅克隆到相邻目录
../TelegramAndroid。快照恢复后会直接复用已有 checkout,避免每次 setup 都联网更新。
setup 还会预热 Nix 开发环境、Gradle 依赖、单元测试和 debug APK 构建;
.agents/resume 只进行快速环境修复与存在性检查,不访问网络。
nix fmt # 格式化(Nix/Java/Kotlin/XML/Markdown)
nix flake check # CI 友好检查minApiVersion=102targetApiVersion=102staticScope=true
入口文件:app/src/main/resources/META-INF/xposed/