Skip to content

Commit

Permalink
Change Windows WebView Cookies to CoreWebView2 (#13518)
Browse files Browse the repository at this point in the history
* Change Windows WebView Cookies to CoreWebView2

* Added testing sample

* Update WebViewPage.xaml.cs

* Update WebViewHandler.Windows.cs

* Add sync cookies to Windows

* Update WebViewHandler.Windows.cs

* Apply suggestions from code review

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>

* Update WebViewHandler.Windows.cs

---------

Co-authored-by: Manuel de la Pena <mandel@microsoft.com>
  • Loading branch information
jfversluis and mandel-macaque authored Mar 9, 2023
1 parent 20f54bc commit ae20455
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@
</HtmlWebViewSource>
</WebView.Source>
</WebView>
<StackLayout
Orientation="Horizontal">
<HorizontalStackLayout>
<Entry
x:Name="input"
WidthRequest="150"
Expand All @@ -70,9 +69,8 @@
Clicked="OnLoadHtmlFileClicked"
HeightRequest="48"
WidthRequest="150" />
</StackLayout>
<StackLayout
Orientation="Horizontal">
</HorizontalStackLayout>
<HorizontalStackLayout>
<Entry
x:Name="userAgent"
Text="{Binding UserAgent, Source={x:Reference FileWebView}}"
Expand All @@ -84,7 +82,7 @@
Clicked="OnSetUserAgentClicked"
HeightRequest="48"
WidthRequest="150" />
</StackLayout>
</HorizontalStackLayout>
<Label
Text="UrlWebViewSource"
Style="{StaticResource Headline}"/>
Expand Down Expand Up @@ -127,10 +125,19 @@
x:Name="EvalResultLabel"
Text="..."
Style="{StaticResource Headline}"/>
<Label
Text="HTML5 Video"
Style="{StaticResource Headline}"/>
<Button
Text="Load HTML5 Video"
Clicked="OnLoadHtml5VideoClicked" />
<StackLayout
<Label
Text="Cookies"
Style="{StaticResource Headline}"/>
<Button
Text="Load httpbin.org with Cookies"
Clicked="OnLoadHttpBinClicked" />
<VerticalStackLayout
IsVisible="{OnPlatform Android=True, Default=False}">
<Label
Text="Platform Specifics"
Expand All @@ -141,7 +148,7 @@
<Button
Text="Enable Zoom Controls"
Clicked="OnEnableZoomControlsClicked"/>
</StackLayout>
</VerticalStackLayout>
</VerticalStackLayout>
</ScrollView>
</views:BasePage.Content>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,5 +120,15 @@ void OnLoadHtml5VideoClicked(object sender, EventArgs e)
{
MauiWebView.Source = new UrlWebViewSource { Url = "video.html" };
}

void OnLoadHttpBinClicked(object sender, EventArgs e)
{
// on httpbin.org find the section where you can load the cookies for the website.
// The cookie that is set below should show up for this to succeed.
MauiWebView.Cookies = new System.Net.CookieContainer();
MauiWebView.Cookies.Add(new System.Net.Cookie("MauiCookie", "Hmmm Cookies!", "/", "httpbin.org"));

MauiWebView.Source = new UrlWebViewSource { Url = "https://httpbin.org/#/Cookies/get_cookies" };
}
}
}
71 changes: 35 additions & 36 deletions src/Core/src/Handlers/WebView/WebViewHandler.Windows.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,20 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.Web.WebView2.Core;
using Windows.Web.Http;

namespace Microsoft.Maui.Handlers
{
public partial class WebViewHandler : ViewHandler<IWebView, WebView2>
{
WebNavigationEvent _eventState;
readonly HashSet<string> _loadedCookies = new HashSet<string>();
readonly HashSet<string> _loadedCookies = new();
Window? _window;

protected override WebView2 CreatePlatformView() => new MauiWebView();
protected override WebView2 CreatePlatformView() => new MauiWebView(this);

internal WebNavigationEvent CurrentNavigationEvent
{
Expand All @@ -34,7 +34,7 @@ protected override void ConnectHandler(WebView2 platformView)
platformView.Loaded += OnWebViewLoaded;
}

void OnWebViewLoaded(object sender, UI.Xaml.RoutedEventArgs e)
void OnWebViewLoaded(object sender, RoutedEventArgs e)
{
OnLoaded();
}
Expand All @@ -45,7 +45,7 @@ void OnLoaded()
_window.Closed += OnWindowClosed;
}

private void OnWindowClosed(object sender, UI.Xaml.WindowEventArgs args)
private void OnWindowClosed(object sender, WindowEventArgs args)
{
Disconnect(PlatformView);
}
Expand Down Expand Up @@ -178,11 +178,11 @@ void NavigationFailed(CoreWebView2 sender, CoreWebView2NavigationCompletedEventA
SendNavigated(uri, CurrentNavigationEvent, WebNavigationResult.Failure);
}

void SendNavigated(string url, WebNavigationEvent evnt, WebNavigationResult result)
async void SendNavigated(string url, WebNavigationEvent evnt, WebNavigationResult result)
{
if (VirtualView is not null)
{
SyncPlatformCookiesToVirtualView(url);
await SyncPlatformCookiesToVirtualView(url);

VirtualView.Navigated(evnt, url, result);
PlatformView?.UpdateCanGoBackForward(VirtualView);
Expand All @@ -191,7 +191,7 @@ void SendNavigated(string url, WebNavigationEvent evnt, WebNavigationResult resu
CurrentNavigationEvent = WebNavigationEvent.NewPage;
}

void SyncPlatformCookiesToVirtualView(string url)
async Task SyncPlatformCookiesToVirtualView(string url)
{
var myCookieJar = VirtualView.Cookies;

Expand All @@ -204,10 +204,9 @@ void SyncPlatformCookiesToVirtualView(string url)
return;

var cookies = myCookieJar.GetCookies(uri);
var retrieveCurrentWebCookies = GetCookiesFromPlatformStore(url);
var retrieveCurrentWebCookies = await GetCookiesFromPlatformStore(url);

var filter = new global::Windows.Web.Http.Filters.HttpBaseProtocolFilter();
var platformCookies = filter.CookieManager.GetCookies(uri);
var platformCookies = await PlatformView.CoreWebView2.CookieManager.GetCookiesAsync(uri.AbsoluteUri);

foreach (Cookie cookie in cookies)
{
Expand All @@ -220,10 +219,10 @@ void SyncPlatformCookiesToVirtualView(string url)
cookie.Value = httpCookie.Value;
}

SyncPlatformCookies(url);
await SyncPlatformCookies(url);
}

void SyncPlatformCookies(string url)
internal async Task SyncPlatformCookies(string url)
{
var uri = CreateUriForCookies(url);

Expand All @@ -235,35 +234,30 @@ void SyncPlatformCookies(string url)
if (myCookieJar is null)
return;

InitialCookiePreloadIfNecessary(url);
await InitialCookiePreloadIfNecessary(url);
var cookies = myCookieJar.GetCookies(uri);

if (cookies is null)
return;

var retrieveCurrentWebCookies = GetCookiesFromPlatformStore(url);

var filter = new global::Windows.Web.Http.Filters.HttpBaseProtocolFilter();
var retrieveCurrentWebCookies = await GetCookiesFromPlatformStore(url);

foreach (Cookie cookie in cookies)
{
HttpCookie httpCookie = new HttpCookie(cookie.Name, cookie.Domain, cookie.Path)
{
Value = cookie.Value
};
filter.CookieManager.SetCookie(httpCookie, false);
var createdCookie = PlatformView.CoreWebView2.CookieManager.CreateCookie(cookie.Name, cookie.Value, cookie.Domain, cookie.Path);
PlatformView.CoreWebView2.CookieManager.AddOrUpdateCookie(createdCookie);
}

foreach (HttpCookie cookie in retrieveCurrentWebCookies)
foreach (CoreWebView2Cookie cookie in retrieveCurrentWebCookies)
{
if (cookies[cookie.Name] is not null)
continue;

filter.CookieManager.DeleteCookie(cookie);
PlatformView.CoreWebView2.CookieManager.DeleteCookie(cookie);
}
}

void InitialCookiePreloadIfNecessary(string url)
async Task InitialCookiePreloadIfNecessary(string url)
{
var myCookieJar = VirtualView.Cookies;

Expand All @@ -279,22 +273,29 @@ void InitialCookiePreloadIfNecessary(string url)

if (cookies is not null)
{
var existingCookies = GetCookiesFromPlatformStore(url);
foreach (HttpCookie cookie in existingCookies)
var existingCookies = await GetCookiesFromPlatformStore(url);

if (existingCookies.Count == 0)
return;

foreach (CoreWebView2Cookie cookie in existingCookies)
{
// TODO Ideally we use cookie.ToSystemNetCookie() here, but it's not available for some reason check back later
if (cookies[cookie.Name] is null)
myCookieJar.SetCookies(uri, cookie.ToString());
myCookieJar.SetCookies(uri,
new Cookie(cookie.Name, cookie.Value, cookie.Path, cookie.Domain)
{
Expires = DateTimeOffset.FromUnixTimeMilliseconds((long)cookie.Expires).DateTime,
HttpOnly = cookie.IsHttpOnly,
Secure = cookie.IsSecure,
}.ToString());
}
}
}

HttpCookieCollection GetCookiesFromPlatformStore(string url)
Task<IReadOnlyList<CoreWebView2Cookie>> GetCookiesFromPlatformStore(string url)
{
var uri = CreateUriForCookies(url);
var filter = new global::Windows.Web.Http.Filters.HttpBaseProtocolFilter();
var platformCookies = filter.CookieManager.GetCookies(uri);

return platformCookies;
return PlatformView.CoreWebView2.CookieManager.GetCookiesAsync(url).AsTask();
}

Uri? CreateUriForCookies(string url)
Expand All @@ -318,8 +319,6 @@ HttpCookieCollection GetCookiesFromPlatformStore(string url)
return null;
}



public static void MapEvaluateJavaScriptAsync(IWebViewHandler handler, IWebView webView, object? arg)
{
if (arg is EvaluateJavaScriptAsyncRequest request)
Expand Down
10 changes: 8 additions & 2 deletions src/Core/src/Platform/Windows/MauiWebView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ namespace Microsoft.Maui.Platform
{
public class MauiWebView : WebView2, IWebViewDelegate
{
public MauiWebView()
readonly WeakReference<WebViewHandler> _handler;

public MauiWebView(WebViewHandler handler)
{
ArgumentNullException.ThrowIfNull(handler, nameof(handler));
_handler = new WeakReference<WebViewHandler>(handler);

NavigationStarting += (sender, args) =>
{
// Auto map local virtual app dir host, e.g. if navigating back to local site from a link to an external site
Expand Down Expand Up @@ -127,7 +132,8 @@ public async void LoadUrl(string? url)
uri = new Uri(LocalScheme + url, UriKind.RelativeOrAbsolute);
}

// TODO: Sync Cookies
if (_handler.TryGetTarget(out var handler))
await handler.SyncPlatformCookies(uri.AbsoluteUri);

try
{
Expand Down
2 changes: 2 additions & 0 deletions src/Core/src/PublicAPI/net-windows/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#nullable enable
Microsoft.Maui.Hosting.MauiApp.DisposeAsync() -> System.Threading.Tasks.ValueTask
Microsoft.Maui.Layouts.FlexBasis.Equals(Microsoft.Maui.Layouts.FlexBasis other) -> bool
Microsoft.Maui.Platform.MauiWebView.MauiWebView(Microsoft.Maui.Handlers.WebViewHandler! handler) -> void
Microsoft.Maui.SizeRequest.Equals(Microsoft.Maui.SizeRequest other) -> bool
override Microsoft.Maui.Layouts.FlexBasis.Equals(object? obj) -> bool
override Microsoft.Maui.Layouts.FlexBasis.GetHashCode() -> int
Expand All @@ -19,3 +20,4 @@ static Microsoft.Maui.Platform.WebViewExtensions.UpdateUserAgent(this Microsoft.
Microsoft.Maui.WeakEventManager.HandleEvent(object? sender, object? args, string! eventName) -> void
static Microsoft.Maui.SizeRequest.operator !=(Microsoft.Maui.SizeRequest left, Microsoft.Maui.SizeRequest right) -> bool
static Microsoft.Maui.SizeRequest.operator ==(Microsoft.Maui.SizeRequest left, Microsoft.Maui.SizeRequest right) -> bool
*REMOVED*Microsoft.Maui.Platform.MauiWebView.MauiWebView() -> void

0 comments on commit ae20455

Please sign in to comment.