当 _hasMainFrameError=true 时,Visibility(visible:false) 将 WebView 替换为 SizedBox.shrink()(0×0),这是 Stack 唯一的非 positioned 子组件。 Scaffold.body 提供松约束(0→max),导致 Stack 尺寸为 0×0, Positioned.fill 的 ErrorOverlay 也变为 0×0,用户只能看到 Scaffold 的 深色背景而看不到错误页面的内容。 修复方式:用 SizedBox.expand() 包裹 Stack,强制紧约束使其始终填满屏幕。 附带变更: - 添加 _debugLog() 封装(kDebugMode 保护) - 在 7 个关键状态转换点添加调试日志 |
||
|---|---|---|
| .. | ||
| android | ||
| lib | ||
| test | ||
| test_assets | ||
| .gitignore | ||
| .metadata | ||
| CHANGELOG.md | ||
| LICENSE | ||
| README.md | ||
| analysis_options.yaml | ||
| devtools_options.yaml | ||
| pubspec.yaml | ||
README.md
web_shell_core
Android 平板专用 H5 壳核心库。所有品牌应用共享此库,只需传入 ShellEnvironment 即可启动。
功能
| 模块 | 说明 |
|---|---|
| WebView 引擎 | 自动兼容低版本 Android WebView,支持 texture / hybrid 双渲染模式自动切换 |
| 启动恢复 | 看门狗超时检测 → 渲染模式降级 → 深度清理 → 自动重试 |
| JS Bridge | window.AppShell 协议,当前支持 12 个 Action |
| 旧相机兼容 | Monkey-patch openCamera / captureImage 兼容老 H5 页面 |
| 媒体服务 | 相机拍照 · 图库选图 · 文件选择 · base64 / dataUrl / uri 三种序列化格式 |
| 权限服务 | camera · microphone · location · photos · videos · storage 统一映射 |
| 导航服务 | URL scheme 白名单路由,非 WebView 协议自动跳转外部应用 |
| 壳层 UI | 启动加载动画 · 错误恢复页 · 进度条 · 不支持平台兜底页 |
| 启动配置 | 支持本地默认启动配置文件、远程启动配置和缓存兜底 |
| 版本检查 | 升级配置独立请求,不再与启动配置共用一个 JSON |
| 方向控制 | 支持通过启动配置动态设置 SystemChrome.setPreferredOrientations |
使用方式
1. 准备本地默认启动配置文件
assets/config/bootstrap.json
{
"initialUrl": "https://example.com/login",
"preferredOrientations": ["portraitUp", "portraitDown"]
}
2. 在应用入口传入环境配置
import 'package:flutter/material.dart';
import 'package:web_shell_core/web_shell_core.dart';
void main() {
runShellApp(
ShellEnvironment(
appName: '全学通',
appKey: 'quanxue_prod',
accentColor: const Color(0xFF3ED37B),
backgroundColor: const Color(0xFFFFFFFF),
textColor: const Color(0xFF1F2937),
mutedTextColor: const Color(0xFF6B7280),
splashImage: const AssetImage('assets/branding/splash.png'),
bootstrapConfigAsset: 'assets/config/bootstrap.json',
bootstrapConfigUrl: 'https://example.com/bootstrap.json',
upgradeConfigUrl: 'https://example.com/upgrade.json',
),
);
}
bootstrapConfigAsset:本地默认启动配置文件bootstrapConfigUrl:可选,远程启动配置地址upgradeConfigUrl:可选,远程升级配置地址preferredOrientations:也可以直接在ShellEnvironment中传入,作为默认值
3. 远程启动配置格式
{
"data": {
"initialUrl": "https://example.com/login",
"preferredOrientations": ["portraitUp", "portraitDown"]
}
}
4. 远程升级配置格式
{
"data": {
"versionName": "1.0.1",
"version": 101,
"isForce": 0,
"remark": "1. 修复已知问题\n2. 优化启动体验",
"filePath": "https://example.com/app-release.apk",
"fileSize": 25000
}
}
启动时序
runShellApp(env)
→ 读取 bootstrapConfigAsset
→ 拉取 bootstrapConfigUrl(可选)
→ 合并 initialUrl / preferredOrientations
→ setupConfigUrl(upgradeConfigUrl)
→ SystemChrome.setPreferredOrientations(...)
→ runApp(ShellApp)
WebShellPage.initState()
→ 首帧后加载首页
→ 异步检查 upgradeConfigUrl
支持的 Bridge Action
pickImagecaptureImagepickFileopenExternalrequestPermissionsreloadPagegoBackcloseAppgetDeviceInfogetNetworkStatusshowToastsetStatusBar
代码结构
lib/
├── core_app.dart
├── web_shell_core.dart
└── src/
├── config/
│ ├── shell_environment.dart
│ └── url_resolver.dart
├── engine/
│ ├── compatibility.dart
│ └── recovery.dart
├── bridge/
│ ├── bridge_protocol.dart
│ ├── bridge_actions.dart
│ └── legacy_camera_compat.dart
├── services/
│ ├── config_service.dart
│ ├── media_service.dart
│ ├── permission_service.dart
│ ├── navigation_service.dart
│ └── upgrade_service.dart
├── ui/
│ ├── shell_app.dart
│ ├── shell_page.dart
│ ├── launch_overlay.dart
│ ├── error_overlay.dart
│ ├── progress_bar.dart
│ └── unsupported_platform_page.dart
└── testing/
└── test_hooks.dart
测试
cd packages/web_shell_core
flutter test
当前测试覆盖:
- 平台检测 · URL 解析 · 启动配置解析 · 方向配置
- Bridge 注入/响应/异常处理 · 媒体序列化 · 权限映射
- 导航路由 · 兼容性策略 · 错误恢复 · 组件渲染
平台约束
仅支持 Android。其他平台会展示兜底提示页。
Android 原生层
CoreShellActivity(Java)提供:
- WebView 数据目录隔离(避免多进程冲突)
- 旧进程自动终止
- WebView 信息查询(SDK 版本、WebView 包名/版本号)
- WebView 状态深度重置