美文网首页WebViewAndroid知识Android开发经验谈
Android 让 WebView 响应下载点击事件

Android 让 WebView 响应下载点击事件

作者: ayuhani | 来源:发表于2017-06-28 10:23 被阅读168次

    最近项目中的邮件模块需要与第三方进行对接并且利用 WebView 展示,测试的时候发现点击附件下载没有任何反应,但是 ios 端却可以直接点击预览,客户非常不开心。

    百度之后发现 WebView 默认不提供下载响应(应该是为了安全性考虑),只要设置了webview.setDownloadListener() 方法我们就可以下载了。既然这么简单我们就赶紧试试吧。

    webView.setDownloadListener(new DownloadListener() {
    
        @Override
        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
                
            // url 你要访问的下载链接
            // userAgent 是HTTP请求头部用来标识客户端信息的字符串
            // contentDisposition 为保存文件提供一个默认的文件名
            // mimetype 该资源的媒体类型
            // contentLength 该资源的大小
            // 这几个参数都是可以通过抓包获取的
    
            // 用手机默认浏览器打开链接
            Uri uri = Uri.parse(url);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
            startActivity(intent);
        }
    });
    

    我们这里先测试用系统默认的浏览器进行下载。在大多数的情况下这样已经满足要求了,网上的方法也确实是这样的,我怀着满心欢喜打开了项目,然后点击下载:”网页无法打开“。很郁闷。我又用手机的浏览器测试了一下,的的确确是没有问题的。那么问题出在哪呢?

    继续抓包,发现了异样。在浏览器中,访问邮件与点击下载获取的 cookie 值是相同的,而在 WebView 中这两个值是不同的。似乎找到原因了!这个下载链接是需要验证 cookie 的。可是怎么把 WebView 的 cookie 传递给系统的浏览器呢?这个我确实不会,那么不如自己写个方法下载吧。

    首先我们要获取到 cookie:

    webView.setWebViewClient(new WebViewClient() {
    
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            view.loadUrl(url);
            return true;
        }
    
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            CookieManager cookieManager = CookieManager.getInstance();
            cookieStr = cookieManager.getCookie(url); // 获取到cookie字符串值
        }
    });
    

    然后我们自己写个下载类:

    private class DownloadTask extends AsyncTask<String, Void, String> {
    
            @Override
            protected String doInBackground(String... params) {
    
                String url = params[0]; // 要访问的链接
                String fileName = params[1]; // 文件名
    
                if (TextUtils.isEmpty(url)) {
                    return null;
                }
    
                File directory = Environment.getExternalStorageDirectory();
                File file = new File(directory, fileName);
                if (file.exists()) {
                    return fileName;
                }
                
                // 下载文件
                try {
                    URL myFileUrl = new URL(url);
                    HttpURLConnection conn = (HttpURLConnection) myFileUrl
                            .openConnection();
                    // 携带cookie请求,要写在请求开始之前
                    conn.addRequestProperty("Cookie", cookieStr);
                    conn.setDoInput(true);
                    conn.connect();
    
                    InputStream is = conn.getInputStream();
                    // 我们把文件保存在sd卡根目录
                    FileOutputStream out = new FileOutputStream(Environment.getExternalStorageDirectory().getAbsolutePath() + "/" +fileName);
                    byte[] buffer = new byte[1024];
                    int r;
                    while ((r = is.read(buffer)) > 0) {
                        out.write(buffer, 0, r);
                        out.flush();
                    }
                    is.close();
                    out.close();
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
                return fileName;
            }
    
            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                // 这里可以对下载好的文件进行打开等操作
            }
        }
    

    启动下载:

    @Override
    public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) {
        // 获取文件名称,在我的项目测试之后发现得到的是乱码
        String fileName = contentDisposition.substring(contentDisposition.indexOf("\"") + 1, contentDisposition.length() - 1);
        DownloadTask task = new DownloadTask();
        task.execute(url, fileName);
    }
    

    ok,工作完成。我测试了一下,成功下载!于是交付测试。

    ...
    ...
    ...

    一段时间之后,被告知又出现了问题:有时可以下载,有时又无法访问链接。

    这又是什么原因呢?有时可以下载说明这种解决办法的方向是正确的,可有时又不能下载,这个问题又出在哪里呢?既然之前无法访问是因为没有验证 cookie,那么这次首先想到的就是 cookie 验证失败了。

    继续抓包,发现 cookie 是有实效性的,也就是一段时间之后 cookie 是会发生变化的,但是 WebView 却一直保留着同一个 cookie 值。找到了原因,那就让 WebView 每次loadUrl(your url)之前清除掉 cookie 。

    webView.clearCache(true); // 清除资源缓存。请注意,缓存是每个应用程序的,所以这将清除所有使用的WebViews的缓存。false的话,只会清除RAM上的缓存。
    webView.clearHistory(); // 清除历史记录
    webView.clearFormData(); // //从当前关注的表单字段中移除自动填充弹出窗口
    webView.clearSslPreferences(); // 清除存储的SSL首选项表
    

    为了保险起见,在onDestroy()方法中写上同样的方法。

    @Override
    protected void onDestroy() {
        super.onDestroy();
        tencent_webview.clearCache(true);
        tencent_webview.clearHistory();
        tencent_webview.clearFormData();
        tencent_webview.clearSslPreferences();
    }
    

    这样就基本解决了问题,测试正常。

    对于 WebView 的了解和掌握,我要学习的还有很多很多,写的不对的地方,欢迎各位指教~

    欢迎关注我的微信公众号

    相关文章

      网友评论

        本文标题: Android 让 WebView 响应下载点击事件

        本文链接:https://www.haomeiwen.com/subject/rbzycxtx.html