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

使用DownloadManager下载APK时,如何检测无效的APK下载URL?

解决DownloadManager无效APK URL检测问题

这个场景我之前也踩过坑——DownloadManager在遇到无效URL导致下载失败时,确实不会触发ACTION_DOWNLOAD_COMPLETE广播,因为下载还没走到“完成”流程就中断了。咱们可以从提前验证和事后监听两个方向来解决:


1. 提前验证URL有效性(推荐)

在启动下载前先做个预检,避免无效请求,效率更高。可以发起HEAD请求,检查目标URL的响应状态和内容类型:

private boolean isValidApkDownloadUrl(String url) {
    HttpURLConnection connection = null;
    try {
        URL apkUrl = new URL(url);
        connection = (HttpURLConnection) apkUrl.openConnection();
        connection.setRequestMethod("HEAD"); // 只请求头,不下载内容
        connection.setConnectTimeout(5000);
        connection.connect();

        // 验证状态码为200,且Content-Type是APK格式
        int responseCode = connection.getResponseCode();
        String contentType = connection.getContentType();
        return responseCode == HttpURLConnection.HTTP_OK 
                && contentType != null 
                && contentType.equals("application/vnd.android.package-archive");
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    } finally {
        if (connection != null) {
            connection.disconnect();
        }
    }
}

使用时先调用这个方法,返回true再启动DownloadManager:

if (isValidApkDownloadUrl(yourApkUrl)) {
    // 启动DownloadManager下载逻辑
} else {
    // 提示用户URL无效
}

2. 下载后监听失败状态

如果必须在下载启动后检测失败,可以通过ContentObserver监听DownloadManager的状态变化,替代单一的完成广播:

第一步:实现ContentObserver

private ContentObserver downloadStatusObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        // 通过下载ID查询状态
        Cursor cursor = getContentResolver().query(
                DownloadManager.COLUMN_STATUS,
                null,
                DownloadManager.COLUMN_ID + "=?",
                new String[]{String.valueOf(yourDownloadId)}, // yourDownloadId是启动下载时返回的ID
                null
        );

        if (cursor != null && cursor.moveToFirst()) {
            int status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (status) {
                case DownloadManager.STATUS_FAILED:
                    // 下载失败,处理错误逻辑
                    int errorReason = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_REASON));
                    // 常见错误码:ERROR_FILE_NOT_FOUND(文件不存在,对应无效URL)、ERROR_UNKNOWN等
                    Log.e("DownloadError", "失败原因码:" + errorReason);
                    break;
                case DownloadManager.STATUS_SUCCESSFUL:
                    // 下载成功,执行你原有的逻辑
                    if(command.equals(Protocol.APPS_UPDATE_ONROUTE_APP)) { 
                        IntentFilter screenStateFilter = new IntentFilter(); 
                        my_context.registerReceiver(new MyBroadCastReciever(), screenStateFilter); 
                        CommandLine.execCommandLine("monkey -p com.fagica.flosko -c android.intent.category.LAUNCHER 1"); 
                    }
                    break;
            }
        }
        if (cursor != null) {
            cursor.close();
        }
    }
};

第二步:注册与注销Observer

启动下载后注册:

getContentResolver().registerContentObserver(
        Uri.parse("content://downloads/my_downloads/" + yourDownloadId),
        true,
        downloadStatusObserver
);

记得在页面销毁或不需要监听时注销,避免内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    getContentResolver().unregisterContentObserver(downloadStatusObserver);
}

补充:DownloadManager常见失败原因码

当下载失败时,COLUMN_REASON会返回对应错误码,比如:

  • DownloadManager.ERROR_FILE_NOT_FOUND:目标文件不存在(最可能对应无效URL的情况)
  • DownloadManager.ERROR_UNKNOWN:未知错误
  • DownloadManager.ERROR_INSUFFICIENT_SPACE:存储空间不足

可以根据这些码给用户更精准的提示。

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

相关产品推荐
方舟 Agent Plan

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

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