如何在Android上使用Xamarin WebView下载像本地浏览器一样的文件?



我想下载任何类型的文件与WebView实现在我的应用程序。在iOS上,我注意到WebView大多只能显示自己内部的文件。在Android上,WebView会在加载过程中陷入循环。它可能试图下载文件,但不能。iOS的原生行为,比如Safari ->在WebView中显示pdf, doc或html。Android的原生行为,即Chrome ->下载所有内容,然后在下载后试图打开或下载后立即打开时尝试使用正确的应用程序查看它(在Android 11.0.0.153的华为P30 Pro上测试)。

为什么我的WebView不能做到这一点。有人能帮我一下吗?

我不想在Android的资源中创建一个自定义布局,我不能采取在Android的git示例中实现的方法,因为它会在我的网站上被阻止,因为会话劫持。如果你想看到android WebView的无穷加载,只需在mainpage . example .cs:

中注释这个&;If &;-子句中的所有内容。if (Device.RuntimePlatform.Equals(Device.Android))

MainPage.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="WebViewExample.MainPage"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
xmlns:customhybridwebview="clr-namespace:WebViewExample.View.Custom">
<ContentPage.Content>
<StackLayout 
BackgroundColor="#000"
Spacing="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<ActivityIndicator x:Name="loadingIndicator"
HorizontalOptions="Center"
VerticalOptions="Center"
Color="Red"
BackgroundColor="Black">
<ActivityIndicator.HeightRequest>
<OnPlatform x:TypeArguments="x:Double" iOS="60" Android="40"/>
</ActivityIndicator.HeightRequest>
<ActivityIndicator.WidthRequest>
<OnPlatform x:TypeArguments="x:Double" iOS="60" Android="40"/>
</ActivityIndicator.WidthRequest>
</ActivityIndicator>
<customhybridwebview:HybridWebView  x:Name="hybridWebView"
Source="{Binding SourceUrl}"
HeightRequest="1000"
WidthRequest="1000"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
Navigating="HybridWebView_Navigating"
Navigated="HybridWebView_Navigated"  
android:WebView.DisplayZoomControls="False"
android:WebView.EnableZoomControls="True"
android:WebView.MixedContentMode="AlwaysAllow">
</customhybridwebview:HybridWebView>
<Button Text="Back"
TextColor="Red"
BackgroundColor="Black"
HorizontalOptions="CenterAndExpand"
Clicked="ClickedWebViewGoBack"
IsVisible="{Binding BackButtonIsVisible}"/>
</StackLayout>
</ContentPage.Content>
</ContentPage>

MainPage.xaml.cs:

using System;
using System.Diagnostics;
using WebViewExample.ViewModel;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace WebViewExample
{
public partial class MainPage : ContentPage
{
private bool navigatingIsGettingCanceled = false;
private bool webViewBackButtonPressed = false;
readonly MainPageViewModel mainPageViewModel;
public MainPage()
{
InitializeComponent();
mainPageViewModel = new MainPageViewModel();
BindingContext = mainPageViewModel;
mainPageViewModel.LoadURL();
}
protected override bool OnBackButtonPressed()
{
base.OnBackButtonPressed();
if (hybridWebView.CanGoBack)
{
hybridWebView.GoBack();
return true;
}
return false;
}
private void HybridWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
Debug.WriteLine("Debug - Sender: " + sender.ToString());
Debug.WriteLine("Debug - Url: " + e.Url.ToString());
if (!loadingIndicator.IsRunning)
{
loadingIndicator.IsRunning = loadingIndicator.IsVisible = true;
//check every new URL the WebView tries connecting to
if (hybridWebView == null) { return; }
if (hybridWebView.Source == null) { return; }
string nextURL = e.Url;
string urlProperty = hybridWebView.Source.GetValue(UrlWebViewSource.UrlProperty).ToString();
if (String.IsNullOrEmpty(nextURL) || nextURL.Contains("about:blank"))
{
return;
}
if (Device.RuntimePlatform.Equals(Device.Android))
{
//navigatingIsGettingCanceled = true;
try
{
Browser.OpenAsync(nextURL, new BrowserLaunchOptions
{
LaunchMode = BrowserLaunchMode.SystemPreferred,
TitleMode = BrowserTitleMode.Show,
PreferredToolbarColor = Color.White,
PreferredControlColor = Color.Red
});
}
catch (Exception ex)
{
//An unexpected error occured. No browser may be installed on the device.
Debug.WriteLine(string.Format("Debug - Following Exception occured: {0}", ex));
}
}
if (Device.RuntimePlatform.Equals(Device.iOS))
{
mainPageViewModel.ShowBackButton();
}
e.Cancel = navigatingIsGettingCanceled;
if (navigatingIsGettingCanceled)
{
loadingIndicator.IsRunning = loadingIndicator.IsVisible = navigatingIsGettingCanceled = false;
Debug.WriteLine("Debug - Navigation getting cancelled");
return;
}
//edited so it would always SetValue (still not loading the pdf on Android)
hybridWebView.Source.SetValue(UrlWebViewSource.UrlProperty, nextURL);
Debug.WriteLine("Debug - Source changed");
}
}
private void HybridWebView_Navigated(object sender, WebNavigatedEventArgs e)
{
loadingIndicator.IsRunning = loadingIndicator.IsVisible = false;
if (webViewBackButtonPressed)
{
hybridWebView.GoBack();
webViewBackButtonPressed = false;
}
}
void ClickedWebViewGoBack(System.Object sender, System.EventArgs e)
{
if (hybridWebView.CanGoBack)
{
hybridWebView.GoBack();
mainPageViewModel.HideBackButton();
webViewBackButtonPressed = true;
}
}
}
}

MainPageViewModel.cs:

using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Input;
using WebViewExample.Model;
namespace WebViewExample.ViewModel
{
public class MainPageViewModel : INotifyPropertyChanged
{
public string SourceUrl { get; set; }
public bool BackButtonIsVisible { get; set; } = false;
public MainPageViewModel() { }
protected void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
public void LoadURL()
{
SourceUrl = Settings.SourceURL;
Debug.WriteLine("Debug - Load new URL: " + SourceUrl.ToString());
RefreshURL();
}
public void RefreshURL() => OnPropertyChanged(nameof(SourceUrl));
public void ShowBackButton()
{
BackButtonIsVisible = true;
OnPropertyChanged(nameof(BackButtonIsVisible));
}
public void HideBackButton()
{
BackButtonIsVisible = false;
OnPropertyChanged(nameof(BackButtonIsVisible));
}
}
}

Settings.cs:

using System;
using Xamarin.Essentials;
namespace WebViewExample.Model
{
public static class Settings
{
#region setting Constants
private const string KeySourceURL = "sourceURL";
private static readonly string SourceURLDEFAULT = "https://download.microsoft.com/download/7/8/8/788971A6-C4BB-43CA-91DC-557B8BE72928/Microsoft_Press_eBook_CreatingMobileAppswithXamarinForms_PDF.pdf";
#endregion
#region setting Properties
public static string SourceURL
{
get { return Preferences.Get(KeySourceURL, SourceURLDEFAULT); }
set { Preferences.Set(KeySourceURL, value); }
}
#endregion
}
}

HybridWebView.cs:

using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace WebViewExample.View.Custom
{
public class HybridWebView : WebView
{
Action<string> action;
public static readonly BindableProperty UriProperty = BindableProperty.Create(
propertyName: "Uri",
returnType: typeof(string),
declaringType: typeof(HybridWebView),
defaultValue: default(string));
public string Uri
{
get { return (string)GetValue(UriProperty); }
set { SetValue(UriProperty, value); }
}
public void RegisterAction(Action<string> callback)
{
Debug.WriteLine("Debug - Register Action");
action = callback;
}
public void Cleanup()
{
Debug.WriteLine("Debug - Clear Action");
action = null;
}
public void InvokeAction(string data)
{
Debug.WriteLine("Debug - Invoke Action");
if (action == null || data == null)
{
return;
}
Debug.WriteLine("Debug - Data: " + data.ToString());
action.Invoke(data);
}
}
}

git repo示例:https://github.com/Nitroklas/WebViewDownloadingExample

微软论坛上的相同帖子:https://learn.microsoft.com/en-us/answers/questions/497906/how-to-download-files-like-the-native-browser-with.html

谢谢你对这件事的帮助。我在这个主题上发现的一切都是从2019年或更早的....

的问候Niklas

您可以尝试下面的代码使用自定义渲染器通过WebView下载文件。

[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), 
typeof(UpgradeWebViewRenderer))]
namespace App8.Droid
{
public class UpgradeWebViewRenderer : ViewRenderer<Xamarin.Forms.WebView, global::Android.Webkit.WebView>
{
public UpgradeWebViewRenderer(Context context) : base(context)
{

}
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (this.Control == null)
{
var webView = new global::Android.Webkit.WebView(this.Context);
webView.SetWebViewClient(new WebViewClient());
webView.SetWebChromeClient(new WebChromeClient());
WebSettings webSettings = webView.Settings;
webSettings.JavaScriptEnabled = true;
webView.SetDownloadListener(new CustomDownloadListener());
this.SetNativeControl(webView);
var source = e.NewElement.Source as UrlWebViewSource;
if (source != null)
{
webView.LoadUrl(source.Url);
}
}
}
}
public class CustomDownloadListener : Java.Lang.Object, IDownloadListener
{
public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength)
{
DownloadManager.Request request = new DownloadManager.Request(Android.Net.Uri.Parse(url));
request.AllowScanningByMediaScanner();
request.SetNotificationVisibility(DownloadVisibility.VisibleNotifyCompleted);
request.SetDestinationInExternalFilesDir(Forms.Context, Android.OS.Environment.DirectoryDownloads, "hello.jpg");
DownloadManager dm = (DownloadManager)Android.App.Application.Context.GetSystemService(Android.App.Application.DownloadService);
dm.Enqueue(request);
}
}
}

最新更新