【发布时间】:2021-10-05 03:16:43
【问题描述】:
我想下载任何在我的应用中实现了 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.xaml.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
感谢您在此问题上的任何帮助。 我在这个主题上找到的所有内容都来自 2019 年或更早......
问候 尼克拉斯
【问题讨论】:
-
请在发帖前阅读How to Ask。您的问题应包含帖子中的所有相关信息,而不是指向外部存储库的链接。
-
这基本上就是重现此代码所需的所有代码。可以在 iOS 上下载和查看 pdf。 Android 上的下载仅适用于默认浏览器,但不适用于 WebView。
-
在 Android 上,无限循环:它是否会多次执行您的某些代码?如果不是,它会“卡”在哪一行代码上/永远不会返回?
-
你好@ToolmakerSteve,我正在谈论的循环是加载指示器,它向我显示 webview 的导航事件仍在运行,或者另一方面导航事件尚未触发并且从从看这个屏幕开始大约 5-10 分钟,它可能永远不会。
-
所以
HybridWebView_Navigating运行,包括hybridWebView.Source.SetValue(UrlWebViewSource.UrlProperty, nextURL);行?但是HybridWebView_Navigated永远不会运行?
标签: android xamarin xamarin.forms webview xamarin.android