[Android] Fixes cancel Webview Navigation (#5458) fixes #4891 fixes #4919 closes #5460

* [Android] Fixes cancel Webview Navigation

* - added fix 4891
- refactoring

* Fix obsolete message

Co-authored-by: Ralph Brackert <brackert@baselineconnect.com>
This commit is contained in:
Pavel Yakovlev 2019-03-19 23:05:38 +03:00 коммит произвёл Rui Marinho
Родитель c2752977d4
Коммит 6a3a10afea
5 изменённых файлов: 221 добавлений и 35 удалений

Просмотреть файл

@ -0,0 +1,105 @@
using System;
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
#if UITEST
using Xamarin.Forms.Core.UITests;
using Xamarin.UITest;
using NUnit.Framework;
#endif
namespace Xamarin.Forms.Controls.Issues
{
#if UITEST
[Category(UITestCategories.ManualReview)]
#endif
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 4891, "[Android] WebView Navigating Cancel property not working with custom scheme", PlatformAffected.Android)]
public class Issue4891 : TestContentPage // or TestMasterDetailPage, etc ...
{
Button _back;
WebView _myWebView;
Label _log;
ScrollView _logScrollView;
protected override void Init()
{
_back = new Button
{
Text = "Back"
};
_back.Clicked += Back_Clicked;
_myWebView = new WebView
{
HorizontalOptions = LayoutOptions.StartAndExpand,
VerticalOptions = LayoutOptions.Start,
HeightRequest = 240
};
_myWebView.Navigating += MyWebView_Navigating;
_myWebView.Navigated += MyWebView_Navigated;
_myWebView.Source = new HtmlWebViewSource()
{
Html = "<html><body>Click on the link below. Expected results:<br/>1. Navigating event logged.<br/>2. Navigated event NOT logged.<br/>3. This page stays loaded in the WebView control.<br/><br/><a href='xamforms4223://custom'>Navigate to Custom xamforms4223 scheme</a></body></html>"
};
_log = new Label
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Text = ""
};
_logScrollView = new ScrollView
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Content = _log
};
Content = new StackLayout
{
Children =
{
_myWebView,
_back,
_logScrollView
}
};
}
void MyWebView_Navigating(object sender, WebNavigatingEventArgs e)
{
LogToScreen($"Navigating: {e.Url}");
if (e.Url.StartsWith("xamforms4223", StringComparison.OrdinalIgnoreCase))
{
LogToScreen("Caught custom scheme, cancelling navigation.");
e.Cancel = true;
}
}
void MyWebView_Navigated(object sender, WebNavigatedEventArgs e)
{
LogToScreen($"Navigated: ({e.Result}) {e.Url}");
}
void LogToScreen(string text)
{
_log.Text += $"{text}\n";
InvalidateMeasure();
_logScrollView.ScrollToAsync(_log, ScrollToPosition.End, false);
}
void Back_Clicked(object sender, EventArgs e)
{
if (_myWebView.CanGoBack)
{
_myWebView.GoBack();
}
}
}
}

Просмотреть файл

@ -0,0 +1,59 @@
using Xamarin.Forms.CustomAttributes;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Controls.Issues
{
[Preserve(AllMembers = true)]
[Issue(IssueTracker.Github, 4919, "Webview Navigation cancel not working", PlatformAffected.Android)]
public class Issue4919 : TestContentPage // or TestMasterDetailPage, etc ...
{
protected override void Init()
{
var url = "https://www.microsoft.com/";
var cancel = true;
var log = new Label
{
VerticalOptions = LayoutOptions.StartAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Text = ""
};
var webView = new WebView()
{
HorizontalOptions = LayoutOptions.Fill,
VerticalOptions = LayoutOptions.FillAndExpand,
Source = url
};
webView.Navigating += (_, e) =>
{
e.Cancel = cancel;
var resultText = cancel ? "[Canceled]" : "[OK]";
log.Text += $"{resultText} {e.Url}{System.Environment.NewLine}";
};
Content = new StackLayout
{
Children =
{
new Label { Text = "WebView must be empty on init" },
webView,
new Button
{
Text = "Go to github",
Command = new Command(() => webView.Source = "https://github.com/xamarin/Xamarin.Forms")
},
new Button
{
Text = "Toggle cancel navigation",
Command = new Command(() => cancel = !cancel)
},
new ScrollView
{
VerticalOptions = LayoutOptions.EndAndExpand,
HorizontalOptions = LayoutOptions.FillAndExpand,
Content = log
}
}
};
}
}
}

Просмотреть файл

@ -14,6 +14,7 @@
<DependentUpon>Bugzilla60787.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)Issue4919.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue5461.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue2102.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue1588.xaml.cs">
@ -133,6 +134,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla37601.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla38105.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue3652.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Issue4891.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla38723.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla38770.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Bugzilla38827.xaml.cs">
@ -1123,4 +1125,4 @@
<Generator>MSBuild:Compile</Generator>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

Просмотреть файл

@ -1,17 +1,9 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.Graphics;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Webkit;
using Android.Widget;
using WView = Android.Webkit.WebView;
namespace Xamarin.Forms.Platform.Android
{
@ -19,42 +11,50 @@ namespace Xamarin.Forms.Platform.Android
{
WebNavigationResult _navigationResult = WebNavigationResult.Success;
WebViewRenderer _renderer;
string _lastUrlNavigatedCancel;
public FormsWebViewClient(WebViewRenderer renderer)
{
if (renderer == null)
throw new ArgumentNullException("renderer");
_renderer = renderer;
}
=> _renderer = renderer ?? throw new ArgumentNullException("renderer");
protected FormsWebViewClient(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}
public override void OnPageStarted(global::Android.Webkit.WebView view, string url, Bitmap favicon)
bool SendNavigatingCanceled(string url) => _renderer?.SendNavigatingCanceled(url) ?? true;
[Obsolete("ShouldOverrideUrlLoading(view,url) is obsolete as of version 4.0.0. This method was deprecated in API level 24.")]
[EditorBrowsable(EditorBrowsableState.Never)]
// api 19-23
public override bool ShouldOverrideUrlLoading(WView view, string url)
=> SendNavigatingCanceled(url);
// api 24+
public override bool ShouldOverrideUrlLoading(WView view, IWebResourceRequest request)
=> SendNavigatingCanceled(request?.Url?.ToString());
public override void OnPageStarted(WView view, string url, Bitmap favicon)
{
if (_renderer?.Element == null || url == WebViewRenderer.AssetBaseUrl)
if (_renderer == null || string.IsNullOrWhiteSpace(url) || url == WebViewRenderer.AssetBaseUrl)
return;
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
var cancel = false;
if (!url.Equals(_renderer.UrlCanceled, StringComparison.OrdinalIgnoreCase))
cancel = SendNavigatingCanceled(url);
_renderer.UrlCanceled = null;
_renderer.ElementController.SendNavigating(args);
_navigationResult = WebNavigationResult.Success;
_renderer.UpdateCanGoBackForward();
if (args.Cancel)
if (cancel)
{
_renderer.Control.StopLoading();
_navigationResult = WebNavigationResult.Cancel;
view.StopLoading();
}
else
{
_navigationResult = WebNavigationResult.Success;
base.OnPageStarted(view, url, favicon);
}
}
public override void OnPageFinished(global::Android.Webkit.WebView view, string url)
public override void OnPageFinished(WView view, string url)
{
if (_renderer?.Element == null || url == WebViewRenderer.AssetBaseUrl)
return;
@ -64,9 +64,14 @@ namespace Xamarin.Forms.Platform.Android
_renderer.ElementController.SetValueFromRenderer(WebView.SourceProperty, source);
_renderer.IgnoreSourceChanges = false;
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, _navigationResult);
bool navigate = _navigationResult == WebNavigationResult.Failure ? !url.Equals(_lastUrlNavigatedCancel, StringComparison.OrdinalIgnoreCase) : true;
_lastUrlNavigatedCancel = _navigationResult == WebNavigationResult.Cancel ? url : null;
_renderer.ElementController.SendNavigated(args);
if (navigate)
{
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, _navigationResult);
_renderer.ElementController.SendNavigated(args);
}
_renderer.UpdateCanGoBackForward();
@ -75,7 +80,7 @@ namespace Xamarin.Forms.Platform.Android
[Obsolete("OnReceivedError is obsolete as of version 2.3.0. This method was deprecated in API level 23.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override void OnReceivedError(global::Android.Webkit.WebView view, ClientError errorCode, string description, string failingUrl)
public override void OnReceivedError(WView view, ClientError errorCode, string description, string failingUrl)
{
_navigationResult = WebNavigationResult.Failure;
if (errorCode == ClientError.Timeout)
@ -85,7 +90,7 @@ namespace Xamarin.Forms.Platform.Android
#pragma warning restore 618
}
public override void OnReceivedError(global::Android.Webkit.WebView view, IWebResourceRequest request, WebResourceError error)
public override void OnReceivedError(WView view, IWebResourceRequest request, WebResourceError error)
{
_navigationResult = WebNavigationResult.Failure;
if (error.ErrorCode == ClientError.Timeout)
@ -100,4 +105,4 @@ namespace Xamarin.Forms.Platform.Android
_renderer = null;
}
}
}
}

Просмотреть файл

@ -1,9 +1,7 @@
using System;
using System.ComponentModel;
using Android.App;
using Android.Content;
using Android.Webkit;
using Android.Widget;
using Android.OS;
using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
using Xamarin.Forms.Internals;
@ -22,6 +20,7 @@ namespace Xamarin.Forms.Platform.Android
protected internal IWebViewController ElementController => Element;
protected internal bool IgnoreSourceChanges { get; set; }
protected internal string UrlCanceled { get; set; }
public WebViewRenderer(Context context) : base(context)
{
@ -42,7 +41,23 @@ namespace Xamarin.Forms.Platform.Android
public void LoadUrl(string url)
{
Control.LoadUrl(url);
if (!SendNavigatingCanceled(url))
Control.LoadUrl(url);
}
protected internal bool SendNavigatingCanceled(string url)
{
if (Element == null || string.IsNullOrWhiteSpace(url))
return true;
if (url == AssetBaseUrl)
return false;
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
ElementController.SendNavigating(args);
UpdateCanGoBackForward();
UrlCanceled = args.Cancel ? null : url;
return args.Cancel;
}
protected override void Dispose(bool disposing)