i have this custom web-view as follow in : MainPage.xaml
```
<controls:HybridWebView
x:Name="MyWebView"
HeightRequest="140"
HorizontalOptions="Fill"
Source="{Binding Source}"
VerticalOptions="FillAndExpand"
WidthRequest="512" />
and the custoum webview code is:
HybridWebView.cs
public class SourceChangedEventArgs : EventArgs
{
public WebViewSource Source
{
get;
private set;
}
public SourceChangedEventArgs(WebViewSource source)
{
Source = source;
}
}
public class JavaScriptActionEventArgs : EventArgs
{
public string Payload { get; private set; }
public JavaScriptActionEventArgs(string payload)
{
Payload = payload;
}
}
public interface IHybridWebView : IView
{
event EventHandler<SourceChangedEventArgs> SourceChanged;
event EventHandler<JavaScriptActionEventArgs> JavaScriptAction;
event EventHandler<EvaluateJavaScriptAsyncRequest> RequestEvaluateJavaScript;
void Refresh();
Task EvaluateJavaScriptAsync(EvaluateJavaScriptAsyncRequest request);
WebViewSource Source { get; set; }
void Cleanup();
void InvokeAction(string data);
}
public class HybridWebView : View, IHybridWebView
{
public event EventHandler<SourceChangedEventArgs> SourceChanged;
public event EventHandler<JavaScriptActionEventArgs> JavaScriptAction;
public event EventHandler<EvaluateJavaScriptAsyncRequest> RequestEvaluateJavaScript;
public HybridWebView()
{
}
public async Task EvaluateJavaScriptAsync(EvaluateJavaScriptAsyncRequest request)
{
await Task.Run(() =>
{
RequestEvaluateJavaScript?.Invoke(this, request);
});
}
public void Refresh()
{
if (Source == null) return;
var s = Source;
Source = null;
Source = s;
}
public WebViewSource Source
{
get { return (WebViewSource)GetValue(SourceProperty); }
set { SetValue(SourceProperty, value); }
}
public static readonly BindableProperty SourceProperty = BindableProperty.Create(
propertyName: "Source",
returnType: typeof(WebViewSource),
declaringType: typeof(HybridWebView),
defaultValue: new UrlWebViewSource() { Url = "about:blank" },
propertyChanged: OnSourceChanged);
private static void OnSourceChanged(BindableObject bindable, object oldValue, object newValue)
{
var view = bindable as HybridWebView;
bindable.Dispatcher.Dispatch(() =>
{
view.SourceChanged?.Invoke(view, new SourceChangedEventArgs(newValue as WebViewSource));
});
}
public void Cleanup()
{
JavaScriptAction = null;
}
public void InvokeAction(string data)
{
JavaScriptAction?.Invoke(this, new JavaScriptActionEventArgs(data));
}
}
and ios
using CoreGraphics;
using Foundation;
using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform;
using WebKit;
using WebViewHostExample.Controls;
namespace WebViewHostExample.Platforms.iOS.Renderers {
public class HybridWebViewHandler : ViewHandler<IHybridWebView, WKWebView> { public static PropertyMapper<IHybridWebView, HybridWebViewHandler> HybridWebViewMapper = new PropertyMapper<IHybridWebView, HybridWebViewHandler>(ViewHandler.ViewMapper);
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
private WKUserContentController userController;
private JSBridge jsBridgeHandler;
static SynchronizationContext sync;
public HybridWebViewHandler() : base(HybridWebViewMapper)
{
sync = SynchronizationContext.Current;
}
private void VirtualView_SourceChanged(object sender, SourceChangedEventArgs e)
{
LoadSource(e.Source, PlatformView);
}
protected override WKWebView CreatePlatformView()
{
sync = sync ?? SynchronizationContext.Current;
jsBridgeHandler = new JSBridge(this);
userController = new WKUserContentController();
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(jsBridgeHandler, "invokeAction");
var config = new WKWebViewConfiguration { UserContentController = userController };
var webView = new WKWebView(CGRect.Empty, config);
return webView;
}
protected override void ConnectHandler(WKWebView platformView)
{
base.ConnectHandler(platformView);
if (VirtualView.Source != null)
{
LoadSource(VirtualView.Source, PlatformView);
}
VirtualView.SourceChanged += VirtualView_SourceChanged;
VirtualView.RequestEvaluateJavaScript += VirtualView_RequestEvaluateJavaScript;
}
private void VirtualView_RequestEvaluateJavaScript(object sender, EvaluateJavaScriptAsyncRequest e)
{
sync.Post((o) =>
{
PlatformView.EvaluateJavaScript(e);
}, null);
}
protected override void DisconnectHandler(WKWebView platformView)
{
base.DisconnectHandler(platformView);
VirtualView.SourceChanged -= VirtualView_SourceChanged;
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
jsBridgeHandler?.Dispose();
jsBridgeHandler = null;
}
private static void LoadSource(WebViewSource source, WKWebView control)
{
if (source is HtmlWebViewSource html)
{
control.LoadHtmlString(html.Html, new NSUrl(html.BaseUrl ?? "http://localhost", true));
}
else if (source is UrlWebViewSource url)
{
control.LoadRequest(new NSUrlRequest(new NSUrl(url.Url)));
}
}
}
public class JSBridge : NSObject, IWKScriptMessageHandler
{
readonly WeakReference<HybridWebViewHandler> hybridWebViewRenderer;
internal JSBridge(HybridWebViewHandler hybridRenderer)
{
hybridWebViewRenderer = new WeakReference<HybridWebViewHandler>(hybridRenderer);
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
HybridWebViewHandler hybridRenderer;
if (hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
{
hybridRenderer.VirtualView?.InvokeAction(message.Body.ToString());
}
}
}}
if i use the code like this:
MainPageViewModel vm;
public MainPage()
{
InitializeComponent();
vm = new MainPageViewModel();
MyWebView.BindingContext = vm;
MyWebView.JavaScriptAction += MyWebView_JavaScriptAction;
}
protected override void OnParentSet()
{
base.OnParentSet();
vm.Source = new HtmlWebViewSource()
{
, Html = htmlSource
BaseUrl = "ios path i want????"
};
}
if i did this in android: and add the path: "file:///android_asset/" it will work on android web-view
protected override void OnParentSet()
{
base.OnParentSet();
vm.Source = new HtmlWebViewSource()
{
, Html = htmlSource
BaseUrl = "file:///android_asset/"
};
}
it will work but i want the same thing in ios ???
what is the default path that will go to "Resources/Raw/" in ios code of maui.net
if i did this in android: and add the path: "file:///android_asset/" it will work on android web-view.
it will work but i want the same thing in ios ???
Try this code:
#elif __IOS__
BaseUrl = Foundation.NSBundle.MainBundle.ResourcePath;
#else
For more details you can refer to this issue: Ios Local device component css failing to load #5245.