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交互传递数据:- 修改网页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); } - 在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) {} });
- 修改网页JS逻辑,将Blob转为Base64并调用Codename One接口:
核心逻辑是:Codename One的BrowserComponent不会像普通浏览器那样自动处理下载弹窗和文件保存,必须通过事件监听或JS-Java交互的方式,手动完成下载请求、文件写入和后续提示流程。
内容的提问来源于stack exchange,提问作者Eric
相关产品推荐
相关产品推荐

