拦截内置浏览器,邮件正文里的链接直接用外部默认浏览器打开。
适用于 QQ 邮箱 Android 版(com.tencent.androidqqmail,已在 7.1.7 上验证)。安装后在邮件正文里点击 http/https 链接时,不再启动 QQ 邮箱的内置浏览器(腾讯 XWeb 内核的 WebViewExplorer),而是直接交给系统默认浏览器;从浏览器返回即回到邮件正文。
本模块已被 LSPosed 官方模块仓库收录:Xposed-Modules-Repo/com.qqmail.extlink,并展示于 modules.lsposed.org。下载 APK 以官方仓库 Release 为准。
- 点链接直接进外部浏览器,内置浏览器窗口完全不出现
- 复用 QQ 邮箱自家
openBrowser()的"记住默认浏览器"逻辑(SharedPreferencesspread/url),没有记忆时弹系统选择器 tel:/mailto:/intent:等特殊协议不受影响mail.qq.com/exmail.qq.com等 QQ 邮箱自家功能页、登录流程不受影响- 腾讯文档 / 微盘 / 卡片等专用预览页默认保持内置(可在源码改为全部外置)
邮件正文点链接的链路是:ReadMailFragment 构造指向 WebViewExplorer 的 Intent → startActivity → 内置浏览器启动加载。本模块按链接生命周期从早到晚拦三层:
| 层 | Hook 点 | 作用 |
|---|---|---|
| 0(主拦截) | ContextWrapper/Activity 的 startActivity / startActivityForResult |
启动内置浏览器的 Intent 发出前劫持:外链就地改发外部浏览器,取消原启动 |
| 1(兜底) | WebViewExplorer$BaseWebViewClient.shouldSafeOverrideUrlLoading |
内置浏览器内点外链也外置,并 finish() 宿主 |
| 2(双保险) | WebViewExplorer.initDataSource |
绕过第 0 层的启动路径在 Activity 创建早期再拦一次 |
外置派发按 openBrowser() 的 smali 逻辑实现:ACTION_VIEW + queryIntentActivities(MATCH_DEFAULT_ONLY) + 记忆包名匹配 + Intent.createChooser 兜底。
- 手机已 root 并安装 LSPosed
- 安装 Releases 里的 APK
- LSPosed 管理器中启用本模块,作用域勾选 QQ邮箱
- 强制停止 QQ 邮箱后重新打开
- 打开邮件点链接即可;首次若弹"选择浏览器",选一个并点"始终"
不依赖 Gradle/Android Studio,用 JDK + Android build-tools 手动链构建:
aapt2 compile/link → javac --release 11 → d8 → 打包 → zipalign → apksigner
准备:
- JDK(
javac/java/keytool在 PATH) - 下载并解压到
<BUILD_ROOT>/sdk/:- build-tools 35.0.1(解压目录改名为
android-15) - platform 35(解压目录为
android-35)
- build-tools 35.0.1(解压目录改名为
- 下载 XposedBridgeApi-82.jar 放到
<BUILD_ROOT>/
构建(BUILD_ROOT 默认为仓库目录,可用环境变量 QMBUILD_ROOT 覆盖):
python -X utf8 build/build_modules.py产物在 dist/。签名库首次构建时自动生成(module.keystore)。
注意:Windows 下
BUILD_ROOT必须是纯 ASCII 路径,aapt2 不支持中文路径。
modules/QQMailExternalLink/ 模块源码(QQ邮箱取消内置浏览器)
build/build_modules.py 构建脚本
本项目仅用于个人学习与研究,请遵守相关软件的服务条款与所在地区法律法规。QQ 邮箱是腾讯公司的产品,本项目与腾讯无任何关联。