Home > Enterprise >  how to call c# code via react jsx in xamarin webview
how to call c# code via react jsx in xamarin webview

Time:10-27

enter image description here

<html>
<body>
    <script src="http://code.jquery.com/jquery-2.1.4.min.js"></script>
    <h1>HybridWebView Test</h1>
    <br />
    Enter name: <input type="text" id="name">
    <br />
    <br />
    <button type="button" onclick="javascript: invokeCSCode('1234');">Invoke C# Code</button>
    <br />
    <p id="result">Result:</p>
    <script type="text/javascript" src="test.js"/>
</body>
</html>

index.html

function invokeCSCode(data) {
    invokeCSharpAction(data);
}

test.js

CodePudding user response:

I modified the React part after seeing the comments of the ToolmakerSteve.

At first I thought that the function could not be found because the function was renamed during a production build of react, but I found that it works regardless (It was just my misunderstanding that the method executed in JavaScript and the method executed in C# had the same name.)

Also I didn't know eval() how to do <button type="button" onclick="javascript: invokeCSCode(data);" >Invoke C# Code</button> in jsx I was wondering if I could use a method like

Below is an example of the code I have successfully received data from react.

React Part

TestFunctions.ts

export default function test(data: string){
    eval(`invokeTest(${data})`);
}

SendButton.tsx

export default function Button(props: ButtonProps){
    const dispatch = useAppDispatch()

    const handleClick = () =>{
        test('1234');
    }

    return(
        <ButtonWrapper heightValue={props.heightValue} widthValue={props.widthValue} marginValue={props.marginValue}>
            <Button variant="outlined" onClick={() => handleClick()} style={{height: '56px', width: '100%', fontSize: 'large'}}>
                send
            </Button>
        </ButtonWrapper>
    )
}

Xamarin Part

WebViewer.cs

public class WebViewer : WebView
{
    public static readonly BindableProperty UriProperty = BindableProperty.Create(
            propertyName: "Uri",
            returnType: typeof(string),
            declaringType: typeof(WebViewer),
            defaultValue: default(string),
            propertyChanged: UriChanged);

    private static void UriChanged(BindableObject bindable, object oldValue, object newValue)
    {
         if (newValue != null && bindable is WebViewer webViewer)
         {
            if(webViewer.CookieList != null && (string)newValue == (string)oldValue)
            {
                Uri uri = new Uri((string)newValue, UriKind.RelativeOrAbsolute);

                CookieContainer cookieContainer = new CookieContainer();

                foreach (Cookie cookie in webViewer.CookieList)
                {
                    cookie.Domain = uri.Host;
                    cookie.Path = uri.PathAndQuery;
                    cookieContainer.Add(cookie);
                }
                webViewer.Cookies = cookieContainer;
             }
             webViewer.Source = (string)newValue;
          }
     }

     public string Uri
     {
         get => (string)GetValue(UriProperty);
         set => SetValue(UriProperty, value);
     }

     public static readonly BindableProperty CookieListProperty = BindableProperty.Create(
            propertyName: "Cookies",
            returnType: typeof(List<Cookie>),
            declaringType: typeof(WebViewer),
            defaultValue: null,
            propertyChanged: CookieListChanged);
        
     public List<Cookie> CookieList
     {
         get => (List<Cookie>)GetValue(CookieListProperty);
         set => SetValue(CookieListProperty, value);
     }
        
     private static void CookieListChanged(BindableObject bindable, object oldValue, object newValue)
     {
         if (newValue != null && bindable is WebViewer webViewer)
         {
             Uri uri = new Uri(webViewer.Uri, UriKind.RelativeOrAbsolute);

             CookieContainer cookieContainer = new CookieContainer();

             foreach (Cookie cookie in (List<Cookie>)newValue)
             {
                 cookie.Domain = uri.Host;
                 cookie.Path = uri.PathAndQuery;
                 cookieContainer.Add(cookie);
             }
             webViewer.Cookies = cookieContainer;

             if (webViewer.Uri != default(string))
             {
                 webViewer.Source = webViewer.Uri;
             }
         }
     }

     Action<string> action;
     public void RegisterAction(Action<string> callback)
     {
         action = callback;
     }

     public void Cleanup()
     {
         action = null;
     }

     public void InvokeAction(string data)
     {
         if (action == null || data == null)
         {
             return;
         }
         action.Invoke(data);
     }
}

WebViewerRenderer.cs

using Android.Content;
using Android.Views;
using Android.Webkit;
using BDApp.Mobile.Droid.CustomRenderer;
using BDApp.Mobile.Views;
using Java.Interop;
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(WebViewer), typeof(WebViewerRenderer))]
namespace BDApp.Mobile.Droid.CustomRenderer
{
    public class WebViewerRenderer : WebViewRenderer
    {
        const string JavascriptFunction = "function invokeTest(data){jsBridge.invokeAction(data);}";
        public WebViewerRenderer(Context context) : base(context)
        {
        }

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

            if(e.OldElement != null)
            {
                Control.RemoveJavascriptInterface("jsBridge");
                ((WebViewer)Element).Cleanup();
            }
            if(e.NewElement != null)
            {
                Control.SetWebViewClient(new JavascriptWebViewClient(this, $"javascript: {JavascriptFunction}"));
                Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
            }
            Control.Settings.SetAppCacheEnabled(false);
            Control.Settings.CacheMode = CacheModes.NoCache;
        }

        public override bool DispatchTouchEvent(MotionEvent e)
        {
            Parent.RequestDisallowInterceptTouchEvent(true);
            return base.DispatchTouchEvent(e);
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                ((WebViewer)Element).Cleanup();
            }
            base.Dispose(disposing);
        }
    }
    public class JavascriptWebViewClient : FormsWebViewClient
    {
        string _javascript;

        public JavascriptWebViewClient(WebViewerRenderer renderer, string javascript) : base(renderer)
        {
            _javascript = javascript;
        }

        public override void OnPageFinished(Android.Webkit.WebView view, string url)
        {
            base.OnPageFinished(view, url);
            view.EvaluateJavascript(_javascript, null);
        }
    }
    public class JSBridge : Java.Lang.Object
    {
        readonly WeakReference<WebViewerRenderer> hybridWebViewRenderer;

        public JSBridge(WebViewerRenderer hybridRenderer)
        {
            hybridWebViewRenderer = new WeakReference<WebViewerRenderer>(hybridRenderer);
        }

        [JavascriptInterface]
        [Export("invokeAction")]
        public void InvokeAction(string data)
        {
            WebViewerRenderer hybridRenderer;

            if (hybridWebViewRenderer != null && hybridWebViewRenderer.TryGetTarget(out hybridRenderer))
            {
                ((WebViewer)hybridRenderer.Element).InvokeAction(data);
            }
        }
    }
}

TestWebViewPage.xaml

<StackLayout>
        <views:WebViewer Uri="{Binding Uri}" x:Name="webView" CookieList="{Binding CookieList}"
                         HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"/>
</StackLayout>
  • Related