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

求助:Codename One的BrowserComponent安卓端下载链接点击无响应

解决方案

1. 拦截下载请求并手动处理

Codename One的BrowserComponent默认不会自动处理网页中的下载链接,需要通过BrowserNavigationCallback拦截请求,手动实现下载逻辑:

BrowserComponent bc = new BrowserComponent();
bc.setBrowserNavigationCallback(new BrowserNavigationCallback() {
    @Override
    public boolean shouldNavigate(String url, String where, boolean isBack) {
        return true;
    }

    @Override
    public void downloadRequested(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
        // 提取文件名,优先从Content-Disposition头获取
        String fileName = extractFileName(contentDisposition, url);
        
        // 请求存储权限后启动下载
        Permission storagePerm = Permission.STORAGE;
        if (storagePerm.isGranted()) {
            startFileDownload(url, fileName);
        } else {
            storagePerm.request(() -> {
                if (storagePerm.isGranted()) {
                    startFileDownload(url, fileName);
                }
            });
        }
    }
});

// 从请求头或URL提取文件名的辅助方法
private String extractFileName(String contentDisposition, String url) {
    if (contentDisposition != null) {
        String[] parts = contentDisposition.split(";");
        for (String part : parts) {
            part = part.trim();
            if (part.startsWith("filename=")) {
                return part.substring(9).replace("\"", "");
            }
        }
    }
    // 从URL截取文件名
    return url.substring(url.lastIndexOf('/') + 1);
}

// 执行下载的核心方法
private void startFileDownload(String url, String fileName) {
    try {
        String savePath = FileSystemStorage.getInstance().getAppHomePath() + fileName;
        ConnectionRequest cr = new ConnectionRequest() {
            @Override
            protected void readResponse(InputStream input) throws IOException {
                OutputStream os = FileSystemStorage.getInstance().openOutputStream(savePath);
                Util.copy(input, os);
                os.close();
                // 下载完成后提示用户
                Display.getInstance().callSerially(() -> {
                    Dialog.show("下载完成", "文件已保存至: " + savePath, "确定", null);
                });
            }
        };
        cr.setUrl(url);
        cr.setPost(false);
        NetworkManager.getInstance().addToQueue(cr);
    } catch (IOException e) {
        e.printStackTrace();
        Dialog.show("错误", "下载失败: " + e.getMessage(), "确定", null);
    }
}

2. 添加并请求存储权限

安卓下载文件需要存储权限,需在项目配置中添加权限,并在运行时主动请求:

  • 在codenameone_settings.properties中添加安卓权限:
android.xpermissions=<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
  • 针对Android 10及以上版本,若需保存到公共存储(如下载文件夹),额外添加:
android.xpermissions=<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />

注意:MANAGE_EXTERNAL_STORAGE权限需要用户在系统设置中手动授权,无法通过常规弹窗请求。如果仅保存到应用私有目录(FileSystemStorage.getInstance().getAppHomePath()),Android 10+无需额外权限。

3. 适配Android 10+分区存储

如果需要将文件保存到公共下载文件夹,需改用MediaStore API适配分区存储,修改startFileDownload方法如下:

private void startFileDownload(String url, String fileName) {
    ConnectionRequest cr = new ConnectionRequest() {
        @Override
        protected void readResponse(InputStream input) throws IOException {
            if (Display.getInstance().getPlatformName().equals("Android")) {
                // Android 10+公共存储适配
                ContentValues values = new ContentValues();
                values.put(MediaStore.Downloads.DISPLAY_NAME, fileName);
                values.put(MediaStore.Downloads.MIME_TYPE, "application/octet-stream");
                values.put(MediaStore.Downloads.RELATIVE_PATH, Environment.DIRECTORY_DOWNLOADS);
                
                ContentResolver resolver = AndroidNativeUtil.getActivity().getContentResolver();
                Uri uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, values);
                
                if (uri != null) {
                    OutputStream os = resolver.openOutputStream(uri);
                    Util.copy(input, os);
                    os.close();
                    Display.getInstance().callSerially(() -> {
                        Dialog.show("下载完成", "文件已保存到系统下载文件夹", "确定", null);
                    });
                } else {
                    throw new IOException("无法创建下载文件");
                }
            } else {
                // 其他平台保存到应用私有目录
                String savePath = FileSystemStorage.getInstance().getAppHomePath() + fileName;
                OutputStream os = FileSystemStorage.getInstance().openOutputStream(savePath);
                Util.copy(input, os);
                os.close();
                Display.getInstance().callSerially(() -> {
                    Dialog.show("下载完成", "文件已保存至: " + savePath, "确定", null);
                });
            }
        }
    };
    cr.setUrl(url);
    cr.setPost(false);
    NetworkManager.getInstance().addToQueue(cr);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 09:30:55