Веб-просмотр Android: загрузка файлов, таких как браузеры

Я работаю над Android-приложением с веб-просмотром, указывающим на динамический веб-сайт другой командой.
Когда я загружаю файл (в основном динамически перенаправленный PDF и ZIP) все, что я получаю, это файл в папке с загрузкой, содержащей некоторый код HTML с сообщением типа "пользователь не разрешил читать файл" , независимо от того, как я реализую загрузку, я попробовал:

  • DownloadManager
  • Intent (позволяя внешнему браузеру управлять загрузкой)
  • "вручную" (AsyncTask и httpconnection...)

все с одинаковыми результатами.

Навигация с обычными загрузками браузеров отлично работают как на настольных ПК, так и на устройствах Android и iOS.

Почему веб-просмотр не должен иметь доступ к файлам?

Может быть проблема с сеансом? порт 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);
}

взято из Как загрузить PDF файл из динамического URL-адреса в веб-обозревателе
Thanx

Ответ 1

Наконец, я решил искать DownloadHandler из кода Android Stock Browser. Единственным заметным недостатком моего кода было 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();
        }
    });

Ответ 2

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 за ваш ответ вы пропустили ); в конце кода.

Ответ 3

С помощью этой опции мне удалось загрузить полные файлы, загрузка работала с другими опциями, но документы выглядели пустыми, особенно при использовании сеанса.

Добавьте строки ниже к 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();

}

Ответ 4

AsyncTask для ручной загрузки имени файла (вы можете добавить к этому классу дополнительный код):

private static class getFileNameAsync extends AsyncTask<String, Void, String> {

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

    @Override
    protected String doInBackground(String... params) {
        URL url;
        String filename = null;
        HttpURLConnection conn = null;
        try {
            url = new URL(params[0]);
            conn = (HttpURLConnection) url.openConnection();
            conn.connect();
            conn.setInstanceFollowRedirects(false);

            try {
                for(int i = 0; i < 100; i++)
                {
                    String stringURL = conn.getHeaderField("Location");
                    if (stringURL != null) {
                        url = new URL(stringURL);
                        conn = (HttpURLConnection) url.openConnection();
                        conn.connect();
                        conn.setInstanceFollowRedirects(false);
                    } else {
                        i = 100;
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            String depo = conn.getHeaderField("Content-Disposition");
            if (depo != null) {
                String depoSplit[] = depo.split(";");
                int size = depoSplit.length;
                for(int i = 0; i < size; i++)
                {
                    if(depoSplit[i].startsWith("filename="))
                    {
                        filename = depoSplit[i].replaceFirst("(?i)^.*filename=\"?([^\"]+)\"?.*$", "$1").trim();
                        i = size;
                    }
                }
            }
        } catch (MalformedURLException e){
            e.printStackTrace();
        } catch (ProtocolException e){
            e.printStackTrace();
        } catch (FileNotFoundException e){
            e.printStackTrace();
        } catch (IOException e){
            e.printStackTrace();
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (conn != null)
                conn.disconnect();
        }
        return filename;
    }
    @Override
    protected void onPostExecute(String filename) {
        super.onPostExecute(filename);
    }
}

DownloadListener (стабильная версия, не меняйте его):

    mWebView.setDownloadListener(new DownloadListener() {
        @Override
        public void onDownloadStart(String url,
                                    String userAgent,
                                    String contentDisposition,
                                    String mimetype,
                                    long contentLength) {
            if(Build.VERSION.SDK_INT >=23){
                Context nContext = MainActivity.this.getApplicationContext();
                if(nContext.checkSelfPermission(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
                    MainActivity.this.requestPermissions(new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
                    return;
                }
            }

            String fileName = "";
            url = url.replace(" ", "%20");

            AsyncTask<String, Void, String> asyncTask = new getFileNameAsync();
            asyncTask.execute(url);

            try {
                fileName = asyncTask.get();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            } catch (CancellationException e) {
                e.printStackTrace();
            }
            if ((fileName == null) || (fileName.hashCode() == "".hashCode())) {
                fileName = URLUtil.guessFileName(url, contentDisposition, mimetype);
            }

            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url));

            request.setMimeType(mimetype);
            String cookies = CookieManager.getInstance().getCookie(url);
            request.addRequestHeader("Cookie", cookies);
            request.addRequestHeader("User-Agent", userAgent);
            request.setDescription("Downloading File");
            request.setTitle(fileName);
            request.allowScanningByMediaScanner();
            request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName);
            DownloadManager downloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            if (downloadManager != null) {
                downloadManager.enqueue(request);
            }
            Toast.makeText(getApplicationContext(), "Downloading File", Toast.LENGTH_LONG).show();
        }
    });