Android Studio中WebView通过JavaScript访问项目外部文件问题
解决Android WebView中JS fetch访问非assets目录文件的问题
方案一:利用res/raw目录存储文件(适合不希望放assets的情况)
res/raw目录可存放任意类型文件,且不会被编译压缩,步骤如下:
- 放置文件:将目标文件放入
res/raw目录(无则新建),文件名仅支持小写字母、数字、下划线。 - Android端暴露文件读取接口:
创建供JS调用的接口类,通过addJavascriptInterface绑定到WebView:
在WebView初始化时绑定接口:public class RawFileReader { private Context context; public RawFileReader(Context ctx) { context = ctx; } @JavascriptInterface public String readRawFile(String fileName) { int resId = context.getResources().getIdentifier(fileName, "raw", context.getPackageName()); if (resId == 0) return null; try (InputStream is = context.getResources().openRawResource(resId); BufferedReader reader = new BufferedReader(new InputStreamReader(is))) { StringBuilder content = new StringBuilder(); String line; while ((line = reader.readLine()) != null) { content.append(line).append("\n"); } return content.toString(); } catch (IOException e) { e.printStackTrace(); return null; } } // 读取二进制文件(返回Base64字符串) @JavascriptInterface public String readRawBinaryFile(String fileName) { int resId = context.getResources().getIdentifier(fileName, "raw", context.getPackageName()); if (resId == 0) return null; try (InputStream is = context.getResources().openRawResource(resId)) { byte[] bytes = new byte[is.available()]; is.read(bytes); return Base64.encodeToString(bytes, Base64.DEFAULT); } catch (IOException e) { e.printStackTrace(); return null; } } }webView.addJavascriptInterface(new RawFileReader(this), "RawFileReader"); webView.getSettings().setJavaScriptEnabled(true); - JS中调用接口获取文件:
// 读取文本文件(如res/raw/data.txt) const textContent = await window.RawFileReader.readRawFile("data"); // 读取二进制文件并转成Blob const base64Data = await window.RawFileReader.readRawBinaryFile("image"); const blob = await fetch(`data:image/png;base64,${base64Data}`).then(res => res.blob());
方案二:使用assets子目录分类存储(最简单的方法)
assets目录支持所有文件类型,可通过创建子目录避免杂乱(如assets/files/、assets/media/),直接用file:///android_asset/路径访问:
// 访问assets/files/data.csv fetch('file:///android_asset/files/data.csv') .then(res => res.text()) .then(content => { // 处理文件内容 }); // 访问assets/media/image.png fetch('file:///android_asset/media/image.png') .then(res => res.blob()) .then(blob => { // 处理二进制文件 });
确保WebView开启文件访问权限:
webView.getSettings().setAllowFileAccess(true);
方案三:复制文件到内部存储后用file://路径访问
适合需要修改文件或频繁读取的场景:
- 首次启动复制文件:将APK内的文件(来自assets/raw)复制到应用内部存储:
private void copyToInternalStorage(String srcAssetPath, String destFileName) { File destFile = new File(getFilesDir(), destFileName); if (destFile.exists()) return; try (InputStream is = getAssets().open(srcAssetPath); OutputStream os = new FileOutputStream(destFile)) { byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) > 0) { os.write(buffer, 0, length); } } catch (IOException e) { e.printStackTrace(); } } - 传递路径给JS:
String fileUrl = "file://" + new File(getFilesDir(), "data.txt").getAbsolutePath(); webView.loadUrl("javascript:window.localFileUrl = '" + fileUrl + "';"); - JS中fetch访问:
fetch(window.localFileUrl) .then(res => res.text()) .then(content => { // 处理内容 });
内容的提问来源于stack exchange,提问作者Pat
相关产品推荐
相关产品推荐

