本文记录一种调试场景:当前已经通过 Chrome DevTools 连接到 Android App 内的 WebView,希望让这个 WebView 直接加载手机本地的 file:// 离线页面。
示例目标地址:
text
file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>
1. 为什么 Console 里直接跳转会失败
在 Chrome DevTools Console 里执行:
js
window.location.href = 'file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>'
或:
js
location.replace('file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>')
可能会报:
text
Not allowed to load local resource: file://...
原因是:当前页面脚本从 http:// 或 https:// 页面主动跳转到 file:// 本地资源时,会被 Chromium/WebView 的安全策略拦截。
这不是 URL 拼写问题,而是页面上下文发起 file:// 导航被禁止。
2. 不要把 file:// 粘到地址栏
如果把下面这种地址直接粘到 Chrome 或 DevTools 的地址栏:
text
file:///storage/emulated/0/Android/data/...
Chrome 有时会把它当成普通搜索或网页地址处理,出现自动拼接 http:// 的情况。
调试 WebView 时,不建议通过地址栏输入这种手机端本地路径。
3. 用 Protocol Monitor 发送 Page.navigate
更合适的方式是通过 Chrome DevTools Protocol 让调试器发起导航,而不是让页面 JS 发起导航。
打开 Protocol Monitor
- 打开连接 WebView 的 DevTools 页面。
- 按
Cmd + Shift + P,Windows/Linux 使用Ctrl + Shift + P。 - 搜索:
text
Protocol Monitor
- 选择:
text
Show Protocol Monitor
如果搜不到:
- 打开 DevTools 右上角齿轮
Settings。 - 进入
Experiments。 - 勾选
Protocol Monitor。 - 关闭并重新打开 DevTools。
- 再通过命令面板打开
Show Protocol Monitor。
正确发送方式
在 Protocol Monitor 里,方法名填:
text
Page.navigate
参数填:
json
{
"url": "file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>"
}
注意:不要把下面这种函数调用整体填进去:
js
Page.navigate({"url":"file:///..."})
否则会报:
json
{
"code": -32601,
"message": "'Page.navigate({...})' wasn't found"
}
这个报错表示 DevTools 把整段 Page.navigate({...}) 当成了 method 名,而不是调用了 Page.navigate 方法。
如果 Protocol Monitor 只有单行 JSON-RPC 输入,可以尝试:
json
{"id":1,"method":"Page.navigate","params":{"url":"file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>"}}
4. URL 参数里的 https 要编码
如果原始参数里有:
text
cdn=https://cdn.example.com
建议编码成:
text
cdn=https%3A%2F%2Fcdn.example.com
否则嵌套 URL 容易在解析 query 参数时出问题。
5. 如果 Page.navigate 也失败
如果通过 Protocol Monitor 发送 Page.navigate 后仍然失败,例如出现:
text
Not allowed to load local resource
或:
text
net::ERR_ACCESS_DENIED
或页面空白,那通常说明 WebView 本身没有允许访问本地文件。
这时需要从 App 代码侧加载,而不是从 DevTools 侧强行跳转。
Kotlin 示例:
kotlin
webView.settings.allowFileAccess = true
webView.settings.allowFileAccessFromFileURLs = true
webView.settings.allowUniversalAccessFromFileURLs = true
webView.loadUrl(
"file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>"
)
Java 示例:
java
webView.getSettings().setAllowFileAccess(true);
webView.getSettings().setAllowFileAccessFromFileURLs(true);
webView.getSettings().setAllowUniversalAccessFromFileURLs(true);
webView.loadUrl(
"file:///storage/emulated/0/Android/data/com.example.app/index.html?file=<path_id>/<resource_id>"
);
6. 判断问题属于哪一类
| 现象 | 可能原因 | 处理方式 |
|---|---|---|
地址栏自动拼 http:// |
地址栏把输入当普通网页地址处理 | 不用地址栏,改用 DevTools Protocol |
Console 报 Not allowed to load local resource |
页面 JS 不能从 http/https 跳到 file | 不用 window.location.href,改用 Page.navigate 或 App 侧 loadUrl |
Protocol Monitor 报 -32601 |
method 填错,把函数调用当方法名 | method 填 Page.navigate,params 单独填 JSON |
Page.navigate 后仍报 ERR_ACCESS_DENIED |
WebView 文件访问权限不允许 | App 侧开启 file access 并调用 webView.loadUrl |
| 页面打开但资源加载失败 | file 页面内跨域访问 http/https 或其他 file 资源受限 | 检查 allowFileAccessFromFileURLs 和 allowUniversalAccessFromFileURLs |
7. 推荐调试顺序
- 先确认文件真实存在于手机路径:
bash
adb shell ls -l /storage/emulated/0/Android/data/com.example.app/index.html
-
用 Chrome DevTools 连接目标 WebView。
-
打开
Protocol Monitor。 -
发送
Page.navigate,不要在 Console 里执行window.location.href。 -
如果仍然被拦截,改为 App 代码侧
webView.loadUrl(fileUrl)。 -
如果页面能打开但内容异常,再检查 WebView 的 file access 相关设置和页面内资源路径。