Hybrid WebView
Github Url: https://github.com/mistrypragnesh40/HybridWebView
Xamarin Forms Project.
Create CustomWebView Renderer in your Xamarin form Project.
HybridWebView/Renderer/CustomWebView.cs
using System; using Xamarin.Forms; namespace HybridWebView.Renderer { public class CustomWebView : View { Action<string> action; public static readonly BindableProperty SourceProperty = BindableProperty.Create( propertyName: "Source", returnType: typeof(string), declaringType: typeof(CustomWebView), defaultValue: default(string), propertyChanged: ItemsSourcePropertyChanged ); private static void ItemsSourcePropertyChanged(BindableObject bindable, object oldValue, object newValue) { var control = (CustomWebView)bindable; if (control != null) { control.Source = newValue.ToString(); } } public string Source { get { return (string)GetValue(SourceProperty); } set { SetValue(SourceProperty, value); } } public void RegisterAction(Action<string> callback) { action = callback; } public void Cleanup() { action = null; } public void InvokeAction(string data) { if (action == null || data == null) { return; } action.Invoke(data); } } }
Now Implement CustomWebView Renderer in your Xamarin iOS and Android Project.
Xamarin iOS Implementation.
HybridWebView.iOS/Renderer/HybridWebViewRenderer.cs
using System; using System.ComponentModel; using System.IO; using Foundation; using HybridWebView.iOS.Renderer; using HybridWebView.Renderer; using WebKit; using Xamarin.Forms; using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(CustomWebView), typeof(HybridWebViewRenderer))] namespace HybridWebView.iOS.Renderer { public class HybridWebViewRenderer : ViewRenderer<CustomWebView, WKWebView>, IWKScriptMessageHandler { const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}"; WKUserContentController userController; protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == "Source") { if (Element.Source != null) { string contentDirectoryPath = Path.Combine(NSBundle.MainBundle.BundlePath); Control.LoadHtmlString(Element.Source, new NSUrl(contentDirectoryPath, true)); } } } protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView> e) { base.OnElementChanged(e); if (e.OldElement != null) { userController.RemoveAllUserScripts(); userController.RemoveScriptMessageHandler("invokeAction"); var hybridWebView = e.OldElement as CustomWebView; hybridWebView.Cleanup(); } if (e.NewElement != null) { if (Control == null) { userController = new WKUserContentController(); var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false); userController.AddUserScript(script); userController.AddScriptMessageHandler(this, "invokeAction"); var config = new WKWebViewConfiguration { UserContentController = userController }; var webView = new WKWebView(Frame, config); SetNativeControl(webView); } if (Element.Source != null) { string contentDirectoryPath = Path.Combine(NSBundle.MainBundle.BundlePath); Control.LoadHtmlString(Element.Source, new NSUrl(contentDirectoryPath, true)); } } } public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message) { if (message.Body != null) { Element.InvokeAction(message.Body.ToString()); } } } }
Now Add HtmlWebView.JS File in your HybridWebView.iOS/Resources Folder.
HtmlWebView.JS
$(document).ready(function () { $('body').on('click', 'a', function (e) { e.preventDefault(); invokeCSCode(e.target.href); }) }); function invokeCSCode(data) { try { invokeCSharpAction(data); } catch (err) { } }
Xamarin Android Implementation.
HybridWebView.Android/Renderer/HybridWebViewRenderer.cs
using System; using System.ComponentModel; using Android.Content; using Android.Service.Controls; using Android.Webkit; using HybridWebView.Droid.Renderer; using HybridWebView.Renderer; using Java.Interop; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; [assembly: ExportRenderer(typeof(CustomWebView), typeof(HybridWebViewRenderer))] namespace HybridWebView.Droid.Renderer { public class HybridWebViewRenderer : ViewRenderer<CustomWebView, Android.Webkit.WebView> { const string JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}"; Context _context; public string BaseUrl = "file:///android_asset/"; public HybridWebViewRenderer(Context context) : base(context) { _context = context; } protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { base.OnElementPropertyChanged(sender, e); if (e.PropertyName == "Source") { Control.LoadDataWithBaseURL(BaseUrl, Element.Source, "text/html", "UTF-8", null); } } protected override void OnElementChanged(ElementChangedEventArgs<CustomWebView> e) { base.OnElementChanged(e); if (e.OldElement != null) { Control.RemoveJavascriptInterface("jsBridge"); var hybridWebView = e.OldElement as CustomWebView; hybridWebView.Cleanup(); } if (e.NewElement != null) { if (Control == null) { var webView = new Android.Webkit.WebView(_context); webView.Settings.JavaScriptEnabled = true; webView.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}")); SetNativeControl(webView); } Control.AddJavascriptInterface(new JSBridge(this), "jsBridge"); Control.LoadDataWithBaseURL(BaseUrl, Element.Source, "text/html", "UTF-8", null); } } } /// <summary> /// JavascriptWebViewClient /// </summary> public class JavascriptWebViewClient : WebViewClient { string _javascript; public JavascriptWebViewClient(string javascript) { _javascript = javascript; } public override void OnPageFinished(Android.Webkit.WebView view, string url) { base.OnPageFinished(view, url); view.EvaluateJavascript(_javascript, null); } } /// <summary> /// JsBridge Class /// </summary> public class JSBridge : Java.Lang.Object { readonly WeakReference<HybridWebViewRenderer> hybridWebViewRenderer; public JSBridge(HybridWebViewRenderer hybridRenderer) { hybridWebViewRenderer = new WeakReference<HybridWebViewRenderer>(hybridRenderer); } [JavascriptInterface] [Export("invokeAction")] public void InvokeAction(string data) { HybridWebViewRenderer hybridRenderer; if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer)) { hybridRenderer.Element.InvokeAction(data); } } } }
Now Add HtmlWebView.JS File in your HybridWebView.Android/Assets Folder.
HtmlWebView.JS
$(document).ready(function () { $('body').on('click', 'a', function (e) { e.preventDefault(); invokeCSCode(e.target.href); }) }); function invokeCSCode(data) { try { invokeCSharpAction(data); } catch (err) { } }
How to use CustomWebView in Xamarin Form Content Page.
Add CustomWebView in Your Content Page.
HybridWebView/MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:renderer="clr-namespace:HybridWebView.Renderer" x:Class="HybridWebView.MainPage"> <StackLayout> <renderer:CustomWebView x:Name="hybridWebView" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" /> </StackLayout> </ContentPage>
In CodeBehind Set Jquery & HtmlWebView.JS Reference and bind htmlContent to hybridwebView.Source.
hybridWebView.RegisterAction(data => ShowAction(data)); // showAction() method will invoke when Anchor tag is clicked.
HybridWebView/MainPage.xaml.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; using Xamarin.Essentials; using Xamarin.Forms; namespace HybridWebView { public partial class MainPage : ContentPage { public MainPage() { InitializeComponent(); string jquery = @" <script src='https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js'></script>"; string webView = @"<script src=""HtmlWebView.js""></script>"; string html = $"<html><head>{jquery} {webView}</head>" + "Html Link1 : <a href='http://www.google.com'>Click here</a> </br>" + "Html Link2: <a href='https://xamarincodingtutorial.blogspot.com'>Xamarin Coding Tutorial</a> </html>"; hybridWebView.Source = html; hybridWebView.RegisterAction(data => ShowAction(data)); } public void ShowAction(string data) { if (!string.IsNullOrWhiteSpace(data)) { try { Browser.OpenAsync(data, BrowserLaunchMode.SystemPreferred); } catch (Exception ex) { } } } } }
No comments:
Post a Comment