javac#iosmauibase-url

ios maui.net custom webview default BaseUrl path


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


Solution

  • 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.