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

Codename One中BrowserComponent的PDF下载失败,是否需额外配置?

解决Codename One中BrowserComponent的PDF下载问题

Codename One的BrowserComponent默认不会自动处理网页内的下载请求,需要通过配置监听和自定义逻辑来实现,具体方案如下:

  • 添加下载事件监听
    给BrowserComponent注册downloadStarted事件,手动接管下载流程,用Codename One的网络API完成文件下载与本地保存:

    browser.addWebEventListener("downloadStarted", evt -> {
        String downloadUrl = (String) evt.getSource();
        ConnectionRequest downloadReq = new ConnectionRequest() {
            @Override
            protected void readResponse(InputStream input) throws IOException {
                FileSystemStorage fs = FileSystemStorage.getInstance();
                String savePath = fs.getAppHomePath() + "generated.pdf";
                // 将下载流写入本地文件
                try (OutputStream output = fs.openOutputStream(savePath)) {
                    Util.copy(input, output);
                }
                // 下载完成后提示用户
                Display.getInstance().callSerially(() -> {
                    if (Display.getInstance().isNativeBrowserSupported()) {
                        Display.getInstance().execute(savePath);
                    } else {
                        Dialog.show("提示", "PDF已保存至:" + savePath, "确定", null);
                    }
                });
            }
        };
        downloadReq.setUrl(downloadUrl);
        downloadReq.setPost(false);
        NetworkManager.getInstance().addToQueue(downloadReq);
    });
    
  • 配置BrowserComponent权限
    如果网页通过Blob URL或本地文件访问触发下载,需要开启相关权限:

    browser.setProperty("allowFileAccess", true);
    browser.setProperty("allowFileAccessFromFileURLs", true);
    // Android平台额外启用下载监听支持
    if (Display.getInstance().getPlatformName().equals("Android")) {
        browser.setProperty("android:downloadListenerEnabled", true);
    }
    
  • 处理Blob URL类下载(如pdfmake场景)
    若网页用Blob生成PDF并触发下载,BrowserComponent无法直接识别Blob URL,需要通过JS与Java交互传递数据:

    1. 修改网页JS逻辑,将Blob转为Base64并调用Codename One接口:
      function handlePdfBlob(blob) {
          const reader = new FileReader();
          reader.onload = function(e) {
              const base64Str = e.target.result.split(',')[1];
              // 通过自定义协议调用Java代码
              document.location = 'codenameone://savePdf?data=' + encodeURIComponent(base64Str);
          };
          reader.readAsDataURL(blob);
      }
      
    2. 在Codename One中监听自定义协议并处理:
      browser.addWebEventListener("onLoad", e -> {
          browser.executeJavascript("window.codenameone = {callNative: function(name, data) { document.location = 'codenameone://' + name + '?data=' + encodeURIComponent(data); }};");
      });
      
      Display.getInstance().addNativeListener(new NativeWebBrowserListener() {
          @Override
          public boolean shouldNavigate(String url) {
              if (url.startsWith("codenameone://savePdf?")) {
                  try {
                      String base64Data = URLDecoder.decode(url.substring("codenameone://savePdf?data=".length()), "UTF-8");
                      byte[] pdfBytes = Base64.decode(base64Data.getBytes());
                      FileSystemStorage fs = FileSystemStorage.getInstance();
                      String savePath = fs.getAppHomePath() + "generated.pdf";
                      try (OutputStream output = fs.openOutputStream(savePath)) {
                          output.write(pdfBytes);
                      }
                      // 提示用户
                      Display.getInstance().callSerially(() -> {
                          if (Display.getInstance().isNativeBrowserSupported()) {
                              Display.getInstance().execute(savePath);
                          } else {
                              Dialog.show("提示", "PDF已保存", "确定", null);
                          }
                      });
                  } catch (Exception ex) {
                      Log.e(ex);
                  }
                  return false; // 阻止浏览器默认导航
              }
              return true;
          }
      
          // 空实现其他接口方法
          @Override public void pageStarted(String url) {}
          @Override public void pageFinished(String url) {}
          @Override public void downloadStarted(String url) {}
          @Override public void titleChanged(String title) {}
      });
      

核心逻辑是:Codename One的BrowserComponent不会像普通浏览器那样自动处理下载弹窗和文件保存,必须通过事件监听或JS-Java交互的方式,手动完成下载请求、文件写入和后续提示流程。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 10:59:54