如何从 webview Android 下载文件?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21864098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:12:18  来源:igfitidea点击:

How to download files from webview Android?

androidwebviewandroid-download-manager

提问by Dritan Berna

My code below loads the url page fine and after searching for a song when I click on the download link it crashes. There aren't so much tutorials on how to get the download manager to work with a webview. What am I doing wrong?

我下面的代码可以很好地加载 url 页面,并且在我单击下载链接时搜索歌曲后崩溃了。关于如何让下载管理器使用 webview 的教程并不多。我究竟做错了什么?

import java.io.File;
import android.app.Activity;
import android.app.DownloadManager;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.webkit.WebView;
import android.webkit.WebViewClient;


public class List1 extends Activity {

        WebView ourBrow;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Use a custom layout file
        setContentView(R.layout.list1);

        final DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);

     final File destinationDir = new File (Environment.getExternalStorageDirectory(), getPackageName());
     if (!destinationDir.exists()) {
         destinationDir.mkdir(); // Don't forget to make the directory if it's not there
     }

        ourBrow = (WebView) findViewById(R.id.wvBrowser);
        ourBrow.getSettings().setJavaScriptEnabled(true);
        ourBrow.setInitialScale(50); 
        ourBrow.getSettings().setUseWideViewPort(true); 
        ourBrow.setVerticalScrollBarEnabled(false);
        ourBrow.setHorizontalScrollBarEnabled(false);
        ourBrow.loadUrl("http://www.degjo.com");



        ourBrow.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading (WebView view, String url) {
                boolean shouldOverride = false;
                // We only want to handle requests for mp3 files, everything else the webview
                // can handle normally
                if (url.endsWith(".mp3")) {
                    shouldOverride = true;
                    Uri source = Uri.parse(url);

                    // Make a new request pointing to the mp3 url
                    DownloadManager.Request request = new DownloadManager.Request(source);
                    // Use the same file name for the destination
                    File destinationFile = new File (destinationDir, source.getLastPathSegment());
                    request.setDestinationUri(Uri.fromFile(destinationFile));
                    // Add it to the manager
                    manager.enqueue(request);
                }
                return shouldOverride;
            }
        });





    }
}

LogCat

日志猫

02-18 19:45:44.891: E/AndroidRuntime(357):  at android.content.ContentProviderProxy.insert(ContentProviderNative.java:408)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.content.ContentResolver.insert(ContentResolver.java:604)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.app.DownloadManager.enqueue(DownloadManager.java:750)
02-18 19:45:44.891: E/AndroidRuntime(357):  at com.example.androidbuttonsactivities.List1.shouldOverrideUrlLoading(List1.java:78)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.webkit.CallbackProxy.uiOverrideUrlLoading(CallbackProxy.java:216)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.webkit.CallbackProxy.handleMessage(CallbackProxy.java:323)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.os.Handler.dispatchMessage(Handler.java:99)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.os.Looper.loop(Looper.java:123)
02-18 19:45:44.891: E/AndroidRuntime(357):  at android.app.ActivityThread.main(ActivityThread.java:3683)
02-18 19:45:44.891: E/AndroidRuntime(357):  at java.lang.reflect.Method.invokeNative(Native Method)
02-18 19:45:44.891: E/AndroidRuntime(357):  at java.lang.reflect.Method.invoke(Method.java:507)
02-18 19:45:44.891: E/AndroidRuntime(357):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-18 19:45:44.891: E/AndroidRuntime(357):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-18 19:45:44.891: E/AndroidRuntime(357):  at dalvik.system.NativeStart.main(Native Method)
02-18 19:45:48.401: I/Process(357): Sending signal. PID: 357 SIG: 9

回答by Brendon

It may be depends on the android build version problem, the below code will work successfully on 2.3+ builds, check this out,

这可能取决于 android 构建版本问题,以下代码将在 2.3+ 构建上成功运行,请查看,

ourBrow.setWebViewClient(new WebViewClient() {
        @Override
        public void onReceivedError(WebView view, int errorCode,
            String description, String failingUrl) {
                Log.d("WEB_VIEW_TEST", "error code:" + errorCode + " - " + description);
        }

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
                // handle different requests for different type of files
                // this example handles downloads requests for .apk and .mp3 files
                // everything else the webview can handle normally
                if (url.endsWith(".apk")) {
                    Uri source = Uri.parse(url);
                    // Make a new request pointing to the .apk url
                    DownloadManager.Request request = new DownloadManager.Request(source);
                    // appears the same in Notification bar while downloading
                    request.setDescription("Description for the DownloadManager Bar");
                    request.setTitle("YourApp.apk");
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
                        request.allowScanningByMediaScanner();
                        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
                    }
                    // save the file in the "Downloads" folder of SDCARD
                    request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "SmartPigs.apk");
                    // get download service and enqueue file
                    DownloadManager manager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
                    manager.enqueue(request);
                }
                else if(url.endsWith(".mp3")) {
                    // if the link points to an .mp3 resource do something else
                }
                // if there is a link to anything else than .apk or .mp3 load the URL in the webview
                else view.loadUrl(url);
                return true;                
        }
    });

回答by Wei WANG

Did you add DownloadManager Permission in your manifest file?

您是否在清单文件中添加了 DownloadManager 权限?

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

-----EDIT-----

- - -编辑 - - -

I'm copying some code snippet for your reference from Android stock browser on starting a download task:

在开始下载任务时,我正在从 Android 股票浏览器复制一些代码片段供您参考:

import android.net.WebAddress;

// java.net.URI is a lot stricter than KURL so we have to encode some
// extra characters. Fix for b 2538060 and b 1634719
WebAddress webAddress;
try {
    webAddress = new WebAddress(url);
    webAddress.setPath(encodePath(webAddress.getPath()));
} catch (Exception e) {
    // This only happens for very bad urls, we want to chatch the
    // exception here
    Log.e(LOGTAG, "Exception trying to parse url:" + url);
    return;
}

String addressString = webAddress.toString();
Uri uri = Uri.parse(addressString);
final DownloadManager.Request request;
try {
    request = new DownloadManager.Request(uri);
} catch (IllegalArgumentException e) {
    Toast.makeText(activity, R.string.cannot_download, Toast.LENGTH_SHORT).show();
    return;
}
request.setMimeType(mimetype);
// set downloaded file destination to /sdcard/Download.
// or, should it be set to one of several Environment.DIRECTORY* dirs depending on mimetype?
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, filename);
// let this downloaded file be scanned by MediaScanner - so that it can 
// show up in Gallery app, for example.
request.allowScanningByMediaScanner();
request.setDescription(webAddress.getHost());
// XXX: Have to use the old url since the cookies were stored using the
// old percent-encoded url.
String cookies = CookieManager.getInstance().getCookie(url, privateBrowsing);
request.addRequestHeader("cookie", cookies);
request.addRequestHeader("User-Agent", userAgent);
request.addRequestHeader("Referer", referer);
request.setNotificationVisibility(
        DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
if (mimetype == null) {
    if (TextUtils.isEmpty(addressString)) {
        return;
    }
    // We must have long pressed on a link or image to download it. We
    // are not sure of the mimetype in this case, so do a head request
    new FetchUrlMimeType(activity, request, addressString, cookies,
            userAgent).start();
} else {
    final DownloadManager manager
            = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
    new Thread("Browser download") {
        public void run() {
            manager.enqueue(request);
        }
    }.start();
}
Toast.makeText(activity, R.string.download_pending, Toast.LENGTH_SHORT)
        .show();

回答by Ibrahim

try this out

试试这个

mWebView.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.allowScanningByMediaScanner();
        request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); //Notify client once download is completed!
        request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Name of your downloadble file goes here, example: Mathematics II ");
        DownloadManager dm = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
        dm.enqueue(request);
        Toast.makeText(getApplicationContext(), "Downloading File", //To notify the Client that the file is being downloaded
                Toast.LENGTH_LONG).show();

    }
});

Also don't forget to add the below code to the manifest.xml file,its very important this will give it permission for save to storage just like giving it Internet permission for the weview.

另外不要忘记将下面的代码添加到 manifest.xml 文件中,这非常重要,这将授予它保存到存储的权限,就像授予它对 weview 的 Internet 权限一样。

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