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

Conversation

Axemasta
Copy link

@Axemasta Axemasta commented Apr 9, 2021

Description of Change

WebView's Navigating event does not allow for async code to be executed to determine whether to cancel the navigation. The implementation creates a race condition and makes the cancellation functionality confusing, the following code will not cancel the WebView navigation event:

public MainPage()
{
    WebView.Navigating += async (s, e) =>
    {
        await Task.Delay(2000);

        e.Cancel = true;
    };
}

This makes it impossible to delay navigation in a WebView whilst doing a check such as seeing if the user can navigate to a url, without writing a hacky workaround ontop of this behaviour.

I make a first attempt at this PR in November and it was suggested by @PureWeen to refactor the code to use a DeferralToken, used by Shell to achieve the functionality (old pr: #12756). I've made a new PR since I made a completely new branch.

Issues Resolved

API Changes

Added:

  • Added DeferralToken, DeferralTokenEventArgs

Changed:

  • Renamed ShellDeferralToken => DeferralToken
  • Removed deferral token functionality from ShellNavigatingArgs into DeferrableEventArgs
  • WebViewNavigatingArgs now inherit from DeferralTokenEventArgs
  • WKWebViewRenderer now uses the deferral token to handle navigation decisions

New API Usage:

WebView.Navigating += async (s, e) =>
{
    var token = e.GetDeferral();

    await Task.Delay(2000);

    var shouldCancel = CanBrowseUrl(e.Url);

    if (shouldCancel)
        e.Cancel();

    token.Complete();
};

Platforms Affected

  • Core / All
  • iOS Currently

Behavioral/Visual Changes

This needs to be discussed but it would break and app using WebViewNavigatingArgs.Cancel to cancel navigation. I did slap an Obsolete attribute onto the property (and rename to OldCancel whilst the PR is work in progress, but it causes the control gallery to fail building. Maybe it can be added back when the PR is good to go & i go back through the control gallery and change all references to deferral.

Before/After Screenshots

Not applicable

Testing Procedure

  • Open the file Xamarin.Forms.Controls.Issues.Shared.Issue12720.xaml.cs
  • You will find 3 event handlers in the constructor, for each event (only ever comment 1 in)
  • Comment in the constructor, comment out the others
  • Run the Control Gallery app
  • Go to Test Cases
  • Find issue G12720
  • Use the web browser:

OnNavigatingWithoutDeferral
No impact to browser

OnNavigatingWithDeferral
User can't browse to any sites containing bbc.co.uk such as:

  • https://www.bbc.co.uk/news/

OnNavigatingWithDeferralAsync
All navigation occurs normally unless the user attempts to browse to any sites containing bbc.co.uk such as:

  • https://www.bbc.co.uk/news/

Requests to this site will be evaluated with a task that increases in duration, and always get cancelled

Todo Before Merge

I've put this PR up to discuss the refactors I've made with the team before committing more time, this PR should be marked as do not merge until all work has been completed.

  • Ensure Shell functioning correctly (affected by deferral refactor)
  • Update Android WebViewRenderer
  • Update GTK WebViewRenderer
  • Update macOS WebViewRenderer
  • Update Tizen WebViewRenderer
  • Update WPF WebViewRenderer
  • Move code from deferral folder to appropriate place (I'm using that folder to keep organised in my work, I'm not very used to working in a codebase with so little folders 😖 )
  • Remove mfractor from git ignore (otherwise git tried to commit about 50 files)
  • Cleanup WebNavigationArgs (base class or interface):
    To get my code working I ended up changing the base class to DeferrableEventArgs, I added an interface for the WebNavigationArgs, we need to discuss what you would like to see about this. I'd personally prefer the interface.

PR Checklist

  • Targets the correct branch
  • Tests are passing (or failures are unrelated)

Axemasta added 6 commits April 5, 2021 18:06
Makes it alot easier to work in this repository :)
Added the issue PR to the control gallery, mainly so I can work on the control and have a fast reference
Added some sample code for the control gallery issue page. Once implemented the async method can be updated
Refactored shell deferral into seperate code so that it can be shared with webview navigating. Shell tests are still passing but more testing required. Fingers crossed the cross platform work is done and all I need to do is update platform implementations
Updated WKWebViewRenderer to use the deferral token as opposed to the event args Cancel property. This seems to be working for all scenarios: No deferral, Sync deferral, async deferral
}
else
{
if (args.DeferralRequested)
Copy link
Author

Choose a reason for hiding this comment

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

i've made this change to make the code more readable

@@ -22,6 +22,7 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Xaml\Diagnostics\" />
<Folder Include="Deferral\" />
Copy link
Author

Choose a reason for hiding this comment

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

Need to remove before a merge

@Axemasta Axemasta marked this pull request as draft April 9, 2021 14:39
@Axemasta
Copy link
Author

Axemasta commented Apr 9, 2021

@PureWeen I've finally got around to putting this PR up with your suggestions. What are your thoughts on how this is implemented?

Since these are technically breaking API changes would this be rejected as part of 5.0.0?

@Axemasta Axemasta marked this pull request as ready for review April 13, 2021 15:04
@Axemasta
Copy link
Author

Axemasta commented Jun 3, 2021

Will this PR be addressed? How much effort would it be to fork the control & ship it as a seperate control (ie WebView2)?

@Axemasta
Copy link
Author

I went ahead and completely forked this control. I've implemented the deferral token stuff so the navigating event is able to cancel navigation from a background thread! Introducing SuperWebView.

I'll keep this PR open because ideally everything I've done in my custom control should come standard with WebView 😁

@jfversluis
Copy link
Member

Hey Alex! You did a totally amazing job, sorry that it didn't get the attention it deserved. I think with a couple of API changes and the size of this PR it's not feasible anymore to merge this for Forms. Would you maybe be willing to bring this to .NET MAUI? I promise we will do a better job there!

Thank you so much for all the time and effort here, although it doesn't show, we really appreciate it!

@jfversluis jfversluis closed this Jul 11, 2022
@Axemasta
Copy link
Author

@jfversluis thanks for the update, I realised quite early into Forms 5 that this PR would never be able to make its way into Xamarin due to the sunsetting of XF & the no api breaks policy in version 5, that is precisely why I forked the control and rolled my "own" implementation of it in my SuperWebView package since I had a project that desperately needed the functionality (it's been in production since for over a year and works flawlessly).

Its definitely something I want to bring into Maui, I made a PR with the changes a bit too early in Maui (Before the WebView handler was implemented). I've been waiting for the right time because for now the Maui team seem very busy getting the .Net 7 GA version out. A little disappointed we couldn't make the change before a GA release and this is the perfect time for Api breaks!

There will be a PR coming soon, my issue and PR on the Maui repo have no interaction from anyone so I've been a little hesitant to put in the work if it goes unnoticed :(

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Bug] WebView Navigating Race Condition
3 participants