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