Android开发:如何在WebView中模拟本地服务器并加载assets站点资源?
WebView加载本地assets网站完整操作步骤
1. 完成WebView基础配置
在加载页面对应的Activity/Fragment中,对WebView做如下必要配置,否则会出现JS失效、资源无法加载的问题:
// 取到WebView实例后配置参数 val webSettings = webView.settings // 启用JavaScript支持,必开,大部分前端站都依赖JS webSettings.javaScriptEnabled = true // 允许WebView访问本地文件 webSettings.allowFileAccess = true // 允许JS跨域访问文件资源,解决本地绝对路径资源跨域报错问题 webSettings.allowUniversalAccessFromFileURLs = true // 启用DOM存储,支持localStorage、sessionStorage等前端存储能力 webSettings.domStorageEnabled = true // 强制所有页面跳转、资源请求都在当前WebView处理,不跳系统浏览器 webView.webViewClient = WebViewClient()
如果你的应用需要加载站外资源,需要在AndroidManifest.xml中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
完全本地运行的站点不需要添加该权限。
2. 加载assets目录下的入口文件
Android assets目录下的资源固定通过file:///android_asset/前缀访问,假设你网站的入口是根目录下的index.html,加载代码如下:
webView.loadUrl("file:///android_asset/index.html")
如果你的网站代码全部放在assets下的子目录(比如assets/web/),则加载地址改为file:///android_asset/web/index.html,路径必须和实际目录结构完全匹配
3. 拦截请求模拟服务端路径映射
如果你的网站使用了绝对路径引用资源(比如/css/main.css)、或者代码里写死了原服务端域名的请求,直接加载会出现资源找不到的问题,需要重写WebViewClient的shouldInterceptRequest方法做路径映射:
webView.webViewClient = object : WebViewClient() { override fun shouldInterceptRequest( view: WebView?, request: WebResourceRequest ): WebResourceResponse? { val requestUrl = request.url.toString() // 替换为你原服务端的域名,匹配所有原站请求 if (requestUrl.startsWith("https://your-original-domain.com/")) { // 提取域名后的路径部分,比如https://xxx.com/css/main.css 提取到 css/main.css val assetRelativePath = requestUrl.removePrefix("https://your-original-domain.com/") return try { // 打开assets下对应路径的资源 val inputStream = assets.open(assetRelativePath) // 根据资源后缀匹配MIME类型 val mimeType = when { assetRelativePath.endsWith(".html") -> "text/html" assetRelativePath.endsWith(".css") -> "text/css" assetRelativePath.endsWith(".js") -> "application/javascript" assetRelativePath.endsWith(".png") -> "image/png" assetRelativePath.endsWith(".jpg", ignoreCase = true) || assetRelativePath.endsWith(".jpeg", ignoreCase = true) -> "image/jpeg" assetRelativePath.endsWith(".svg") -> "image/svg+xml" else -> "application/octet-stream" } WebResourceResponse(mimeType, "UTF-8", inputStream) } catch (e: Exception) { // 找不到对应资源走系统默认逻辑 super.shouldInterceptRequest(view, request) } } // 非原站请求走默认逻辑 return super.shouldInterceptRequest(view, request) } }
如果有后端接口请求,也可以在该方法中拦截接口路径,直接返回本地预置的JSON数据,完全模拟服务端接口响应
4. 特殊场景兼容
- 单页应用(Vue/React等)路由:如果用的是history模式路由,需要在拦截方法中将所有路由请求都映射到入口index.html文件
- 服务端动态内容:如果原站有服务端渲染的动态内容,需要提前做静态化处理,或者在拦截请求时本地生成对应内容返回
- 跨域请求:如果原站有跨域调用第三方接口的逻辑,已经开了
allowUniversalAccessFromFileURLs的前提下不需要额外处理,如果还有问题可以在拦截方法中代理跨域请求
内容的提问来源于stack exchange,提问作者toto_tata
相关产品推荐
相关产品推荐

