如何在 Android 上使用 Xamarin WebView 下载类似本机浏览器的文件? [英] How to download files like the native browser with Xamarin WebView on Android?

查看:29
本文介绍了如何在 Android 上使用 Xamarin WebView 下载类似本机浏览器的文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I would like to download any kind of file with the WebView implemented in my app. On iOS I noticed that the WebView can mostly only show the file inside itself. On Android, the WebView is somehow caught in a loop or in the loading process. It probably tries to download the file, but can't. The native behavior for iOS, so Safari -> show the pdf, doc or html in the WebView. The native behavior for Android, i.e. Chrome -> download everything and then try to view it with the right app when trying to open it after download or open it right after download (tested on Huawei P30 Pro with Android 11.0.0.153).

为什么我的 WebView 无法做到这一点.有人能帮我解决这个问题吗?

Why is my WebView not able to do that. Can anyone help me with this?

我不想在 Android 的资源中创建自定义布局,我不能采用 Android 的 git 示例中实现的方法,因为它会由于会话劫持而在我的网站上被阻止.如果您想看到 android WebView 无限加载,只需在 MainPage.xaml.cs 上的if"子句中注释所有内容:

I don't want to create a custom layout in the resources for Android and I can't take the method implemented in the git example for Android because it would be blocked on my website due to session hyjacking. If you want to see the android WebView endless loading just comment everything in this "if"-clause on the MainPage.xaml.cs:

if (Device.RuntimePlatform.Equals(Device.Android))

MainPage.xaml:

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:

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:

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:

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:

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

The git repo example: https://github.com/Nitroklas/WebViewDownloadingExample

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

Same post on the microsoft forum: https://docs.microsoft.com/en-us/answers/questions/497906/how-to-download-files-like-the-native-browser-with.html

感谢您对此事的任何帮助.我在这个主题上找到的所有内容都来自 2019 年或更早......

Thanks for any help on this matter. Everything I have found on this topic is from 2019 or older ....

问候尼古拉斯

推荐答案

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

You could try the code below to use the custom renderer to download file via 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);
    }
}

}

这篇关于如何在 Android 上使用 Xamarin WebView 下载类似本机浏览器的文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆