本文讨论UWP和Xamarin上面各种WebVeiw和各种HttpClient的Cookies问题。

UWP上原生WebView,Xamarin.Forms WebView和Windows.Web.Http.HttpClient共享Cookies,它们的Cookies可通过new Windows.Web.Http.Filters.HttpBaseProtocolFilter().CookieManager访问

Xamarin.iOS:UIWebView,WKWebView,NSUrlSession以及Xamarin.Forms WebView共享Cookies,可通过Foundation.NSHttpCookieStorage.SharedStorage来访问。

Xamarin.Android:原生WebView以及Xamarin.Forms WebView的Cookies可通过Android.Webkit.CookieManager.Instance访问。

System.Net.Http.HttpClient拥有独立的Cookies,它不与任何其他东西,包括UWP和Xamarin.Forms上的WebView,或者另一个HttpClient实例共享Cookies。一个普通的HttpClient并不能直接执行Cookies操作,需要通过如下方式声明HttpClient才能暴露其CookieContainer,并对其Cookies进行操作。

var cookieContainer = new CookieContainer();
var handler = new HttpClientHandler()
{
    CookieContainer = cookieContainer
};
var httpClient = new HttpClient(handler);

从三大平台WebView中复制Cookies到CookieContainer的代码如下。由于CookieContainer操作Cookies需要指定地址,所以你需要在baseUrlString放置需要复制Cookies的网站地址。通过这个函数,可以实现使用WebView登录之后,使用HttpClient来访问需要登录的内容。

private void CopyCookies()
{
    var baseUri = new Uri(baseUrlString);
#if WINDOWS_UWP
    var filter = new Windows.Web.Http.Filters.HttpBaseProtocolFilter();
    var cookies = filter.CookieManager.GetCookies(baseUri);
    foreach (var item in cookies)
    {
        cookieContainer.SetCookies(baseUri, $"{item.Name}={item.Value}");
    }
#endif
#if __ANDROID__
    var cookieManager = global::Android.Webkit.CookieManager.Instance;
    var cookie = cookieManager.GetCookie(baseUrlString);
    cookieContainer.SetCookies(baseUri, cookie.Replace(';', ','));
#endif
#if __IOS__
    var nsUrl = new Foundation.NSUrl(baseUrlString);
    foreach (var item in Foundation.NSHttpCookieStorage.SharedStorage.CookiesForUrl(nsUrl))
    {
        cookieContainer.SetCookies(baseUri, $"{item.Name}={item.Value}");
    }
#endif
}