# web_android_shell

Android 平板专用 H5 壳应用 Monorepo，面向多品牌白标场景。

## 当前品牌

- `apps/aixue`：爱学蝶变
- `apps/test`：测试壳工程
- `apps/yunxiao`：云校嗨学

## 目录结构

```text
web_android_shell/
├── apps/                         # 品牌应用（每个品牌一个 Flutter App）
│   ├── aixue/
│   ├── test/
│   └── yunxiao/
├── flavors/                      # 品牌配置 + 品牌资源源文件
│   ├── aixue.yaml
│   ├── test.yaml
│   ├── yunxiao.yaml
│   ├── aixue/
│   ├── test/
│   └── yunxiao/
├── packages/
│   ├── web_shell_core/           # 核心壳能力库
│   └── web_android_shell/        # 历史包，当前不作为主入口维护
├── tool/
│   ├── generate_app.dart         # 按 flavor 一键生成品牌 App
│   └── flutter_run_fresh.ps1     # Windows 调试脚本
└── doc/
    └── architecture.md           # 架构说明
```

## 核心思路

- 应用启动优先读取本地默认启动配置 `assets/config/bootstrap.json`
- 如配置了 `bootstrap_config_url`，会继续拉取远程启动配置，并使用缓存兜底
- 如配置了 `upgrade_config_url`，首帧后异步检查版本更新
- 启动配置与升级配置已拆分，不再共用同一个 JSON
- 屏幕方向支持通过启动配置中的 `preferredOrientations` 控制

## 快速开始

### 运行已有品牌

建议优先使用仓库内 `.fvm` 的 Flutter / Dart，避免全局版本不一致。

Windows PowerShell：

```powershell
cd apps/aixue
..\..\.fvm\flutter_sdk\bin\flutter.bat run
```

macOS / zsh：

```bash
cd apps/aixue
../../.fvm/flutter_sdk/bin/flutter run
```

也可以替换为：

```powershell
cd apps/test
..\..\.fvm\flutter_sdk\bin\flutter.bat run
```

```bash
cd apps/yunxiao
../../.fvm/flutter_sdk/bin/flutter run
```

### 生成或重建品牌应用

请在仓库根目录执行。

Windows PowerShell：

```powershell
.\.fvm\flutter_sdk\bin\dart.bat run tool\generate_app.dart aixue
.\.fvm\flutter_sdk\bin\dart.bat run tool\generate_app.dart test
.\.fvm\flutter_sdk\bin\dart.bat run tool\generate_app.dart yunxiao
```

macOS / zsh：

```bash
./.fvm/flutter_sdk/bin/dart run tool/generate_app.dart aixue
./.fvm/flutter_sdk/bin/dart run tool/generate_app.dart test
./.fvm/flutter_sdk/bin/dart run tool/generate_app.dart yunxiao
```

注意：生成脚本会删除并重建已有的 `apps/<品牌名>/` 目录。

生成脚本会自动完成：

- 创建 Flutter Android 应用到 `apps/<品牌名>/`
- 添加 `web_shell_core` 依赖
- 修正 Android `namespace` 与 `applicationId`
- 生成 `MainActivity` 并继承 `CoreShellActivity`
- 生成品牌入口 `lib/main.dart`
- 生成本地默认启动配置 `assets/config/bootstrap.json`
- 复制品牌资源到 `assets/branding/`
- 注册 `assets/branding/` 与 `assets/config/`
- 生成 launcher icon 与 splash
- 注入 Android 签名配置

## Flavor 配置格式

每个品牌在 `flavors/<品牌名>.yaml` 中维护配置。

```yaml
app_name: "全学通"
application_id: "com.yuanxuan.quanxue"
app_key: "quanxue_prod"
default_url: "https://example.com/login"
bootstrap_config_url: "https://example.com/bootstrap.json"
upgrade_config_url: "https://example.com/upgrade.json"
preferred_orientations:
  - "portraitUp"
  - "portraitDown"
theme:
  accent_color: "0xFF3ED37B"
  bg_color: "0xFFFFFFFF"
  text_color: "0xFF1F2937"
  muted_text_color: "0xFF6B7280"
branding:
  icon: "icon.png"
  icon_background: "#FFFFFF"
  icon_foreground: "icon_foreground.png"
  splash: "splash.png"
  splash_color: "#FFFFFF"
```

### 字段说明

- `default_url`：生成到本地默认启动配置 `assets/config/bootstrap.json`
- `bootstrap_config_url`：可选，远程启动配置地址；为空时不会写入 `main.dart`
- `upgrade_config_url`：可选，远程升级配置地址；为空时不会写入 `main.dart`
- `preferred_orientations`：首屏方向配置，支持：
  - `portraitUp`
  - `portraitDown`
  - `landscapeLeft`
  - `landscapeRight`

## 生成后的入口形态

生成器会把品牌入口写成统一模板：

```dart
runShellApp(
  ShellEnvironment(
    appName: '品牌名',
    appKey: 'brand_key',
    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',
  ),
);
```

其中远程地址为空时，对应字段不会写入生成结果。

## 本地默认启动配置格式

生成器会自动生成 `assets/config/bootstrap.json`：

```json
{
  "initialUrl": "https://example.com/login",
  "preferredOrientations": [
    "portraitUp",
    "portraitDown"
  ]
}
```

## 品牌资源规格

| 资源 | 文件名 | 最小尺寸 | 格式 | 说明 |
|---|---|---|---|---|
| 应用图标 | `icon.png` | 1024×1024 | PNG | 用于生成各尺寸 launcher icon |
| 自适应图标前景 | `icon_foreground.png` | 1024×1024 | PNG | 建议透明背景，主体留安全区 |
| 启动页图片 | `splash.png` | 1152×1152 | PNG | 用于生成 Android 12+ 与旧版启动页 |

品牌资源源文件放在 `flavors/<品牌名>/` 下，生成后会复制到 `apps/<品牌名>/assets/branding/`。

## 调试说明

部分教育平板设备在 `flutter run` 中断后，旧进程可能残留并影响 WebView 启动。

推荐做法：

- 调试结束时在 `flutter run` 控制台按 `q` 退出
- 或使用：

```powershell
.\tool\flutter_run_fresh.ps1
.\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` |
| 配置缓存 | `shared_preferences` |
| 网络与状态 | `http` · `connectivity_plus` |
| 原生层 | Java `CoreShellActivity` + Kotlin plugin |

## 平台约束

仅支持 Android 平板。
