使用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
相关产品推荐
相关产品推荐

