当用户单击WebView中的链接时,我需要下载文件。当我在Chrome应用中执行相同的操作时,该动作正常工作,但在WebView中不起作用。我提到了多个问题,并尝试实施提供的解决方案,但它行不通。
stackoverflow问题提到并尝试了解决方案。
在WebView中下载文件
Android WebView不触发HREF下载文件
如何从webview android下载文件?
我使用的WebView代码,
wv_main.getSettings().setJavaScriptEnabled(true);
wv_main.getSettings().setDomStorageEnabled(true);
wv_main.getSettings().setAllowFileAccess(true);
wv_main.getSettings().setAllowFileAccessFromFileURLs(true);
wv_main.getSettings().setAllowUniversalAccessFromFileURLs(true);
wv_main.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
wv_main.getSettings().setBlockNetworkLoads(false);
wv_main.getSettings().setAllowContentAccess(true);
wv_main.getSettings().setPluginState(WebSettings.PluginState.ON);
wv_main.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();
}
});
wv_main.setWebViewClient(new WebViewClient() {
private int webViewPreviousState;
private final int PAGE_STARTED = 0x1;
private final int PAGE_REDIRECTED = 0x2;
@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error) {
// Get cert from SslError
SslCertificate sslCertificate = error.getCertificate();
Certificate cert = getX509Certificate(sslCertificate);
if (cert != null && certificate != null) {
try {
// Reference: https://developer.android.com/reference/java/security/cert/Certificate.html#verify(java.security.PublicKey)
cert.verify(certificate.getPublicKey()); // Verify here...
handler.proceed();
} catch (CertificateException | NoSuchAlgorithmException | InvalidKeyException | NoSuchProviderException | SignatureException e) {
super.onReceivedSslError(view, handler, error);
e.printStackTrace();
}
} else {
super.onReceivedSslError(view, handler, error);
}
}
@Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
webViewPreviousState = PAGE_REDIRECTED;
wv_main.loadUrl(urlNewString);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewPreviousState = PAGE_STARTED;
Log.e("Start Loading", "Start Loading.........");
/*if (dialog == null || !dialog.isShowing())
dialog = ProgressDialog.show(MainActivity.this, "", "Loading", true, true);*/
}
@Override
public void onPageFinished(WebView view, String url) {
if (webViewPreviousState == PAGE_STARTED) {
//dialog.dismiss();
Log.e("Loading Done", "Loading Done.........");
}
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request,
WebResourceError error) {
super.onReceivedError(view, request, error);
Toast.makeText(SecretLinkBrowserActivity.this, "Error:" + error.toString(), Toast.LENGTH_SHORT).show();
}
});
wv_main.setWebChromeClient(new WebChromeClient() {
@Override
public void onPermissionRequest(final PermissionRequest request) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
request.grant(request.getResources());
}
}
@Override
public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
Log.d("LogTag", message);
result.confirm();
return true;
}
});
在调试时,我注意到,当我单击链接时,shouldOverrideUrlLoading()
没有被调用。网站进行下载的方式是他们使用了动态生成URL并下载文件的doPostBack()
。
If you do this steps in Kotlin you can Download files from any WebView
1- Add these to your Manifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
2- Add these settings to your webview
val webViewSettings = binding.your@id@webview(InsideXML).settings
webViewSettings.javaScriptEnabled = true //Needed
webViewSettings.domStorageEnabled = true //Needed
webViewSettings.allowFileAccess = true //Needed
webViewSettings.loadsImagesAutomatically = true //Needed
----Yo can have more here but this are needed -----
3-Handle the downloads
//handle downloading
binding.wvBase.setDownloadListener { url, userAgent, contentDisposition, mimeType, _ ->
val request = DownloadManager.Request(
Uri.parse(url)
)
request.setMimeType(mimeType)
val cookies: String = CookieManager.getInstance().getCookie(url)
request.addRequestHeader("cookie", cookies)
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
)
)
val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
dm.enqueue(request)
alertdialog()
}
In my case I have a custom alert Dialog to control if user says no, yes
您可以启动一个新意图,并允许用户选择另一个应用程序以下载:
wv_main.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);
}
});
,但我想您想使用下载管理器,您缺少SetDestinationuri方法调用,应该是这样的东西
DownloadManager.Request request=new DownloadManager.Request(Uri.parse(url))
.setTitle("Dummy File")// Title of the Download Notification
.setDescription("Downloading")// Description of the Download Notification
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE)// Visibility of the download Notification
.setDestinationUri(Uri.fromFile(file))// Uri of the destination file
.setRequiresCharging(false)// Set if charging is required to begin the download
.setAllowedOverMetered(true)// Set if download is allowed on Mobile network
.setAllowedOverRoaming(true);// Set if download is allowed on roaming network