Skip to content
This repository was archived by the owner on May 1, 2024. It is now read-only.

[Android] Fix WebView.Navigating event, make WebViewClient inheritable #3780

Merged
merged 3 commits into from
Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions Xamarin.Forms.Platform.Android/Renderers/FormsWebViewClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using System;
using System.Collections.Generic;
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;

namespace Xamarin.Forms.Platform.Android
{
public class FormsWebViewClient : WebViewClient
{
WebNavigationResult _navigationResult = WebNavigationResult.Success;
WebViewRenderer _renderer;

public FormsWebViewClient(WebViewRenderer renderer)
{
if (renderer == null)
throw new ArgumentNullException("renderer");
_renderer = renderer;
}

protected FormsWebViewClient(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{

}

public override void OnPageStarted(global::Android.Webkit.WebView view, string url, Bitmap favicon)
{
if (_renderer?.Element == null || url == WebViewRenderer.AssetBaseUrl)
return;

var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);

_renderer.ElementController.SendNavigating(args);
_navigationResult = WebNavigationResult.Success;

_renderer.UpdateCanGoBackForward();

if (args.Cancel)
{
_renderer.Control.StopLoading();
}
else
{
base.OnPageStarted(view, url, favicon);
}
}

public override void OnPageFinished(global::Android.Webkit.WebView view, string url)
{
if (_renderer?.Element == null || url == WebViewRenderer.AssetBaseUrl)
return;

var source = new UrlWebViewSource { Url = url };
_renderer.IgnoreSourceChanges = true;
_renderer.ElementController.SetValueFromRenderer(WebView.SourceProperty, source);
_renderer.IgnoreSourceChanges = false;

var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, _navigationResult);

_renderer.ElementController.SendNavigated(args);

_renderer.UpdateCanGoBackForward();

base.OnPageFinished(view, url);
}

[Obsolete("OnReceivedError is obsolete as of version 2.3.0. This method was deprecated in API level 23.")]
public override void OnReceivedError(global::Android.Webkit.WebView view, ClientError errorCode, string description, string failingUrl)
{
_navigationResult = WebNavigationResult.Failure;
if (errorCode == ClientError.Timeout)
_navigationResult = WebNavigationResult.Timeout;
#pragma warning disable 618
base.OnReceivedError(view, errorCode, description, failingUrl);
#pragma warning restore 618
}

public override void OnReceivedError(global::Android.Webkit.WebView view, IWebResourceRequest request, WebResourceError error)
{
_navigationResult = WebNavigationResult.Failure;
if (error.ErrorCode == ClientError.Timeout)
_navigationResult = WebNavigationResult.Timeout;
base.OnReceivedError(view, request, error);
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_renderer = null;
}
}
}
103 changes: 20 additions & 83 deletions Xamarin.Forms.Platform.Android/Renderers/WebViewRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@ namespace Xamarin.Forms.Platform.Android
{
public class WebViewRenderer : ViewRenderer<WebView, AWebView>, IWebViewDelegate
{
bool _ignoreSourceChanges;
public const string AssetBaseUrl = "file:///android_asset/";

WebViewClient _webViewClient;
FormsWebChromeClient _webChromeClient;

IWebViewController ElementController => Element;
protected internal IWebViewController ElementController => Element;
protected internal bool IgnoreSourceChanges { get; set; }

public WebViewRenderer(Context context) : base(context)
{
Expand All @@ -33,7 +36,7 @@ public WebViewRenderer()

public void LoadHtml(string html, string baseUrl)
{
Control.LoadDataWithBaseURL(baseUrl == null ? "file:///android_asset/" : baseUrl, html, "text/html", "UTF-8", null);
Control.LoadDataWithBaseURL(baseUrl ?? AssetBaseUrl, html, "text/html", "UTF-8", null);
}

public void LoadUrl(string url)
Expand All @@ -47,19 +50,25 @@ protected override void Dispose(bool disposing)
{
if (Element != null)
{
if (Control != null)
Control.StopLoading();
Control?.StopLoading();

ElementController.EvalRequested -= OnEvalRequested;
ElementController.GoBackRequested -= OnGoBackRequested;
ElementController.GoForwardRequested -= OnGoForwardRequested;

_webViewClient?.Dispose();
_webChromeClient?.Dispose();
}
}

base.Dispose(disposing);
}

protected virtual WebViewClient GetWebViewClient()
{
return new FormsWebViewClient(this);
}

protected virtual FormsWebChromeClient GetFormsWebChromeClient()
{
return new FormsWebChromeClient();
Expand All @@ -85,7 +94,9 @@ protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
#pragma warning disable 618 // This can probably be replaced with LinearLayout(LayoutParams.MatchParent, LayoutParams.MatchParent); just need to test that theory
webView.LayoutParameters = new global::Android.Widget.AbsoluteLayout.LayoutParams(LayoutParams.MatchParent, LayoutParams.MatchParent, 0, 0);
#pragma warning restore 618
webView.SetWebViewClient(new WebClient(this));

_webViewClient = GetWebViewClient();
webView.SetWebViewClient(_webViewClient);

_webChromeClient = GetFormsWebChromeClient();
_webChromeClient.SetContext(Context as Activity);
Expand Down Expand Up @@ -136,11 +147,10 @@ protected override void OnElementPropertyChanged(object sender, PropertyChangedE

void Load()
{
if (_ignoreSourceChanges)
if (IgnoreSourceChanges)
return;

if (Element.Source != null)
Element.Source.Load(this);
Element.Source?.Load(this);

UpdateCanGoBackForward();
}
Expand Down Expand Up @@ -175,7 +185,7 @@ void OnGoForwardRequested(object sender, EventArgs eventArgs)
UpdateCanGoBackForward();
}

void UpdateCanGoBackForward()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this should be protected at best.

protected internal void UpdateCanGoBackForward()
{
if (Element == null || Control == null)
return;
Expand All @@ -191,79 +201,6 @@ void UpdateMixedContentMode()
}
}

class WebClient : WebViewClient
{
WebNavigationResult _navigationResult = WebNavigationResult.Success;
WebViewRenderer _renderer;

public WebClient(WebViewRenderer renderer)
{
if (renderer == null)
throw new ArgumentNullException("renderer");
_renderer = renderer;
}

public override void OnPageFinished(AWebView view, string url)
{
if (_renderer.Element == null || url == "file:///android_asset/")
return;

var source = new UrlWebViewSource { Url = url };
_renderer._ignoreSourceChanges = true;
_renderer.ElementController.SetValueFromRenderer(WebView.SourceProperty, source);
_renderer._ignoreSourceChanges = false;

var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, _navigationResult);

_renderer.ElementController.SendNavigated(args);

_renderer.UpdateCanGoBackForward();

base.OnPageFinished(view, url);
}

[Obsolete("OnReceivedError is obsolete as of version 2.3.0. This method was deprecated in API level 23.")]
public override void OnReceivedError(AWebView view, ClientError errorCode, string description, string failingUrl)
{
_navigationResult = WebNavigationResult.Failure;
if (errorCode == ClientError.Timeout)
_navigationResult = WebNavigationResult.Timeout;
#pragma warning disable 618
base.OnReceivedError(view, errorCode, description, failingUrl);
#pragma warning restore 618
}

public override void OnReceivedError(AWebView view, IWebResourceRequest request, WebResourceError error)
{
_navigationResult = WebNavigationResult.Failure;
if (error.ErrorCode == ClientError.Timeout)
_navigationResult = WebNavigationResult.Timeout;
base.OnReceivedError(view, request, error);
}

[Obsolete]
public override bool ShouldOverrideUrlLoading(AWebView view, string url)
{
if (_renderer.Element == null)
return true;

var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);

_renderer.ElementController.SendNavigating(args);
_navigationResult = WebNavigationResult.Success;

_renderer.UpdateCanGoBackForward();
return args.Cancel;
}

protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_renderer = null;
}
}

class JavascriptResult : Java.Lang.Object, IValueCallback
{
TaskCompletionSource<string> source;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@
<Compile Include="GetDesiredSizeDelegate.cs" />
<Compile Include="IDeviceInfoProvider.cs" />
<Compile Include="ITabStop.cs" />
<Compile Include="Renderers\FormsWebViewClient.cs" />
<Compile Include="Renderers\IImageViewHandler.cs" />
<Compile Include="InnerGestureListener.cs" />
<Compile Include="InnerScaleListener.cs" />
Expand Down