【问题标题】:Android webview: download files like browsers doAndroid webview:像浏览器一样下载文件
【发布时间】:2015-10-30 11:06:00
【问题描述】:

我正在开发一个带有指向另一个团队的动态网站的 web 视图的 Android 应用。
当我下载一个文件时(主要是动态重定向 PDF和ZIP)我得到的只是下载文件夹中的一个文件,其中包含一些HTML代码,并带有“用户不允许阅读文件”之类的消息,不管我怎么实现下载,我都试过了:

  1. 下载管理器
  2. Intent(让外部浏览器管理下载)
  3. “手动”(AsyncTask 和 httpconnection...)

所有结果都相同。

在台式电脑、Android 和 iOS 设备上使用普通浏览器下载都可以正常工作

为什么 webview 不能访问文件?

可能是会话问题? http 端口?
我真的需要一些想法...

另一个提示:当从同一个链接下载两次文件时,链接将重定向到同一个文件,但会导致两个不同的文件名......


编辑:我没有将 webView 指向网络应用程序,而是尝试指向一个带有链接重定向的通用网页来下载另一个文件,嗯,很简单有用。


以下是webview.setDownloadListener - onDownloadStart() 参数:

 userAgent=Mozilla/5.0 (Linux; Android 4.4.2; Nexus 7 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.0.0 Safari/537.36

 contentDisposition=attachment;
 filename=correct_filename.pdf,      
 url=http://www.xxx.xx/site/downloadfile.wplus?REDIRECTFILE=D-507497120&ID_COUNTOBJ=ce_5_home&TYPEOBJ=CExFILE&LN=2

 mimeType=application/octet-stream

这里有一些代码

    wv.getSettings().setSupportMultipleWindows(true);
    wv.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
    wv.getSettings().setAllowFileAccess(true);
    wv.getSettings().setJavaScriptEnabled(true);
    wv.getSettings().setBuiltInZoomControls(true);
    wv.getSettings().setDisplayZoomControls(false);
    wv.getSettings().setLoadWithOverviewMode(true);
    wv.getSettings().setUseWideViewPort(true);
    wv.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));

            request.setDescription("Download file...");
            request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimetype));
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, contentDisposition, mimetype));
            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            dm.enqueue(request);
            Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
        } 
    }



EDIT II

这是我尝试“手动”下载文件时使用的代码:

onDownloadStart() 是我调用 downloadFileAsync() 的地方:

        public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimeType, long contentLength) {
            String fileName;
            try {
                fileName = URLUtil.guessFileName(url, contentDisposition, mimeType);
                downloadFileAsync(url, fileName);
            }catch (Exception e){

            }
        }

这是 AsyncTask:

private void downloadFileAsync(String url, String filename){

    new AsyncTask<String, Void, String>() {
        String SDCard;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        @Override
        protected String doInBackground(String... params) {
            try {
                URL url = new URL(params[0]);
                HttpURLConnection urlConnection = null;
                urlConnection = (HttpURLConnection) url.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.setDoOutput(true);
                urlConnection.connect();
                int lengthOfFile = urlConnection.getContentLength();
                //SDCard = Environment.getExternalStorageDirectory() + File.separator + "downloads";
                SDCard = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)+"";
                int k = 0;
                boolean file_exists;
                String finalValue = params[1];
                do {
                    if (k > 0) {
                        if (params[1].length() > 0) {
                            String s = params[1].substring(0, params[1].lastIndexOf("."));
                            String extension = params[1].replace(s, "");

                            finalValue = s + "(" + k + ")" + extension;
                        } else {
                            String fileName = params[0].substring(params[0].lastIndexOf('/') + 1);
                            String s = fileName.substring(0, fileName.lastIndexOf("."));
                            String extension = fileName.replace(s, "");
                            finalValue = s + "(" + k + ")" + extension;
                        }
                    }
                    File fileIn = new File(SDCard, finalValue);
                    file_exists = fileIn.exists();
                    k++;
                } while (file_exists);

                File file = new File(SDCard, finalValue);
                FileOutputStream fileOutput = null;
                fileOutput = new FileOutputStream(file, true);
                InputStream inputStream = null;
                inputStream = urlConnection.getInputStream();
                byte[] buffer = new byte[1024];
                int count;
                long total = 0;
                while ((count = inputStream.read(buffer)) != -1) {
                    total += count;
                    //publishProgress(""+(int)((total*100)/lengthOfFile));
                    fileOutput.write(buffer, 0, count);
                }
                fileOutput.flush();
                fileOutput.close();
                inputStream.close();
            } catch (MalformedURLException e){
            } catch (ProtocolException e){
            } catch (FileNotFoundException e){
            } catch (IOException e){
            } catch (Exception e){
            }
            return params[1];
        }
        @Override
        protected void onPostExecute(final String result) {

        }

    }.execute(url, filename);
}

取自How to download a PDF from a dynamic URL in a webview
谢谢

【问题讨论】:

  • 您似乎正在下载外部存储中的文件。确保您在清单中有权限 ()。看看是否有效
  • @Tasos 当然我已经设置好了,反正thanx。
  • 好的,您可以随时嵌入人行横道,它具有与 chrome 浏览器等相同的 api 以及更多功能,以使事情变得简单。您只需要添加 () 即可下载文件,没问题。 crosswalk-project.org -- 测试一下 -- github.com/dougdiego/CrosswalkDemo -- 在 gradle 中使用最新的构建工具、SDK 和 crosswalk 版本 (15.44.384.12)
  • @Tasos 好的,thanx,但我不会重新开始学习对我来说全新的东西,我只是想了解为什么我的应用程序无法下载这些文件,而完全能够下载其他文件来自其他所有网站的文件。什么会导致“防火墙”不允许我的应用下载这些动态文件?
  • 那么您必须检查防火墙日志以了解原因。也许您需要更改它的设置。

标签: android webview download permissions dynamic-links


【解决方案1】:

最后我决定寻找 DownloadHandler from the Android Stock Browser code。 我的代码中唯一明显的缺失是 cookie (!!!)。

这是我的最终工作版本(DownloadManager 方法):

    wv.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));

            request.setMimeType(mimeType);
            //------------------------COOKIE!!------------------------
            String cookies = CookieManager.getInstance().getCookie(url);
            request.addRequestHeader("cookie", cookies);
            //------------------------COOKIE!!------------------------
            request.addRequestHeader("User-Agent", userAgent);
            request.setDescription("Downloading file...");
            request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimeType));
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, contentDisposition, mimeType));
            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            dm.enqueue(request);
            Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
        }
    });

【讨论】:

  • 谢谢你!这也是我所缺少的。我的 webview 试图从动态(自动生成的链接)下载 PDF。
  • @j.c 请回答以下问题我已经尝试了很多东西,但没有任何帮助! stackoverflow.com/questions/43140708/…
  • 您好,您忘了在清单文件中提及
  • 如何保存在自定义特定文件夹中,例如:root/My Folder/File.ext
  • 太棒了!谢谢
【解决方案2】:

使用此选项,我设法下载了完整的文件,下载与其他选项一起使用,但文档显示为空,尤其是在使用会话时。

以下行添加到AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

将 DownloadListener 添加到您的 WebView

试试这个代码

wv.setDownloadListener(new DownloadListener() {
    @Override
    public void onDownloadStart(final String url, final String userAgent, String contentDisposition, String mimetype, long contentLength) {
        //Checking runtime permission for devices above Marshmallow.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
                    == PackageManager.PERMISSION_GRANTED) {
                Log.v(TAG, "Permission is granted");
                downloadDialog(url, userAgent, contentDisposition, mimetype);

            } else {

                Log.v(TAG, "Permission is revoked");
                //requesting permissions.
                ActivityCompat.requestPermissions(PortalActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);

            }
        } else {
            //Code for devices below API 23 or Marshmallow
            Log.v(TAG, "Permission is granted");
            downloadDialog(url, userAgent, contentDisposition, mimetype);

        }
    }
});

//downloadDialog Method

public void downloadDialog(final String url, final String userAgent, String contentDisposition, String mimetype) {
    //getting filename from url.
    final String filename = URLUtil.guessFileName(url, contentDisposition, mimetype);
    //alertdialog
    AlertDialog.Builder builder = new AlertDialog.Builder(this);

    //title of alertdialog
    builder.setTitle(R.string.download_title);
    //message of alertdialog
    builder.setMessage(getString(R.string.download_file) + ' ' + filename);
    //if Yes button clicks.

    builder.setPositiveButton(getString(R.string.yes), new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            //DownloadManager.Request created with url.
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));
            //cookie
            String cookie = CookieManager.getInstance().getCookie(url);
            //Add cookie and User-Agent to request
            request.addRequestHeader("Cookie", cookie);
            request.addRequestHeader("User-Agent", userAgent);
            //file scanned by MediaScannar
            request.allowScanningByMediaScanner();
            //Download is visible and its progress, after completion too.
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            //DownloadManager created
            DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            //Saving files in Download folder
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
            //download enqued
            downloadManager.enqueue(request);
        }
    });
    builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            //cancel the dialog if Cancel clicks
            dialog.cancel();
            mWebView.goBack();
        }

    });
    //alertdialog shows.
    builder.show();

}

【讨论】:

    【解决方案3】:
    wv.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));
    
            request.setMimeType(mimeType);
            //------------------------COOKIE!!------------------------
            String cookies = CookieManager.getInstance().getCookie(url);
            request.addRequestHeader("cookie", cookies);
            //------------------------COOKIE!!------------------------
            request.addRequestHeader("User-Agent", userAgent);
            request.setDescription("Downloading file...");
            request.setTitle(URLUtil.guessFileName(url, contentDisposition, mimeType));
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, URLUtil.guessFileName(url, contentDisposition, mimeType));
            DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            dm.enqueue(request);
            Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
        }
    });
    

    感谢 j.c 的回答 您在代码末尾错过了 );..

    【讨论】:

      【解决方案4】:

      你也可以使用:

      mWebView.setDownloadListener(new DownloadListener() {
      public void onDownloadStart(String url, String userAgent,
                  String contentDisposition, String mimetype,
                  long contentLength) {
          Intent i = new Intent(Intent.ACTION_VIEW);
          i.setData(Uri.parse(url));
          startActivity(i);
      }});
      

      【讨论】:

        【解决方案5】:

        请注意 - 您还应该添加“Referer”请求标头 - 没有它,某些网站根本不会让您下载文件。

        【讨论】:

          猜你喜欢
          • 2018-09-24
          • 1970-01-01
          • 2011-12-19
          • 2013-03-22
          • 2021-10-05
          • 2015-04-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多