You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android WebView加载Liferay Portlet时PDF下载无响应问题求助

嘿,我之前也在Android WebView里处理过Liferay Portlet的PDF下载问题,刚好踩过类似的坑,给你几个实用的解决方案:

核心问题:WebView默认不处理下载请求

WebView本身不会自动触发文件下载操作,哪怕服务器正确返回了PDF响应,也需要我们手动拦截并处理下载逻辑。

方案一:给WebView设置DownloadListener(最常用)

这是处理WebView下载的标准方式,通过拦截下载请求,调用系统的DownloadManager来完成文件保存:

  • 1. 初始化WebView时添加下载监听
    在你的WebView初始化代码里加入这段逻辑:

    webView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
            // 构建下载请求
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            request.setMimeType(mimeType);
            
            // 解析服务器返回的文件名(从Content-Disposition头中提取)
            String filename = URLUtil.guessFileName(url, contentDisposition, mimeType);
            
            // 关键:传递Cookie,因为Liferay Portlet需要用户会话验证
            request.addRequestHeader("Cookie", CookieManager.getInstance().getCookie(url));
            
            // 设置下载提示和通知
            request.setDescription("正在下载PDF文件");
            request.setTitle(filename);
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            
            // 指定下载到系统下载目录
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
            
            // 发起下载
            DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            if (downloadManager != null) {
                downloadManager.enqueue(request);
                Toast.makeText(getApplicationContext(), "开始下载", Toast.LENGTH_SHORT).show();
            }
        }
    });
    

    这里一定要注意传递Cookie,否则Liferay服务器会因为没有会话信息拒绝你的下载请求,毕竟Portlet通常需要用户登录才能访问。

  • 2. 检查Liferay的响应头格式
    你当前的响应头设置基本没问题,但建议给文件名加上双引号,避免特殊字符导致解析失败:

    res.addProperty(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + cod + ".pdf\"");
    

    另外确保Content-Length也正确返回,这样系统能显示准确的下载进度。

  • 3. 处理Android权限问题
    如果你的应用目标是Android 6.0(API 23)及以上,需要动态申请WRITE_EXTERNAL_STORAGE权限(如果下载到外部存储的话),否则会保存失败。可以在触发下载前先检查权限:

    if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1001);
    } else {
        // 这里执行下载逻辑,或者在权限申请通过后重新触发
    }
    

    记得在onRequestPermissionsResult回调中处理权限通过后的下载操作。

方案二:处理AJAX发起的下载请求

如果你的Portlet是通过AJAX请求生成PDF的(比如前端JS调用ResourceURL),WebView的DownloadListener可能拦截不到请求。这时候可以:

  • 在Liferay端生成PDF后,返回一个重定向到PDF文件的URL,让WebView自动触发下载;
  • 或者在前端JS中,当收到PDF的Blob数据时,创建一个隐藏的<a>标签来触发下载:
    function handlePdfDownload(blobData, fileName) {
        const downloadUrl = window.URL.createObjectURL(blobData);
        const link = document.createElement('a');
        link.href = downloadUrl;
        link.download = fileName;
        document.body.appendChild(link);
        link.click();
        window.URL.revokeObjectURL(downloadUrl);
        document.body.removeChild(link);
    }
    
    这种方式需要前端和Liferay后端配合,确保能正确传递Blob数据和文件名。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:55:52