# Android 端显示 “Not Found” 排查计划（Hua.Todo.Maui）

## 目标

- 找出 Android 模拟器里只显示 `Not Found` 的根因（是 Web 资源缺失、内嵌 Web Server 路由/解析问题，还是 WebView 加载了错误地址）
- 给出可验证的修复方案，并确保修复后能在 Android 上正常加载前端页面

## 背景（当前实现快速定位）

- Android 使用自建 TCP HTTP Server，静态资源从 APK 的 `Assets/wwwroot/*` 读取：[MobileEmbeddedWebServerService](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Platforms/Android/MobileEmbeddedWebServerService.cs)
- WebView 默认加载内嵌服务器地址（`IsUsingStatic=true` 时）：[MainPage.xaml.cs](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Views/MainPage.xaml.cs)
- Android 端静态文件找不到时返回纯文本 `Not Found`：[HandleStaticAsync](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Platforms/Android/MobileEmbeddedWebServerService.cs#L214-L255)

## 排查顺序（从“最可能 & 最省时间”到“深入原因”）

### 1) 确认 WebView 实际加载的 URL

- 在 Android Debug 输出里确认 WebView Source（期望是 `http://localhost:5057` 或 `http://localhost:5057/`）
- 如果不是内嵌地址，检查 `appsettings.json` 的 `WebServer.IsUsingStatic` 与 `ForEndUrl` 配置：[appsettings.json](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/appsettings.json)

判定：
- 若加载的是内嵌地址 → 继续第 2 步
- 若加载的是外部地址（ForEndUrl）→ 重点查 ForEndUrl 对应服务是否启动/路由是否正确

### 2) 确认前端 dist 是否存在且可用于打包

- 检查 `src/Hua.Todo.Web/dist/index.html` 是否存在
- 如果不存在：在 `src/Hua.Todo.Web` 下执行 `npm ci` + `npm run build`，确保产物生成

判定：
- dist 不存在/为空 → “Not Found”高概率来自 Android 静态资源根本没被构建或没被打进 APK

### 3) 确认 Android APK 内是否真的包含 `Assets/wwwroot/index.html`

- 重点验证打包结果是否存在：
  - `assets/wwwroot/index.html`
  - `assets/wwwroot/assets/*`（至少有 js/css）
- 项目里通过 MSBuild 目标把 `Hua.Todo.Web/dist` 映射为 AndroidAsset（Link 到 `wwwroot/...`）：[Hua.Todo.Maui.csproj](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Hua.Todo.Maui.csproj#L150-L175)

判定：
- APK 内没有 `wwwroot/index.html` → 修复构建/打包流程（第 6 步会给方案）
- APK 内有 `wwwroot/index.html` → 继续第 4 步

### 4) 记录 Android 内嵌服务器的“收到的请求 Path”与“找不到的 assetPath”

目的：判断是否是“请求行解析不兼容”或“路径格式异常”导致找不到资源。

- 在 `ReadRequestAsync`、`HandleStaticAsync` 临时输出：
  - requestLine / target / path
  - 计算出的 assetPath
  - TryOpenAsset 失败的 assetPath

高频根因候选：
- WebView 请求行使用 absolute-form（例如 `GET http://localhost:5057/ HTTP/1.1`），当前解析逻辑会把整个 URL 当作 path，最终拼成无效 `wwwroothttp://...`，导致 404

### 5) 排除 WebView/网络限制类问题（只在必要时做）

- 如果看到的不是纯文本 `Not Found`，而是加载错误/空白：
  - 检查 Android 明文 HTTP（`http://localhost`）是否被允许
  - 检查 `network_security_config.xml` 与 Manifest 配置：[network_security_config.xml](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Platforms/Android/Resources/xml/network_security_config.xml)、[AndroidManifest.xml](file:///d:/Proj/Hua.Todo/src/Hua.Todo.Maui/Platforms/Android/AndroidManifest.xml)

### 6) 修复与验证（根据前面判定选择）

#### A. 资源缺失/未打包

- 让构建流程更“硬性”：
  - 若 dist 不存在则强制构建，或在 Debug 也保证 `AndroidAsset` 包含 dist
  - 可选：把 dist 复制进 `Hua.Todo.Maui/wwwroot` 再用 `<Content Include="wwwroot\**" />`/`<MauiAsset />` 统一打包（减少条件目标的不确定性）

验证：
- APK 内能看到 `assets/wwwroot/index.html`，启动后不再返回 `Not Found`

#### B. 请求路径解析不兼容（absolute-form 等）

- 改进 `ReadRequestAsync`：当 target 是 `http(s)://...` 时解析出其中的 Path + Query，再走现有逻辑

验证：
- 记录到的 path 变为 `/` 或 `/index.html`，能成功打开 `wwwroot/index.html`

#### C. 资源引用路径问题（js/css 请求 404）

- 检查 dist 中 `index.html` 对 `assets/*` 的引用路径是否与 AndroidAsset 的 Link 一致
- 若 Vite 输出含子目录（例如 `assets/chunks/...`），需要在 csproj 里用 `dist\**\*` 并保留 `%(RecursiveDir)`，避免扁平化导致引用断裂

验证：
- WebView 网络请求里 js/css 全部 200，页面正常渲染

## 本次排查的“最短闭环”

- 先确认 dist 是否存在 + APK 是否包含 `assets/wwwroot/index.html`
- 若存在仍 Not Found，再用日志确认 requestLine/target/path 是否被解析成异常值（absolute-form 是最高优先级怀疑点）

