Hi everyone,
I'm using Hybrid Webview with EventRegister , Invoke JS , EvaluateJavascript functions. As you know Hybrid webview using WKWebview. But WkWebview didnt manage and support JS Alert , prompt etc. . But also i notice WebViewRenderer(from xamarin.Forms) support JS alert, prompt etc. Do you have a way to bundle this 2 webview or do you have a any suggestions to My HybridWebview ?
@MDemir Refer to this documentation https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview#creating-the-custom-renderer-on-ios to create a custom renderer for iOS.
Then set the delegate like:
var config = new WKWebViewConfiguration { UserContentController = userController }; var webView = new WKWebView (Frame, config); // Set the delegate here webView.UIDelegate = new MyWKWebViewDelegate(); SetNativeControl (webView);
Adjust the Delegate like:
public class MyWKWebViewDelegate : WKUIDelegate { public override void RunJavaScriptAlertPanel(WKWebView webView, string message, WKFrameInfo frame, Action completionHandler) { var alertController = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert); alertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, (action) => { })); UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null); completionHandler(); } public override void RunJavaScriptConfirmPanel(WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler) { // Confirm } public override void RunJavaScriptTextInputPanel(WKWebView webView, string prompt, string defaultText, WKFrameInfo frame, Action<string> completionHandler) { // Prompt } }
Thanks @LandLu for massive helps. I changed MyCystıneDelegate like this;
`
public class MyWkWebViewDelegate : WKUIDelegate
{
[Foundation.Export("webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:completionHandler:")] public override void RunJavaScriptAlertPanel(WebKit.WKWebView webView, string message, WebKit.WKFrameInfo frame, System.Action completionHandler) { // Create and present a native UIAlertController with the message var alertController = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert); alertController.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, null)); UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null); // Call the completion handler completionHandler(); } // Called when a Javascript confirm() alert is called in the WKWebView // The alert panel should display the message with two buttons - "OK" and "Cancel" [Export("webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:completionHandler:")] public override void RunJavaScriptConfirmPanel(WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler) { // Create a native UIAlertController with the message var alertController = UIAlertController.Create(null, message, UIAlertControllerStyle.Alert); // Add two actions to the alert. Based on the result we call the completion handles and pass either true or false alertController.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, okAction => { completionHandler(true); })); alertController.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Default, cancelAction => { completionHandler(false); })); // Present the alert UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null); } // Called when a Javascript prompt() alert is called in the WKWebView // The alert panel should display the prompt, default placeholder text and two buttons - "OK" and "Cancel" [Foundation.Export("webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:completionHandler:")] public override void RunJavaScriptTextInputPanel(WebKit.WKWebView webView, string prompt, string defaultText, WebKit.WKFrameInfo frame, System.Action<string> completionHandler) { // Create a native UIAlertController with the message var alertController = UIAlertController.Create(null, prompt, UIAlertControllerStyle.Alert); // Add a text field to the alert, set the placeholder text and keep a refernce to the field UITextField alertTextField = null; alertController.AddTextField((textField) => { textField.Placeholder = defaultText; alertTextField = textField; }); // Pass the text to the completion handler when the "OK" button is tapped alertController.AddAction(UIAlertAction.Create("Ok", UIAlertActionStyle.Default, okAction => { completionHandler(alertTextField.Text); })); // If "Cancel" is tapped, we can just return null alertController.AddAction(UIAlertAction.Create("Cancel", UIAlertActionStyle.Default, cancelAction => { completionHandler(null); })); // Present the alert UIApplication.SharedApplication.KeyWindow.RootViewController.PresentViewController(alertController, true, null); } }
`
And set like @LandLu said that. Its works like a charm.
Answers
You can implement the
WKUIDelegate
to achieve the alert and prompt:Do not forget to set this delegate to the wkwebview in your custom renderer.
@LandLu How can I set this delegate to my customrenderer wkwebview ?
Here is my custom renderer;
using System;
using System.Threading;
using System.Threading.Tasks;
using Foundation;
using Paperwork.Mobile.CustomControls;
using Paperwork.Mobile.iOS.CustomRenderers;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PWHybridWebView), typeof(PWHybridWebViewRenderer))]
namespace Paperwork.Mobile.iOS.CustomRenderers
{
public class PWHybridWebViewRenderer : ViewRenderer<PWHybridWebView, WKWebView>, IWKScriptMessageHandler,
IWKNavigationDelegate
{
private const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
private WKUserContentController userController;
}
@LandLu How can I set this delegate to the wkwebview in my custom renderer ?
@MDemir Refer to this documentation https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/hybridwebview#creating-the-custom-renderer-on-ios to create a custom renderer for iOS.
Then set the delegate like:
Adjust the Delegate like:
Thanks @LandLu for massive helps. I changed MyCystıneDelegate like this;
`
public class MyWkWebViewDelegate : WKUIDelegate
{
`
And set like @LandLu said that. Its works like a charm.
Here is my custom renderer
`using System;
using System.Threading;
using System.Threading.Tasks;
using Foundation;
using Paperwork.Mobile.CustomControls;
using Paperwork.Mobile.iOS.CustomRenderers;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PWHybridWebView), typeof(PWHybridWebViewRenderer))]
namespace Paperwork.Mobile.iOS.CustomRenderers
{
public class PWHybridWebViewRenderer : ViewRenderer<PWHybridWebView, WKWebView>, IWKScriptMessageHandler,
IWKNavigationDelegate
{
private const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
private WKUserContentController userController;
}`
How can I set this delegate to the wkwebview in my custom renderer ?
here is my custom renderer
`using System;
using System.Threading;
using System.Threading.Tasks;
using Foundation;
using Paperwork.Mobile.CustomControls;
using Paperwork.Mobile.iOS.CustomRenderers;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(PWHybridWebView), typeof(PWHybridWebViewRenderer))]
namespace Paperwork.Mobile.iOS.CustomRenderers
{
public class PWHybridWebViewRenderer : ViewRenderer<PWHybridWebView, WKWebView>, IWKScriptMessageHandler,
IWKNavigationDelegate
{
private const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
private WKUserContentController userController;
}
`