doc:整理文档
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
# 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 是最高优先级怀疑点)
|
||||
|
||||
Reference in New Issue
Block a user