Hyper Browser 是一个 Android 原生浏览器和 WebApp 容器项目,使用 Kotlin、Jetpack Compose、Material3 和 GeckoView 构建。
它不是普通 Demo 浏览器。当前目标是做一个接近 Chrome Android 基础交互的浏览器壳:能打开普通网页、管理多标签、保存书签和历史、处理下载、把任意 URL 安装成类 App 容器,并支持 GeckoView WebExtension。
当前项目处于 alpha 阶段,适合开发者、测试用户和对 GeckoView Android 浏览器壳感兴趣的人试用。它还不是经过大规模安全审计的稳定浏览器。
公开发布包通过 GitHub Releases 分发,APK 按 CPU 架构拆分:
arm64-v8a:大多数现代 Android 手机。armeabi-v7a:较老的 32 位 Android 设备。x86_64:部分模拟器和 x86 Android 设备。
如果不确定设备架构,优先尝试 arm64-v8a。安装 APK 时需要允许当前安装来源安装未知应用。
- 当前没有账号同步、跨设备同步或云备份服务。
- 当前没有隐身模式;历史、书签和设置按普通浏览器数据保存在 App 私有目录。
- 当前 APK 通过 GitHub Releases 分发,不是 Play Store / F-Droid 正式渠道包。
- 当前 updater 使用 GitHub Release split APK,需要 release 索引提供匹配设备架构的正式签名 APK。
- WebExtension 支持基于 GeckoView 能力,不等同于桌面 Firefox 的完整扩展体验。
- GeckoView 浏览器内核,普通浏览器标签和 WebApp 默认共享同一个
GeckoRuntime/ profile。 - Chrome Android 风格主界面:主页、圆角地址栏、标签计数、三点菜单、搜索/地址输入页。
- 多标签管理,标签页支持 Card / List 两种模式;Card 模式使用 GeckoView 页面截图缩略图。
- 移动端链接打开策略:普通点击拦截
target=_blank新窗口请求并在当前标签页直接跳转;长按链接时再提供“在新标签页打开”。 - 内置页面:主页、搜索、设置、WebApp 管理、书签、历史。
- 书签、历史、设置、下载记录、favicon 缓存和 WebApp 定义使用 App 私有目录 JSON/文件保存。
- 当前页面可安装为 WebApp,并支持创建 Android pinned shortcut。
- 独立
WebAppActivity,用于类 App 方式启动已安装网页。 - Android AMO 扩展搜索、XPI 安装、启用/禁用、卸载、扩展菜单 action 和 popup。
- 内置 WebExtension bridge,让内置 React 页面通过
window.hyperBrowser调用 Kotlin 浏览器壳能力。 - GeckoView 媒体会话通知,支持从系统通知执行播放、暂停、前后跳转等媒体动作。
- 下载处理和下载列表页。
- 下拉刷新会结合 GeckoView 滚动状态和页面内部滚动容器状态,避免内部容器未到顶部时误触发刷新。
- Android:Kotlin
- UI:Jetpack Compose / Material3
- 浏览器内核:Mozilla GeckoView
151.0.20260525130955 - 构建:Gradle Wrapper
- Java:17
- Android SDK:
compileSdk 36/targetSdk 36/minSdk 26 - 包名:
com.dadigua.hyperbrowser - 内置页面:React 19 + TypeScript + Vite
- JS 包管理:pnpm
- 开源许可:Apache-2.0
.
├── app/
│ └── src/main/
│ ├── assets/
│ │ ├── apps.html
│ │ ├── bookmarks.html
│ │ ├── history.html
│ │ ├── home.html
│ │ ├── search.html
│ │ ├── settings.html
│ │ └── internal/
│ └── java/com/dadigua/hyperbrowser/
│ ├── HyperBrowserApp.kt
│ ├── browser/
│ ├── data/
│ ├── extensions/
│ ├── gecko/
│ ├── ui/browser/
│ ├── ui/webapp/
│ ├── ui/theme/
│ └── webapp/
├── internal-pages/
│ ├── public/
│ │ ├── background.js
│ │ ├── manifest.json
│ │ └── pull-refresh-content.js
│ ├── src/
│ │ ├── hyper-browser.ts
│ │ └── pages/
│ └── vite.config.ts
├── build.gradle.kts
├── settings.gradle.kts
└── gradlew.bat
HyperBrowserApp.kt
全局 Application 入口,持有webApps和extensions仓库。ui/browser/BrowserActivity.kt
主浏览器 Activity,也是 launcher 入口;包含 toolbar、菜单、搜索页、标签页、下载页、书签/历史页、扩展页和内置页命令分发。ui/webapp/WebAppActivity.kt
独立 WebApp Activity,用于启动已安装的网页 App。gecko/GeckoRuntimeProvider.kt
全局单例GeckoRuntime配置,在 debuggable 构建中启用 remote debugging,并设置 WebExtension 安装/更新权限 prompt 策略。gecko/GeckoSessionController.kt
单个 tab/WebApp 的GeckoSession封装,负责导航、内置路由、崩溃恢复、下载请求、媒体 session、bridge 注册、下拉刷新状态,以及把target=_blank/ 新窗口请求收敛为当前标签页跳转。gecko/GeckoBrowserView.kt
ComposeAndroidView中的 GeckoView 包装和下拉刷新手势处理。gecko/HyperBridge.kt
内置 WebExtension native-message bridge,只接受可信内置页面 sender,普通网页只允许上报下拉刷新触摸状态。extensions/ExtensionRepository.kt
AMO 搜索、XPI 下载和安装、扩展启停/卸载、菜单 action、popup session 和扩展新标签请求。browser/BrowserProfileStore.kt
保存书签、历史和浏览器设置。browser/DownloadHandler.kt/browser/DownloadStore.kt
处理 GeckoView 下载请求、系统下载状态同步和下载记录。browser/FaviconRepository.kt
favicon 下载、缓存和 data URL 输出。browser/BrowserMediaNotificationController.kt
GeckoView 媒体会话到 Android 媒体通知的桥接。webapp/WebAppRepository.kt
WebApp 定义、图标解析和 pinned shortcut 集成。
- Windows PowerShell。
- JDK 17。
- Android SDK,并且有可通过
adb访问的真机或模拟器。 - pnpm,用于构建内置页面。
项目优先使用 Gradle Wrapper,不依赖全局 Gradle。
构建 debug APK:
.\gradlew.bat :app:assembleDebug --console=plainAndroid preBuild 会自动执行 internal-pages 的 pnpm install/build,并把产物输出到 app/src/main/assets/。
构建 release APK:
.\gradlew.bat :app:assembleRelease --console=plainrelease 构建会生成未签名 split APK。公开发布请使用 GitHub Actions release workflow 签名,并按 发布流程 更新 update/stable.json。
只构建内置页面:
pnpm --dir internal-pages build只检查内置页面 TypeScript 类型:
pnpm --dir internal-pages typecheck安装 debug APK:
.\gradlew.bat :app:installDebug --console=plain启动 App:
adb shell monkey -p com.dadigua.hyperbrowser 1启动浏览器 Activity 并打开指定 URL:
adb shell am force-stop com.dadigua.hyperbrowser
adb shell am start -n com.dadigua.hyperbrowser/.ui.browser.BrowserActivity --es extra_url https://example.com确认 launcher 入口:
adb shell cmd package resolve-activity --brief com.dadigua.hyperbrowser期望结果:
com.dadigua.hyperbrowser/.ui.browser.BrowserActivity
内置页面源码在 internal-pages/,构建产物输出到 app/src/main/assets/。Vite 当前会打包 6 个入口:
home.htmlsearch.htmlsettings.htmlapps.htmlbookmarks.htmlhistory.html
语义路由:
hyper://homehyper://searchhyper://settingshyper://appshyper://bookmarkshyper://history
运行时页面通过内置 WebExtension 的 moz-extension://... base URL 加载,地址栏和历史展示仍映射为用户可读的 hyper://... URL。
不要手改这些生成文件:
app/src/main/assets/*.html
app/src/main/assets/internal/
app/src/main/assets/background.js
app/src/main/assets/manifest.json
app/src/main/assets/pull-refresh-content.js
需要改内置页面时,修改 internal-pages/ 源码,然后运行:
pnpm --dir internal-pages build内置 bridge 由 internal-pages/public/ 下的 built-in WebExtension 提供。
通信链路:
内置页面 JS
-> window.hyperBrowser
-> browser.runtime.sendMessage(...)
-> background.js
-> browser.runtime.sendNativeMessage("hyperBrowser", ...)
-> Kotlin HyperBridge
-> BrowserActivity / GeckoSessionController
内置页面通过页面生命周期主动请求数据:
requestHomeData()requestBookmarksData()requestHistoryData()
安全规则:
- 内置 WebExtension 页面可以发送浏览器命令,也可以请求书签、历史、设置、WebApp 等数据。
- 普通网页、第三方扩展页、
http/https页面不能调用特权浏览器命令。 - 普通网页只允许发送
pullRefresh.touch,用于辅助判断页面内部滚动容器是否已经到顶部。 - Kotlin bridge 返回给 WebExtension 的值使用 JSON string,避免 GeckoView 回调序列化问题。
扩展能力集中在 ExtensionRepository.kt 和 BrowserActivity.kt:
- 从 Android AMO catalog 搜索扩展。
- 下载并安装 XPI。
- 启用、禁用和卸载已安装扩展。
- 主菜单中的
Extensions行可展开,已启用扩展作为子项显示。 - 点击扩展条目本身触发 WebExtension action/popup。
- 条目右侧
Settings和底部Manage extensions才进入扩展管理。 - popup 内部打开 options/control panel 时,会在浏览器中新建 tab 打开对应
moz-extension://...页面。
GeckoView WebExtension 管理 API 对线程要求严格,需要 Handler 的调用应切到 Dispatchers.Main.immediate。
作为手机浏览器,Hyper Browser 默认不让网页的 target=_blank 自动打散用户当前上下文。普通点击链接时,如果页面尝试打开新窗口或新标签,GeckoSessionController.onNewSession(...) 会拦截请求,并把目标 URL 直接加载到当前标签页。
需要新标签时使用移动端更明确的操作:长按链接打开链接菜单,再选择“在新标签页打开”。这能减少网页随意弹出新标签带来的跳转混乱,同时保留用户主动多标签浏览的能力。
当前版本没有使用 Room/DataStore,而是使用 App 私有目录下的 JSON 文件和 favicon 目录:
browser_history.jsonbrowser_bookmarks.jsonbrowser_settings.jsonbrowser_downloads.jsonweb_apps.jsoninstalled_extensions.jsonfavicons/
调试已安装扩展状态时可读取:
adb shell run-as com.dadigua.hyperbrowser cat files/installed_extensions.json- JS 包管理优先使用
pnpm,不要默认用npm。 - Android 构建优先使用 Gradle Wrapper。
- 原生 App 代码是 Kotlin + Compose。
- 内置页面是 React + TypeScript。
GeckoRuntimeProvider必须保持单例,这样普通浏览器标签和 WebApp 才能共享 Cookie/profile。- release 包必须使用持久签名 key,不要发布临时 CI key 签名的 APK,否则后续用户无法平滑升级。
- 修浏览器交互时不要做大范围无关重构,核心逻辑通常集中在
BrowserActivity.kt、GeckoSessionController.kt、GeckoBrowserView.kt和ExtensionRepository.kt。 - 调试 GeckoView 内容、扩展 popup 或内置页 DOM 时,优先使用 Firefox
about:debugging连接 Android 设备;uiautomator更适合确认 Compose 外层文本和 bounds。
# 构建 debug APK
.\gradlew.bat :app:assembleDebug --console=plain
# 构建 release APK
.\gradlew.bat :app:assembleRelease --console=plain
# 单元测试
.\gradlew.bat :app:testDebugUnitTest --console=plain
# 安装 debug APK
.\gradlew.bat :app:installDebug --console=plain
# 构建内置页面
pnpm --dir internal-pages build
# 检查内置页面类型
pnpm --dir internal-pages typecheck
# 启动 App
adb shell monkey -p com.dadigua.hyperbrowser 1
# 打开指定 URL
adb shell am start -n com.dadigua.hyperbrowser/.ui.browser.BrowserActivity --es extra_url https://example.com
# 检查当前前台窗口
adb shell dumpsys window | Select-String -Pattern "mCurrentFocus|mFocusedApp"修改浏览器主交互后,建议手工检查:
- 构建并安装 debug APK。
- 启动 App。
- 打开
https://example.com。 - 点击地址栏,确认能进入搜索/地址输入页。
- 打开三点菜单,确认导航、下载、扩展、书签、历史、设置入口可用。
- 展开三点菜单里的
Extensions,确认已启用扩展作为子项显示。 - 打开标签页,确认 Card/List 模式可切换。
- 打开
hyper://home、hyper://bookmarks、hyper://history、hyper://apps、hyper://settings,确认内置页可以加载和返回。 - 点击带
target=_blank的链接,确认不会自动新开标签,而是在当前标签页跳转。 - 长按普通链接,确认菜单里可以选择“在新标签页打开”。
- 在普通页面测试返回键:搜索页、书签页、历史页、扩展页、标签页应先关闭面板;普通网页页应优先执行网页后退。
- 在普通 body 滚动页面和内部滚动容器页面测试下拉刷新,内部容器未到顶部时不应触发浏览器刷新。
Hyper Browser is licensed under the Apache License, Version 2.0. See LICENSE.