有没有办法在 .NET 6 MAUI 中的 shell 应用程序和 webview 之间创建双向通信?

Hol*_*aii 7 javascript webview xamarin.forms maui .net-6.0

最近,我收到了在 .NET MAUI 中的 shell 应用程序和网页之间创建双向互操作桥的任务。没有找到任何方法来解决这个问题,我首先想到在 Xamarin.Forms 中创建它,因为 MAUI 是它的延续。

创建此应用程序后,我尝试使用 dotnet/maui github wiki 上的 Microsoft 说明将其转换为 MAUI。

我现在遇到的主要问题是我一直在 Android 的WebViewRendererWebViewClientJava.Lang.Object上使用扩展,以便能够向 WebView 发送和接收 javascript。

public class ExtendedWebViewRenderer : WebViewRenderer
    {
        private const String JavascriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}";

        public ExtendedWebViewRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<WebView> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                Control.RemoveJavascriptInterface("jsBridge");
                ((ExtendedWebView)Element).Cleanup();
            }
            if (e.NewElement != null)
            {
                Control.SetWebViewClient(new JavascriptWebViewClient($"javascript: {JavascriptFunction}"));
                Control.AddJavascriptInterface(new JsBridge(this), "jsBridge");
            }
        }
    }

public class JavascriptWebViewClient : WebViewClient
    {
        private readonly String _javascript;

        public JavascriptWebViewClient(String javascript)
        {
            _javascript = javascript;
        }

        public override void OnPageFinished(WebView view, String url)
        {
            base.OnPageFinished(view, url);
            view.EvaluateJavascript(_javascript, null);
        }
    }

public class JsBridge : Java.Lang.Object
    {
        private readonly WeakReference<ExtendedWebViewRenderer> _extendedWebViewMainRenderer;

        public JsBridge(ExtendedWebViewRenderer extendedRenderer)
        {
            _extendedWebViewMainRenderer = new WeakReference<ExtendedWebViewRenderer>(extendedRenderer);
        }

        [JavascriptInterface]
        [Export("invokeAction")]
        public void InvokeAction(String data)
        {
            if (_extendedWebViewMainRenderer != null && _extendedWebViewMainRenderer.TryGetTarget(out var extendedRenderer))
            {
                ((ExtendedWebView)extendedRenderer.Element).InvokeAction(data);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

所有这三个功能现在要么不可用,要么不会在 MAUI 中实现,因为许多依赖于平台的代码现在已经自动化。这给我留下了一个问题,我似乎无法弄清楚如何更改当前的代码以在 MAUI 中完成同样的事情。

鉴于 MAUI 目前尚未完全发布,我想知道这目前是否不可能,或者是否有一些解决方法可以使其成为可能。

任何帮助将不胜感激。

Mr *_*r W 8

从 webview 调用 C# 实际上非常简单。只需导航然后在 C# 中拦截即可。

xaml:

<WebView  WidthRequest="400" HeightRequest="400" Navigating="WebView1_Navigating">
<WebView.Source>`enter code here`
    <HtmlWebViewSource>
        <HtmlWebViewSource.Html>
            <![CDATA[
            <HTML>
                <script>
                    function callCsharp(){
                        window.location.href = 'http://poc.MyFunction?name=john&country=DK';
                    }
                </script>
            <BODY
                <a href="http://poc.MyFunction?name=john&country=DK">A link that triggers C#</a>
                <br>
                <button onclick="callCsharp()" type="button">A button calling javascript</button>
            </BODY>
            </HTML>
            ]]>
        </HtmlWebViewSource.Html>
    </HtmlWebViewSource>
</WebView.Source>
Run Code Online (Sandbox Code Playgroud)

C#:

private async void WebView1_Navigating(object sender, WebNavigatingEventArgs e)
{
    var urlParts = e.Url.Split(".");
    if (urlParts[0].ToLower().Equals("http://poc"))
    {
        var funcToCall = urlParts[1].Split("?");
        var methodName = funcToCall[0];
        var funcParams = funcToCall[1];
        Debug.WriteLine("Calling " + methodName);
        
        // prevent the navigation to complete
        e.Cancel = true;

        // TODO smart parsing and type casting of parameters and then some reflection magic
    }
}
Run Code Online (Sandbox Code Playgroud)


r2d*_*igo 5

MAUI 默认WebView具有从 C# 调用 JavaScript 代码的Eval和函数:EvaluateJavaScriptAsync

  • Evalstring只是以“即发即忘”的方式执行您传递的脚本。
  • EvaluateJavaScriptAsync需要等待,但也会返回一个string带有脚本返回的数据的字符串化结果。

如果您想使用回调/桥接方法自动从 JavaScript 端接收数据,而无需从应用程序的 C# 端进行任何输入,则必须扩展默认的每平台渲染器才能添加该功能。好消息是,自定义 WebView中有一个关于如何为 Xamarin Forms 执行此操作的官方教程,该教程几乎可以直接移植到 .NET MAUI - 您只需更改渲染器的注册方式