Android Studio开发应用商店:WebView下载APK完成后打开及找不到文件问题咨询
问题修复方案
无法找到下载文件的原因
- 未动态申请存储权限,Android 6.0及以上系统默认拒绝存储写入权限,导致文件写入公共下载目录失败
- 代码中写死了文件名为示例文本,没有提取下载链接对应的真实APK文件名,即使下载成功也无法对应到实际文件
- 未适配高版本Android的存储权限规则
修复步骤
1. 补全AndroidManifest.xml配置
添加所需权限和FileProvider配置(Android 7.0+打开APK需要FileProvider适配):
<!-- 基础权限 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 存储权限,Android 13及以上无需申请 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <!-- 安装APK所需权限 --> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <application ...> <!-- 配置FileProvider --> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
在res/xml目录下新建file_paths.xml文件,内容如下:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="download" path="Download/" /> </paths>
2. 动态申请存储权限
在Activity的onCreate方法中先检查并申请权限:
// 权限申请请求码 private static final int PERMISSION_REQUEST_CODE = 1001; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 检查权限 if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST_CODE); } } // 后续WebView初始化逻辑 }
3. 修正下载逻辑,解析真实文件名
修改DownloadListener中的代码,从contentDisposition中提取真实文件名,避免写死:
// 存储下载ID,后续接收广播时用 private long downloadId; // WebView的DownloadListener实现 webview.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { // 解析文件名 String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // 传入解析得到的真实文件名 request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); // 保存下载ID downloadId = dm.enqueue(request); Toast.makeText(getApplicationContext(), "正在下载文件", Toast.LENGTH_LONG).show(); } });
4. 注册广播接收器,实现下载完成自动打开APK
在Activity中注册广播,监听下载完成事件:
private BroadcastReceiver downloadCompleteReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1); // 判断是不是我们发起的下载 if (id == downloadId) { DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); Uri downloadUri = dm.getUriForDownloadedFile(downloadId); if (downloadUri != null) { openApkFile(downloadUri); } } } }; // 打开APK文件的方法 private void openApkFile(Uri apkUri) { Intent installIntent = new Intent(Intent.ACTION_VIEW); installIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { // Android 7.0+使用FileProvider获取Uri String packageName = getPackageName(); Uri contentUri = FileProvider.getUriForFile(this, packageName + ".fileprovider", new File(apkUri.getPath())); installIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); installIntent.setDataAndType(contentUri, "application/vnd.android.package-archive"); } else { installIntent.setDataAndType(apkUri, "application/vnd.android.package-archive"); } startActivity(installIntent); } @Override protected void onResume() { super.onResume(); // 注册广播 IntentFilter filter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE); registerReceiver(downloadCompleteReceiver, filter); } @Override protected void onPause() { super.onPause(); // 注销广播 unregisterReceiver(downloadCompleteReceiver); }
内容的提问来源于stack exchange,提问作者TheNewRock1909
相关产品推荐
相关产品推荐

