You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

无法获取Blob形式接收的图片,仅能读取PDF问题求助

解决Android WebView中Blob图片转存失败的问题

看起来你的代码在处理PDF Blob时能正常工作,但图片转存失败,核心问题出在Base64字符串的前缀处理和可能的解码参数上,我来一步步帮你解决:

核心问题分析

FileReader.readAsDataURL()返回的base64字符串是包含MIME类型前缀的,比如图片会是 data:image/png;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD/...,PDF则是data:application/pdf;base64,JVBERi0xLjMKJcfsj6IKNSAwIG9iago8PC9M...。而你当前直接用Base64.decode()解码带前缀的字符串,这会导致图片解码失败(PDF可能因为某些偶然情况能勉强解析,但其实也是不符合规范的)。

解决方案步骤

1. 移除Base64字符串的MIME前缀

writeToSDFile方法中,先剥离掉前缀部分,只保留纯Base64内容:

private void writeToSDFile(String string, String fileName) {
    // 剥离base64前缀(data:xxx;base64,)
    String base64Content = string;
    if (string.contains("base64,")) {
        base64Content = string.split("base64,")[1];
    }
    
    File root = android.os.Environment.getExternalStorageDirectory();
    File dir = new File(root.getAbsolutePath() + "/" + Environment.DIRECTORY_DOWNLOADS);
    dir.mkdirs();
    File file = new File(dir, fileName);
    
    try {
        // 使用NO_WRAP避免换行符导致的解码问题
        byte[] data = android.util.Base64.decode(base64Content, Base64.NO_WRAP);
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
        bos.write(data);
        bos.flush();
        bos.close();
        
        CommonUtilities._Log(TAG, "File Path " + file.getCanonicalPath());
        CommonUtilities.showFolderIntent(this, dir);
    } catch (Exception e) {
        CommonUtilities._Log(TAG, Log.getStackTraceString(e));
    }
}

2. 确保文件名包含正确的图片后缀

onDownloadStartcontentDisposition参数中解析出正确的文件名(包含后缀),避免保存的图片文件没有后缀导致系统无法识别:

web.setDownloadListener(new DownloadListener() {
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
        CommonUtilities._Log(TAG, "url = " + url + " ,, userAgent = " + userAgent + " ,,contentDisposition " + contentDisposition + " ,, mimetype = " + mimetype + " ,, length= " + contentLength);
        
        // 解析contentDisposition获取带后缀的文件名
        String fileName = "unknown_file";
        if (contentDisposition != null) {
            String[] parts = contentDisposition.split("filename=");
            if (parts.length > 1) {
                fileName = parts[1].replace("\"", "").trim();
            }
        }
        
        String s = "var request = new XMLHttpRequest();\n" +
                "request.open('GET', \"" + url + "\", true);\n" +
                "request.responseType = 'blob';\n" +
                "request.timeout = 30000;" +
                "request.onload = function() {\n" +
                " var reader = new FileReader();\n" +
                " reader.readAsDataURL(request.response); \n" +
                " reader.onloadend = function() {\n" +
                " base64data = reader.result; \n" +
                " Android.androidPay(base64data, \"" + fileName + "\")" + // 传递文件名
                " }\n" +
                "}\n" +
                "request.send();";
        
        WebLink.this.web.evaluateJavascript(s, new ValueCallback<String>() {
            @Override
            public void onReceiveValue(String value) {
                CommonUtilities._Log(TAG, "value " + value);
            }
        });
    }
});

3. 更新Javascript接口方法

修改你的androidPay方法,接收base64数据和文件名两个参数:

@JavascriptInterface
public void androidPay(String base64Data, String fileName) {
    writeToSDFile(base64Data, fileName);
}

额外检查点

  • 权限:确保你的App在Android 10及以上版本中,对Downloads目录的写入权限是正常的(公共Downloads目录不需要额外的WRITE_EXTERNAL_STORAGE权限,但如果是自定义目录则需要)。
  • 超时设置:如果是大尺寸图片,可以适当调整XMLHttpRequest的超时时间(比如改为60000毫秒)。
  • 调试:在Javascript中打开console.log(base64data),检查图片的base64字符串是否完整,有没有截断情况。

按照这些步骤修改后,应该就能正常转存图片Blob了。

内容的提问来源于stack exchange,提问作者Rahul Khurana

火山引擎 最新活动