在 Xamarin Forms 中实现自定义 Webview
Implementing Custom Webview in Xamarin Forms
我是 Xamarin.Forms
的新手,我在 Droid
项目中实现了自定义 Web 视图渲染器。
问题是在 iOS
项目中实现渲染器时,就像 Webview
初始化时没有加载 CSS 和 Javascript。因为它只显示 HTML
没有任何功能的页面。
经过一些研究,我知道我们必须实现 WKWebviewRenderer
并且我们必须在 iOS
中加载 LoadFileUrl
方法,但我仍然无法捕捉到 url 在渲染器中。
任何人都知道如何将以下 Android Renderer
代码实现到 iOS Renderer
??
Droid 项目中的自定义渲染器:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.Droid.WebViewRenderer))]
namespace MyProject.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
private bool isMyCustomWebview = false;
public IWebViewController ElementController => Element;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement.GetType() == typeof(MyCustomWebview))
{
Control.SetWebViewClient(new Callback(this));
isMyCustomWebview = true;
}
else
{
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity));
isMyCustomWebview = false;
}
}
public class Callback : WebViewClient
{
Activity _context;
public Callback(Activity _context)
{
this._context = _context;
}
WebViewRenderer _renderer;
public Callback(WebViewRenderer renderer)
{
_renderer = renderer ?? throw new ArgumentNullException("Renderer");
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Show();
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
_renderer.ElementController.SendNavigating(args);
}
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Dismiss();
var source = new UrlWebViewSource { Url = url };
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);
_renderer.ElementController.SendNavigated(args);
}
}
}
}
}
更新:iOS 项目中的自定义渲染器:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.iOS.WebViewRenderer))]
namespace MyProject.iOS
{
// Xamarin.Forms.Platform.iOS.WebViewRenderer
public class WebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
// webView.LoadFileUrl(url, url);
}
}
}
更新:
以下是我在便携式项目中为 webview 设置源和基础 url 的方式:
var result = await client.PostAsync("/embedded/pay", content);
if (result.IsSuccessStatusCode)
{
var resp = await result.Content.ReadAsStringAsync();
var html = new HtmlWebViewSource
{
Html = resp,
BaseUrl = paymentGatewayUrl
};
//Adding Cookie
CookieContainer cookies = new CookieContainer();
var domain = new Uri(html.BaseUrl).Host;
var cookie = new Cookie
{
Secure = true,
Expired = false,
HttpOnly = false,
Name = "cookie",
Expires = DateTime.Now.AddDays(10),
Domain = domain,
Path = "/"
};
cookies.Add(new Uri(html.BaseUrl), cookie);
webView.Source = html;
}
您可以修改 Custom Renderer 的代码,如下所示。
[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace xxx.iOS
{
public class MyWebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
//webView.LoadFileUrl();
}
}
}
iOS 渲染器:
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(WebView), typeof(MyNamespace.iOS.MyWebViewRenderer))]
namespace MyNamespace.iOS
{
//WkWebViewRenderer inherits from WKWebView
public class MyWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
WKWebView wkWebView = this;
wkWebView.NavigationDelegate = new MyNavigationDelegate(); //not shown here
}
}
}
}
我是 Xamarin.Forms
的新手,我在 Droid
项目中实现了自定义 Web 视图渲染器。
问题是在 iOS
项目中实现渲染器时,就像 Webview
初始化时没有加载 CSS 和 Javascript。因为它只显示 HTML
没有任何功能的页面。
经过一些研究,我知道我们必须实现 WKWebviewRenderer
并且我们必须在 iOS
中加载 LoadFileUrl
方法,但我仍然无法捕捉到 url 在渲染器中。
任何人都知道如何将以下 Android Renderer
代码实现到 iOS Renderer
??
Droid 项目中的自定义渲染器:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.Droid.WebViewRenderer))]
namespace MyProject.Droid
{
public class WebViewRenderer : Xamarin.Forms.Platform.Android.WebViewRenderer
{
private bool isMyCustomWebview = false;
public IWebViewController ElementController => Element;
protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.WebView> e)
{
base.OnElementChanged(e);
if (e.NewElement.GetType() == typeof(MyCustomWebview))
{
Control.SetWebViewClient(new Callback(this));
isMyCustomWebview = true;
}
else
{
Control.SetWebViewClient(new Callback(Plugin.CurrentActivity.CrossCurrentActivity.Current.Activity));
isMyCustomWebview = false;
}
}
public class Callback : WebViewClient
{
Activity _context;
public Callback(Activity _context)
{
this._context = _context;
}
WebViewRenderer _renderer;
public Callback(WebViewRenderer renderer)
{
_renderer = renderer ?? throw new ArgumentNullException("Renderer");
}
public override void OnPageStarted(Android.Webkit.WebView view, string url, Android.Graphics.Bitmap favicon)
{
base.OnPageStarted(view, url, favicon);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Show();
var args = new WebNavigatingEventArgs(WebNavigationEvent.NewPage, new UrlWebViewSource { Url = url }, url);
_renderer.ElementController.SendNavigating(args);
}
}
public override void OnPageFinished(Android.Webkit.WebView view, string url)
{
base.OnPageFinished(view, url);
if (_renderer != null && _renderer.isMyCustomWebview)
{
DependencyService.Get<ILoadingIndicator>().Dismiss();
var source = new UrlWebViewSource { Url = url };
var args = new WebNavigatedEventArgs(WebNavigationEvent.NewPage, source, url, WebNavigationResult.Success);
_renderer.ElementController.SendNavigated(args);
}
}
}
}
}
更新:iOS 项目中的自定义渲染器:
[assembly: ExportRenderer(typeof(Xamarin.Forms.WebView), typeof(MyProject.iOS.WebViewRenderer))]
namespace MyProject.iOS
{
// Xamarin.Forms.Platform.iOS.WebViewRenderer
public class WebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
// webView.LoadFileUrl(url, url);
}
}
}
更新:
以下是我在便携式项目中为 webview 设置源和基础 url 的方式:
var result = await client.PostAsync("/embedded/pay", content);
if (result.IsSuccessStatusCode)
{
var resp = await result.Content.ReadAsStringAsync();
var html = new HtmlWebViewSource
{
Html = resp,
BaseUrl = paymentGatewayUrl
};
//Adding Cookie
CookieContainer cookies = new CookieContainer();
var domain = new Uri(html.BaseUrl).Host;
var cookie = new Cookie
{
Secure = true,
Expired = false,
HttpOnly = false,
Name = "cookie",
Expires = DateTime.Now.AddDays(10),
Domain = domain,
Path = "/"
};
cookies.Add(new Uri(html.BaseUrl), cookie);
webView.Source = html;
}
您可以修改 Custom Renderer 的代码,如下所示。
[assembly: ExportRenderer(typeof(WebView), typeof(MyWebViewRenderer))]
namespace xxx.iOS
{
public class MyWebViewRenderer : ViewRenderer<WebView, WKWebView>
{
WKWebView wkWebView;
protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
{
base.OnElementChanged(e);
if (Control != null) return;
var config = new WKWebViewConfiguration();
wkWebView = new WKWebView(Frame, config) { NavigationDelegate = new MyNavigationDelegate() };
SetNativeControl(wkWebView);
}
}
public class MyNavigationDelegate : WKNavigationDelegate
{
public override void DidFinishNavigation(WKWebView webView, WKNavigation navigation)
{
//get url here
var url = webView.Url;
//webView.LoadFileUrl();
}
}
}
iOS 渲染器:
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(WebView), typeof(MyNamespace.iOS.MyWebViewRenderer))]
namespace MyNamespace.iOS
{
//WkWebViewRenderer inherits from WKWebView
public class MyWebViewRenderer : WkWebViewRenderer
{
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
WKWebView wkWebView = this;
wkWebView.NavigationDelegate = new MyNavigationDelegate(); //not shown here
}
}
}
}