# Android 端显示 “Not Found” 排查计划(TodoList.Maui) ## 目标 - 找出 Android 模拟器里只显示 `Not Found` 的根因(是 Web 资源缺失、内嵌 Web Server 路由/解析问题,还是 WebView 加载了错误地址) - 给出可验证的修复方案,并确保修复后能在 Android 上正常加载前端页面 ## 背景(当前实现快速定位) - Android 使用自建 TCP HTTP Server,静态资源从 APK 的 `Assets/wwwroot/*` 读取:[MobileEmbeddedWebServerService](file:///d:/Proj/TodoList/src/TodoList.Maui/Platforms/Android/MobileEmbeddedWebServerService.cs) - WebView 默认加载内嵌服务器地址(`IsUsingStatic=true` 时):[MainPage.xaml.cs](file:///d:/Proj/TodoList/src/TodoList.Maui/Views/MainPage.xaml.cs) - Android 端静态文件找不到时返回纯文本 `Not Found`:[HandleStaticAsync](file:///d:/Proj/TodoList/src/TodoList.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/TodoList/src/TodoList.Maui/appsettings.json) 判定: - 若加载的是内嵌地址 → 继续第 2 步 - 若加载的是外部地址(ForEndUrl)→ 重点查 ForEndUrl 对应服务是否启动/路由是否正确 ### 2) 确认前端 dist 是否存在且可用于打包 - 检查 `src/TodoList.Web/dist/index.html` 是否存在 - 如果不存在:在 `src/TodoList.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 目标把 `TodoList.Web/dist` 映射为 AndroidAsset(Link 到 `wwwroot/...`):[TodoList.Maui.csproj](file:///d:/Proj/TodoList/src/TodoList.Maui/TodoList.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/TodoList/src/TodoList.Maui/Platforms/Android/Resources/xml/network_security_config.xml)、[AndroidManifest.xml](file:///d:/Proj/TodoList/src/TodoList.Maui/Platforms/Android/AndroidManifest.xml) ### 6) 修复与验证(根据前面判定选择) #### A. 资源缺失/未打包 - 让构建流程更“硬性”: - 若 dist 不存在则强制构建,或在 Debug 也保证 `AndroidAsset` 包含 dist - 可选:把 dist 复制进 `TodoList.Maui/wwwroot` 再用 ``/`` 统一打包(减少条件目标的不确定性) 验证: - 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 是最高优先级怀疑点)