Recientemente tuve la tarea de crear un puente de interoperabilidad bidireccional entre una aplicación de shell y una página web en .NET MAUI. Al no encontrar ninguna forma de resolver esto, tuve la idea de crearlo en Xamarin.Forms, primero viendo que MAUI es una continuación de él.
Después de haber creado esta aplicación, intenté convertirla a MAUI usando las instrucciones de Microsoft en la wiki dotnet/maui github.
El principal problema que encuentro en este momento es que he estado usando extensiones en WebViewRenderer , WebViewClient y Java.Lang.Object de Android para poder enviar y recibir javascript hacia y desde WebView.
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); } } }Los tres no están disponibles en este momento o no se implementarán en MAUI, ya que ahora se ha automatizado una gran cantidad de código dependiente de la plataforma. Lo que me deja con el problema de que parece que no puedo descifrar cómo cambiar mi código actual para lograr lo mismo en MAUI.
Al ver que MAUI actualmente ni siquiera está completamente lanzado, me preguntaba si esto no es posible actualmente o si hay alguna solución para hacerlo posible.
Cualquier ayuda sería muy apreciada.
El WebView predeterminado de MAUI tiene las funciones Eval y EvaluateJavaScriptAsync para llamar al código JavaScript desde C#:
Eval simplemente ejecuta la cadena de string comandos que pasa de una manera de disparar y olvidar.EvaluateJavaScriptAsync , pero también devuelve una string con un resultado en forma de cadena de los datos que devolvió el script.Si desea utilizar métodos de devolución de llamada/puente para recibir datos automáticamente desde el lado de JavaScript sin ninguna entrada desde el lado de C# de la aplicación, tendrá que ampliar los procesadores por plataforma predeterminados para agregar esa funcionalidad. La buena noticia es que hay un tutorial oficial sobre cómo hacerlo para Xamarin Forms en Customizing a WebView, que es casi sencillo de migrar a .NET MAUI: solo tiene que cambiar la forma en que se registran los renderizadores .
Llamar a C# desde una vista web es realmente extremadamente simple. Simplemente navegue y luego intercepte eso en c #.
el 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>La 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 } }