Android 通过 WebView 请求下载 APK

本文介绍如何使用WebView的setDownloadListener方法实现点击H5按钮下载并安装APK的功能,包括创建下载任务、监听下载状态及安装流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

很少去研究 Webview 的具体使用,之前在项目中遇到,通过点击 H5 中的按钮来进行下载 Apk 。刚收到这个需求想到的第一个想法就是调用 JS 来实现。之后实际运用前去看了看 WebView 的 API 发现了  WebView 下有一个 setDownloadListener 方法。它主要就是负责当你需要在使用 webview 时下载资源用的。具体的下载 APK 方法:

一个 Downloader 下载工具:

import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import android.widget.Toast;

import java.io.File;

/**
 * Created by 49829 on 2017/8/28.
 */

public class Downloader {
    //下载器
    private DownloadManager downloadManager;
    //上下文
    private Context mContext;
    //下载的ID
    private long downloadId;

    public Downloader(Context context) {
        this.mContext = context;
    }

    //下载apk
    public void downloadAPK(String url, String name) {

        //创建下载任务
        DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
        //移动网络情况下是否允许漫游
        request.setAllowedOverRoaming(false);

        //在通知栏中显示,默认就是显示的
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE);
        request.setTitle("雪豹外汇");
        request.setDescription("正在下载...");
        request.setVisibleInDownloadsUi(true);

        //设置下载的路径
        request.setDestinationInExternalPublicDir(Environment.getExternalStorageDirectory().getAbsolutePath(), name);

        //获取DownloadManager
        downloadManager = (DownloadManager) mContext.getSystemService(Context.DOWNLOAD_SERVICE);
        //将下载请求加入下载队列,加入下载队列后会给该任务返回一个long型的id,通过该id可以取消任务,重启任务、获取下载的文件等等
        downloadId = downloadManager.enqueue(request);

        //注册广播接收者,监听下载状态
        mContext.registerReceiver(receiver,
                new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    //广播监听下载的各个状态
    private BroadcastReceiver receiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            checkStatus();
        }
    };


    //检查下载状态
    private void checkStatus() {
        DownloadManager.Query query = new DownloadManager.Query();
        //通过下载的id查找
        query.setFilterById(downloadId);
        Cursor c = downloadManager.query(query);
        if (c.moveToFirst()) {
            int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
            switch (status) {
                //下载暂停
                case DownloadManager.STATUS_PAUSED:
                    break;
                //下载延迟
                case DownloadManager.STATUS_PENDING:
                    break;
                //正在下载
                case DownloadManager.STATUS_RUNNING:
                    break;
                //下载完成
                case DownloadManager.STATUS_SUCCESSFUL:
                    //下载完成安装APK
                    installAPK();
                    break;
                //下载失败
                case DownloadManager.STATUS_FAILED:
                    Toast.makeText(mContext, "下载失败", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    //下载到本地后执行安装
    private void installAPK() {

        Intent intent = new Intent();
        File apkFile = queryDownloadedApk();
        Uri uri;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {//7.0启动姿势<pre name="code" class="html">    //com.xxx.xxx.fileprovider为上述manifest中provider所配置相同;apkFile为问题1中的外部存储apk文件</pre>
            uri = FileProvider.getUriForFile(mContext, "com.zz.fileprovider", apkFile);
            intent.setAction(Intent.ACTION_INSTALL_PACKAGE);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//7.0以后,系统要求授予临时uri读取权限,安装完毕以后,系统会自动收回权限,次过程没有用户交互
        } else {//7.0以下启动姿势
            uri = Uri.fromFile(apkFile);
            intent.setAction(Intent.ACTION_VIEW);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }
        intent.setDataAndType(uri, "application/vnd.android.package-archive");
        mContext.startActivity(intent);
    }



    public File queryDownloadedApk() {
        File targetApkFile = null;
        if (downloadId != -1) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(downloadId);
            query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
            Cursor cur = downloadManager.query(query);
            if (cur != null) {
                if (cur.moveToFirst()) {
                    String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                    if (!uriString.isEmpty()) {
                        targetApkFile = new File(Uri.parse(uriString).getPath());
                    }
                }
                cur.close();
            }
        }
        return targetApkFile;
    }

}
直接在 WebView  的下载监听中使用:

   webView.setDownloadListener(new DownloadListener() {
                            @Override
                            public void onDownloadStart(final String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
                                runOnUiThread(new Runnable() {
                                    @Override
                                    public void run() {
                                        //使用前先判断是否有读取、写入内存卡权限
                                        if (ContextCompat.checkSelfPermission(RechargeActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                                            ActivityCompat.requestPermissions(RechargeActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, MY_PERMISSIONS_WRITE_EXTERNAL_STORAGE2);
                                        } else {
                                            downloadAPK.downloadAPK(url,"***.apk");//DownLoader 需要在oncreate 中初始化
                                        }
                                    }
                                });


                            }
                        });




### 使用 Android WebView 实现 APK 文件下载Android 开发中,`WebView` 组件允许应用内嵌浏览器功能。当涉及到通过 `WebView` 下载 APK 文件时,可以通过设置 `setDownloadListener` 来处理下载请求。 #### 设置 Download Listener 为了使 `WebView` 能够响应并处理下载链接,需为其配置一个自定义的 `DownloadListener`: ```java webView.setDownloadListener(new DownloadManager.Request.DownloadSource() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { // 处理下载逻辑 } }); ``` 此方法会在用户点击页面内的下载链接时触发[^1]。 #### 创建下载管理器实例 对于实际执行下载任务的部分,推荐利用系统的 `DownloadManager` 服务来发起下载请求,并指定目标路径保存文件: ```java DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); request.setTitle("Application"); request.setDescription("Downloading..."); request.allowScanningByMediaScanner(); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "app.apk"); DownloadManager manager = (DownloadManager)getSystemService(Context.DOWNLOAD_SERVICE); manager.enqueue(request); ``` 这段代码会创建一个新的下载任务并将进度显示给用户,同时确保下载完成后通知栏会有提示[^2]。 #### 解决无法下载的问题 如果遇到 `WebView` 无法启动下载的情况,可能是因为权限不足或未正确配置 MIME 类型等原因造成的。确认已授予存储读写权限,并检查服务器端返回的内容类型是否匹配预期(application/vnd.android.package-archive)。另外,在某些情况下还需要调整 `WebViewClient.shouldInterceptRequest()` 方法的行为以支持特定类型的 URL 加载[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值