docs: 完善全部项目文档

- 重写根 README.md(项目结构 + 快速开始 + 品牌配置 + 调试说明 + 技术栈)
- 重写 web_shell_core/README.md(功能表 + 使用方式 + 代码结构 + 测试 + 原生层)
- 重写 apps/quanxue/README.md(品牌应用说明)
- 更新 packages/web_android_shell/README.md(迁移通知)
- 填充 web_shell_core/CHANGELOG.md(0.0.1 初始发布内容)
- 新增 doc/architecture.md(分层架构 + 启动流程 + Bridge 协议 + 兼容策略)
- 修正 pubspec.yaml 中的占位 description
This commit is contained in:
Max 2026-03-19 20:00:04 +08:00
parent 97be25b332
commit 115713d8f4
9 changed files with 301 additions and 185 deletions

View File

@ -1,28 +1,86 @@
# web_android_shell # web_android_shell
Android 平板专用 H5 壳项目。 Android 平板专用 H5 壳应用 — Monorepo 多品牌架构。
## 项目结构
```
web_android_shell/
├── apps/ # 品牌应用(每个品牌一个 Flutter App
│ └── quanxue/ # 全学通
├── packages/
│ ├── web_shell_core/ # 核心库WebView 引擎 + Bridge + 服务)
│ └── web_android_shell/ # 旧版入口(已迁移至 apps/quanxue
├── flavors/ # 品牌配置 YAML
│ └── quanxue.yaml
├── tool/
│ ├── generate_app.dart # 一键生成新品牌应用
│ └── flutter_run_fresh.ps1 # Windows 调试脚本(自动杀旧进程)
└── doc/ # 项目文档
```
## 快速开始
### 1. 运行已有品牌
```bash
cd apps/quanxue
flutter run
```
### 2. 生成新品牌
```bash
# 1) 在 flavors/ 下创建品牌配置
cp flavors/quanxue.yaml flavors/新品牌.yaml
# 2) 修改配置中的 app_name, application_id, app_key, theme
# 3) 运行生成脚本
dart run tool/generate_app.dart 新品牌
```
生成脚本会自动完成:
- 创建 Flutter 应用 → `apps/新品牌/`
- 添加 `web_shell_core` 依赖
- 覆写 `MainActivity` 继承 `CoreShellActivity`
- 生成品牌入口 `main.dart`
- 配置 `flutter_launcher_icons`
### 3. 品牌配置格式
```yaml
app_name: "全学通" # 应用名
application_id: "com.wanmake.quanxue" # 包名
app_key: "quanxue_prod" # 业务标识
theme:
accent_color: "0xFF3ED37B" # 主题色
bg_color: "0xFFFFFFFF" # 背景色
text_color: "0xFF1F2937" # 主文字色
muted_text_color: "0xFF6B7280" # 次要文字色
```
## 调试说明 ## 调试说明
这个项目在部分设备上,如果直接用 `Ctrl+C` 结束 `flutter run`,设备里的上一次 App 进程可能还留在后台,下一次运行时会影响内嵌 WebView 启动。 部分教育平板设备使用 `Ctrl+C` 结束 `flutter run` 后,旧进程可能留在后台影响 WebView 启动。
更稳的做法: **推荐做法:**
- 调试结束时在 `flutter run` 控制台按 `q` 退出
- 调试结束时优先在 `flutter run` 里按 `q` - 或使用调试脚本自动杀旧进程再启动:
- 或者使用项目自带脚本,先自动杀掉旧进程再启动
```powershell ```powershell
.\tool\flutter_run_fresh.ps1 .\tool\flutter_run_fresh.ps1 # 自动选设备
.\tool\flutter_run_fresh.ps1 -d F136A # 指定设备
``` ```
如果要指定设备,也可以继续透传给 `flutter run` ## 技术栈
```powershell | 组件 | 技术 |
.\tool\flutter_run_fresh.ps1 -d F136A |---|---|
``` | 框架 | Flutter 3.x (Dart 3.11+) |
| WebView | `webview_flutter` + `webview_flutter_android` |
| 宿主能力 | `image_picker` · `file_picker` · `permission_handler` · `url_launcher` |
| 原生层 | Kotlin Plugin + Java `CoreShellActivity` |
| 代码规范 | `very_good_analysis` |
脚本会自动: ## 平台约束
- 读取 `android/local.properties` 中的 `sdk.dir` **仅支持 Android 平板。** iOS / Web / Desktop 平台已移除。
- 调用 `adb shell am force-stop com.yuanxuan.webshell.web_android_shell`
- 然后执行 `flutter run`

View File

@ -1,17 +1,35 @@
# quanxue # 全学通 (quanxue)
A new Flutter project. 「全学通」品牌的 Android 平板 H5 壳应用。
## Getting Started ## 概述
This project is a starting point for a Flutter application. 本应用是 `web_shell_core` 核心库的品牌实例。`main.dart` 仅 16 行代码,只负责传入品牌配置,所有业务逻辑由核心库提供。
A few resources to get you started if this is your first Flutter project: ## 运行
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter) ```bash
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) flutter run
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources) ```
For help getting started with Flutter development, view the ## 配置
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference. | 配置项 | 值 |
|---|---|
| 应用名 | 全学通 |
| 包名 | `com.wanmake.quanxue` |
| 业务标识 | `quanxue_prod` |
| 主题色 | `#3ED37B` |
品牌配置源文件:[`flavors/quanxue.yaml`](../../flavors/quanxue.yaml)
## 构建
```bash
flutter build apk --release
```
## 依赖
- `web_shell_core`(本地 path 引用)
- `cupertino_icons`(兼容历史代码)

View File

@ -1,5 +1,5 @@
name: quanxue name: quanxue
description: "A new Flutter project." description: "全学通 — Android 平板 H5 壳应用。"
# 阻止误发布到 pub.dev。 # 阻止误发布到 pub.dev。
publish_to: 'none' publish_to: 'none'

93
doc/architecture.md Normal file
View File

@ -0,0 +1,93 @@
# 架构设计
## 整体架构
```
┌──────────────────────────────────────────────────────┐
│ apps/quanxue apps/品牌B apps/品牌C │ 品牌应用层
│ (16 行 main.dart) │ 只传 ShellEnvironment
├──────────────────────────────────────────────────────┤
│ web_shell_core │ 核心库
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ config │ │ engine │ │ bridge │ │
│ │ 环境配置 │ │ 兼容引擎 │ │ JS 桥接 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ services │ │ ui │ │ testing │ │
│ │ 宿主服务 │ │ 壳层界面 │ │ 测试钩子 │ │
│ └──────────┘ └──────────┘ └──────────┘ │
├──────────────────────────────────────────────────────┤
│ CoreShellActivity (Java) │ 原生层
│ 进程隔离 · WebView 信息查询 · 深度重置 │
└──────────────────────────────────────────────────────┘
```
## 核心流程
### 1. 启动流程
```
main() → runShellApp(env)
→ WidgetsFlutterBinding.ensureInitialized()
→ 设置屏幕方向(竖屏锁定)
→ 进入沉浸式模式
→ runApp(ShellApp)
→ Android? → WebShellPageWebView 容器)
→ 其他? → UnsupportedPlatformPage兜底页
```
### 2. WebView 启动与恢复
```
WebShellPage.initState()
→ 查询 Android WebView 信息SDK / 包名 / 版本号)
→ 生成兼容性策略renderModes / useWideViewPort / aggressiveRecovery
→ 创建 WebView默认 texture 模式)
→ 首帧就绪后加载初始 URL
→ 启动看门狗计时器
→ 超时? → 切换渲染模式hybrid→ 深度清理 → 自动重试
→ 再超时? → 展示错误页 + 兼容性提示
```
### 3. JS Bridge 协议
```
H5 页面 Flutter 壳
│ │
│ AppShellChannel. │
│ postMessage(JSON) │
│ ──────────────────────→ │ 解析 action + payload
│ │ 执行对应 handler
│ window. │
│ __appShellReceiveResponse│
│ ←────────────────────── │ 返回 { requestId, success, data/error }
```
**支持的 Action**
| Action | 说明 | 返回 |
|---|---|---|
| `pickImage` | 从图库选图(支持多选) | `[{name, uri, mimeType, size, dataUrl}]` |
| `captureImage` | 相机拍照 | `{name, uri, mimeType, size, dataUrl}` |
| `pickFile` | 文件选择 | `[{name, uri, mimeType, size, dataUrl}]` |
| `openExternal` | 打开外部应用 | `boolean` |
| `requestPermissions` | 请求系统权限 | `{type: statusName}` |
| `reloadPage` | 重新加载当前页面 | `true` |
| `goBack` | 返回上一页 | `boolean` |
| `closeApp` | 关闭应用 | 无(直接退出) |
## 兼容性策略
| 条件 | 渲染模式 | 恢复策略 |
|---|---|---|
| SDK ≥ 29 + WebView ≥ 113 | texture 优先 | 标准恢复 |
| SDK ≤ 28 或 WebView < 113 | hybrid 优先 | 激进恢复2 次重试 |
| F136A 设备 | hybrid 优先 | 激进恢复 + 建议更新 WebView |
## 新增品牌
1. 创建 `flavors/品牌名.yaml`
2. 运行 `dart run tool/generate_app.dart 品牌名`
3. 脚本自动生成完整的 Flutter App 在 `apps/品牌名/`
4. 修改图标后运行 `flutter pub run flutter_launcher_icons`
5. 构建 APK`flutter build apk --release`

View File

@ -1,125 +0,0 @@
# Role & Context
你是一个精通 Flutter 混合架构Hybrid App与移动端 APM应用性能监控的资深架构师。
当前任务为一款基于“单工程多风味Flavors”架构的教育平板应用包含“劝学”和“点智学”两个 Flavor生成核心 MVP 代码框架与监控埋点方案。
底层环境约定:兼容 Android 14量产基线并向下兼容处理 Android 15 的 WindowInsetsEdge-to-Edge特性。
# Product Architecture (Flutter 壳与 H5 的边界界定)
本 MVP 采用“瘦壳重网页”模式:
1. **Flutter 壳职责:** 仅负责生命周期管理、沉浸式/Kiosk 模式控制、设备硬件能力桥接(相机/录音/持久化存储、全局骨架屏Loading、以及高可用 WebView 容器的维护。
2. **H5 职责:** 承载所有教学业务逻辑(题库、视频播放、个人中心)。
3. **通信机制:** 统一通过注入的 `JSBridge` 进行双向通信。
# MVP Core Modules (核心功能模块需求)
## 1. 动态环境与配置引擎 (Config Engine)
- **需求:** 读取 `--dart-define=APP_FLAVOR`
- **功能:** 根据 Flavor 动态下发不同的 `baseUrl`H5 首页地址)、主题色、以及持久化缓存策略。
## 2. 高可用 WebView 容器 (Core Web Container)
- **核心依赖:** 使用 `webview_flutter``flutter_inappwebview`
- **Android 15 兼容性(关键):** WebView Widget 必须包裹在自定义的 `SafeArea` 或响应 `WindowInsets` 的布局中,将顶部的 `statusBarHeight` 和底部的 `navigationBarHeight` 动态获取,并作为 URL 参数或注入的 JS 变量传给 H5供前端写 CSS 避让区。
- **Cookie 策略:** 必须显式开启 `Third-Party Cookies``DOM Storage`,确保跨域 SSO 单点登录不掉线。
## 3. 标准化 JSBridge 协议层
要求实现一个健壮的 JSBridge 类,至少包含以下基础方法,供 H5 调用:
- `getDeviceInfo()`: 返回系统版本、电量、当前网络状态WiFi/4G
- `setImmersiveMode(boolean)`: 控制隐藏/显示系统状态栏和底部导航栏。
- `openCamera(config)`: 唤起原生相机并返回 Base64 或文件路径。
- `reportEvent(eventName, params)`: H5 将核心业务埋点转发给 Flutter 壳进行统一上报。
## 4. Kiosk Mode (专注模式/设备管控)
- 预留 `MethodChannel` 接口,命名为 `DeviceControlChannel`
- 包含方法 `enableKioskMode()``disableKioskMode()`(具体 Android 原生端 `startLockTask` 逻辑暂用 TODO 占位,需定义好 Dart 侧的调用规范)。
---
# APM & Observability Metrics (应用性能与稳定性指标体系)
请在代码中创建一个 `AppMonitor` 单例类,负责拦截并上报以下三大类核心指标(目前先在控制台打印日志,预留后续接入 Firebase / Sentry / 自研后端的接口):
## 1. 容器加载性能指标 (Performance)
- `Shell_Launch_Time`: Flutter 引擎初始化到原生首屏Splash 结束)的耗时。
- `WebView_Init_Time`: 从触发加载到 WebView 实例创建完成的耗时。
- `H5_TTFB (Time to First Byte)`: Web 页面发出请求到收到第一个字节的耗时(需注入 JS 获取)。
- `H5_FCP (First Contentful Paint)`: 白屏时间(从 `onPageStarted``onPageFinished`,结合 JS 注入获取真实渲染时间)。
## 2. 稳定性指标 (Stability)
- `WebView_Crash_Rate`: 捕获 `onWebResourceError`,特别是 `OOM`(内存溢出)导致的白屏终止。
- `JSBridge_Fail_Count`: 统计 H5 调用原生能力失败的次数与错误码(如权限被拒、参数格式错误)。
- `Http_Error_Rate`: 拦截并统计 WebView 内发生的 404/500 等静态资源或接口请求错误。
## 3. 业务与设备指标 (Business & Device)
- `Session_Duration`: 从应用 `resumed``paused` 的有效停留时间。
- `Network_Switch_Count`: 监听网络状态,记录用户在弱网/断网环境下的掉线频次。
---
# Execution Steps for Code X (执行步骤)
请一步步为我生成上述方案的代码骨架:
1. **Step 1:** 生成目录结构建议(基于 feature 驱动或分层架构)。
2. **Step 2:** 生成 `Config Engine``AppMonitor` 的单例类代码,实现核心指标的日志打印结构。
3. **Step 3:** 编写核心的 `HybridWebView` Widget包含 Insets 处理、Cookie 策略配置和首屏加载时间计算。
4. **Step 4:** 编写 `JSBridge` 核心处理类,实现拦截 H5 消息并路由到对应原生方法的逻辑。

View File

@ -1,28 +1,7 @@
# web_android_shell # web_android_shell(已迁移)
H5 壳子项目 > ⚠️ 本包为旧版入口,已迁移至 Monorepo 架构
## 调试说明 当前用途:为旧版 `MainActivity` 提供壳层入口,调用 `web_shell_core` 启动应用。
这个项目在部分设备上,如果直接用 `Ctrl+C` 结束 `flutter run`,设备里的上一次 App 进程可能还留在后台,下一次运行时会影响内嵌 WebView 启动。 新品牌应用请使用 `apps/` 目录下的独立应用,参考 [`apps/quanxue/`](../../apps/quanxue/)。
更稳的做法:
- 调试结束时优先在 `flutter run` 里按 `q`
- 或者使用项目自带脚本,先自动杀掉旧进程再启动
```powershell
.\tool\flutter_run_fresh.ps1
```
如果要指定设备,也可以继续透传给 `flutter run`
```powershell
.\tool\flutter_run_fresh.ps1 -d F136A
```
脚本会自动:
- 读取 `android/local.properties` 中的 `sdk.dir`
- 调用 `adb shell am force-stop com.yuanxuan.webshell.web_android_shell`
- 然后执行 `flutter run`

View File

@ -1,3 +1,16 @@
# Changelog
## 0.0.1 ## 0.0.1
* TODO: Describe initial release. ### 新增
- 从 `web_android_shell` 提取核心库,支持多品牌白标架构
- `runShellApp()` 唯一入口 + `ShellEnvironment` 品牌配置
- 15 个模块文件拆分config / engine / bridge / services / ui
- Android WebView 兼容性自动检测(`AndroidWebViewInfo` + `AndroidCompatibilityPlan`
- 双渲染模式texture / hybrid自动切换 + 启动看门狗恢复链
- `window.AppShell` JS Bridge 协议8 种 Action
- 旧相机 JS 兼容层(`openCamera` / `captureImage` monkey-patch
- 媒体序列化支持 `base64` / `dataUrl` / `uri` 三种格式
- 54 个单元测试 + Widget 测试
- `CoreShellActivity` 原生层(进程隔离 + WebView 信息查询 + 深度重置)
- 全中文 `debugPrint` 日志

View File

@ -1,12 +1,92 @@
# web_shell_core # web_shell_core
Android 平板专用的 H5 壳核心库,负责: Android 平板专用的 H5 壳核心库。所有品牌应用共享此库,只需传入 `ShellEnvironment` 即可启动。
- WebView 启动与恢复 ## 功能
- H5 / Native JS Bridge
- 文件、相机、权限等宿主能力 | 模块 | 说明 |
- 品牌化壳层 UI |---|---|
| **WebView 引擎** | 自动兼容低版本 Android WebView支持 texture / hybrid 双渲染模式自动切换 |
| **启动恢复** | 看门狗超时检测 → 渲染模式降级 → 深度清理 → 自动重试 |
| **JS Bridge** | `window.AppShell` 协议,支持 8 种 ActionpickImage · captureImage · pickFile · openExternal · requestPermissions · reloadPage · goBack · closeApp |
| **旧相机兼容** | Monkey-patch `openCamera` / `captureImage` 兼容老 H5 页面 |
| **媒体服务** | 相机拍照 · 图库选图 · 文件选择 · base64 / dataUrl / uri 三种序列化格式 |
| **权限服务** | camera · microphone · location · photos · videos · storage 统一映射 |
| **导航服务** | URL scheme 白名单路由,非 WebView 协议自动跳转外部应用 |
| **壳层 UI** | 启动加载动画 · 错误恢复页 · 进度条 · 不支持平台兜底页 |
## 使用方式
```dart
import 'package:web_shell_core/web_shell_core.dart';
void main() {
runShellApp(
ShellEnvironment(
appName: '全学通',
appKey: 'quanxue_prod',
accentColor: Color(0xFF3ED37B),
backgroundColor: Color(0xFFFFFFFF),
textColor: Color(0xFF1F2937),
mutedTextColor: Color(0xFF6B7280),
initialUrl: 'example.com/login', // 可选,不传使用默认地址
),
);
}
```
## 代码结构
```
lib/
├── core_app.dart # 库入口 + part 指令 + runShellApp()
├── web_shell_core.dart # 公开 API 导出
└── src/
├── config/
│ ├── shell_environment.dart # 品牌配置数据类
│ └── url_resolver.dart # URL 解析与归一化
├── engine/
│ ├── compatibility.dart # Android WebView 兼容检测
│ └── recovery.dart # 启动看门狗 + 错误映射
├── bridge/
│ ├── bridge_protocol.dart # JS Bridge 注入与响应
│ ├── bridge_actions.dart # Action handler占位
│ └── legacy_camera_compat.dart # 旧相机 JS 兼容层
├── services/
│ ├── media_service.dart # 相机/图库/文件 + 序列化
│ ├── permission_service.dart # 权限类型映射
│ └── navigation_service.dart # URL 路由 + 外链跳转
├── ui/
│ ├── shell_app.dart # MaterialApp 入口
│ ├── shell_page.dart # WebView 主页面
│ ├── launch_overlay.dart # 启动加载动画
│ ├── error_overlay.dart # 错误恢复页
│ ├── progress_bar.dart # 顶部进度条
│ └── unsupported_platform_page.dart # 平台兜底页
└── testing/
└── test_hooks.dart # 测试钩子(@visibleForTesting
```
## 测试
```bash
cd packages/web_shell_core
flutter test
```
当前 **54 个测试用例**,覆盖:
- 平台检测 · URL 解析 · 兼容性策略 · 错误映射
- Bridge 注入/响应/异常处理 · 媒体序列化 · 权限映射
- 导航路由 · 所有独立 UI 组件
## 平台约束 ## 平台约束
当前仅支持 Android。 仅支持 **Android**。其他平台会展示兜底提示页。
## Android 原生层
`CoreShellActivity`Java提供
- WebView 数据目录隔离(避免多进程冲突)
- 旧进程自动终止
- WebView 信息查询SDK 版本、WebView 包名/版本号)
- WebView 状态深度重置

View File

@ -1,5 +1,5 @@
name: web_shell_core name: web_shell_core
description: "A new Flutter plugin project." description: "Android 平板专用 H5 壳核心库,提供 WebView 引擎、JS Bridge 和宿主服务。"
version: 0.0.1 version: 0.0.1
homepage: homepage: