Android webview 本地下载文件不跳转到浏览器,下载之后自动安装

本篇重点介绍使用webview遇到下载文件时,不跳转到浏览器,自己用DownLoadManager来下载。说下思路:

1.跳转到浏览器去下载文件的前提是webview有个DownLoadListener里监听到要下载,这时候我们用代码告诉它跳转到浏览器去下载这个文件,但这样用户体验不好,因为已经跳出了APP应用程序,至于怎么实现在以前两篇博客里已经贴过代码,这里不再多说。

2.在本地下载也是顺着这个思路,当监听到有文件要下载的时候这个时候我们弹出一个对话框提示用户下载还是取消下载---->当用户点击下载之后------>用DownLoadManger去下载------->下载完成后用BroadCastReceiver接收消息后进行自动安装。

代码如下:

1.

/**
 * Created by xutingting on 2017/8/17.
 * 这个类的作用是监听到有需要下载的文件时弹出下载对话框,点击下载后调用下载的类的downloadApk。
 */

public class MyDownLoadListener implements DownloadListener {
    private Context context;

    private String name;

    public MyDownLoadListener(Context context) {
        this.context = context;
    }

    @Override
    public void onDownloadStart(final String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {

        //截取url的最后/后面的字符串作为每个下载app的名字
        String[] split = url.split("/");
        if (split.length > 0) {
            name = split[split.length - 1];
        }

        /**
         * 弹出下载提示框
         */

        final AlertDialog dialog = new AlertDialog.Builder(context, R.style.Theme_Light_Dialog).create();
        View inflate = LayoutInflater.from(context).inflate(R.layout.xia_zai_dialog, null);
        Window window = dialog.getWindow();
        //设置dialog在屏幕底部
        window.setGravity(Gravity.BOTTOM);
        window.getDecorView().setPadding(0, 0, 0, 0);
        //获得window窗口的属性
        android.view.WindowManager.LayoutParams lp = window.getAttributes();
        //设置窗口宽度为充满全屏
        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
        //设置窗口高度为包裹内容
        lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
        dialog.setView(inflate);
        dialog.show();
        //将设置好的属性set回去
        window.setAttributes(lp);


        RelativeLayout mGroundLayout = (RelativeLayout) inflate.findViewById(R.id.bei_jing_layout);

        TextView mCancleTextView = (TextView) inflate.findViewById(R.id.qu_xiao_textview); //取消按钮

        TextView mSureTextView = (TextView) inflate.findViewById(R.id.xia_zai_textView); //下载按钮

        mCancleTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                dialog.dismiss();
            }
        });

        mSureTextView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread() {
                    @Override
                    public void run() {
                        // Looper.prepare();
                        new Handler(Looper.getMainLooper()).post(new Runnable() {

                            @Override
                            public void run() {
                                //检查权限,有去下载,没有去请求权限。
                                if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                                    ActivityCompat.requestPermissions((Activity) context, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
                                } else {
                                    Downloader downloader = new Downloader(context);  //下载类
                                    Toast.makeText(context, "成功创建下载任务,正在下载", Toast.LENGTH_SHORT).show();
                                    dialog.dismiss();
                                    if (name.length() > 0) {
                                        downloader.downloadAPK(url, name);//DownLoader 需要在oncreate 中初始化
                                    } else {
                                        downloader.downloadAPK(url, "***.apk");//DownLoader 需要在oncreate 中初始化
                                    }

                                }

                            }
                        });
                    }
                }.start();

            }
        });

    }
}

2.这个是Downloader 类,主要是用DownLoadManager去下载(downloadApk)

/**
 * Created by xutingting on 2018/2/28.
 * 用DownLoadManager去下载
 */

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(name);
        request.setDescription("正在下载...");
        request.setVisibleInDownloadsUi(true);

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

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

3.用BroadCastReceiver接收到下载完成的监听后,进行自动安装。这里DownLoadManager会自己一直发送自己下载进度的广播,不需要我们担心,我们只需要注册一个静态的广播来接收就可以,这里没有用动态方式去注册广播是因为用动态的方式去注册广播的缺点是广播会受到生命周期的影响,当生命周期结束后广播也随机停止,会导致下载完成后没有自动安装。

/**
 * Created by xutingting on 2018/4/13.
 * 静态注册的MyBroadCastReceiver,收到下载完成的消息后进行安装
 */

public class MyBroadCastReceiver extends BroadcastReceiver {

    private long downloadId;

    private DownloadManager downloadManager;


    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "下载完成", Toast.LENGTH_SHORT).show();
        if (intent.getAction().equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
            downloadManager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
            downloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0);
            //检查下载状态
            checkStatus(context);
        }
    }


    /**
     * 检查下载状态
     * 这里的contxt 直接用onReceive里的context,MyBroadCastReceiver不能有构造方法这里需要注意,需要参数的时候从onReceiver里的context和intent获得
     * @param context
     */
    private void checkStatus(Context context) {
        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(context);
                    break;
                //下载失败
                case DownloadManager.STATUS_FAILED:
                    Toast.makeText(context, "下载失败", Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    }

    /**
     * 下载到本地后执行安装
     * @param context
     */
    private void installAPK(Context context) {

        Intent intent = new Intent();
        File apkFile = queryDownloadedApk();
        String packageName = context.getPackageName();
        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(context, packageName + ".fileprovider", apkFile);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);//7.0以后,系统要求授予临时uri读取权限,安装完毕以后,系统会自动收回权限,次过程没有用户交互
            intent.setAction(Intent.ACTION_INSTALL_PACKAGE);
        } 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");
        context.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;
    }
}

4.在清单文件里静态注册广播在</application>的标签里

<!--静态注册广播接受者-->
<receiver android:name=".view.MyBroadCastReceiver">
    <intent-filter>
        <action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
    </intent-filter>
</receiver>
5.最后一步就是设置给webview将MyDownLoadListener

mWebView.setDownloadListener(new MyDownLoadListener(this));

截图如下:



  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
如果你想在当前浏览器下载文件而不是跳转到系统浏览器,你可以使用WebView的setDownloadListener方法来实现。下面是一个示例代码: ```java webView.setDownloadListener(new DownloadListener() { @Override public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) { // 创建一个下载请求 DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); // 设置文件保存路径,这里使用应用的缓存目录 String fileName = URLUtil.guessFileName(url, contentDisposition, mimeType); File file = new File(getApplicationContext().getExternalCacheDir(), fileName); request.setDestinationUri(Uri.fromFile(file)); // 设置一些其他下载参数,如标题、描述、可见性等 request.setTitle(fileName); request.setDescription("Downloading file"); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); // 获取系统的下载管理器并开始下载 DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); downloadManager.enqueue(request); } }); ``` 在上面的代码中,我们首先设置了一个DownloadListener,在下载开始时会回调onDownloadStart方法。在这个方法中,我们创建了一个DownloadManager.Request对象,并设置了文件保存路径、标题、描述等参数。然后,我们获取系统的下载管理器,并使用enqueue方法将下载请求加入队列,开始下载。 请注意,为了使上述代码正常工作,你需要在AndroidManifest.xml文件中添加以下权限: ```xml <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> ``` 这样,WebView中的下载链接将在当前浏览器中进行下载,而不是跳转到系统浏览器

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值