8

For Xamarin.iOS/Monotouch it is simple to retrieve a string when evaluating javascript.

e.g.

string elementValue = browser.EvaluateJavascript("document.getElementById('Id').value");

if(elementValue != "")
{
   DoSomething();
}

Could anybody provide an example of how to do this for Xamarin. Android/Monodroid Android kitkat and above using Evaluatejavascript()? Specifically how to use/setup IValueCallback Synchronously.

JakeRanderson86
  • 183
  • 1
  • 11
  • possible duplicate of [How to evaluate javascript in Xamarin.Android/Monodroid and retrieve result?](http://stackoverflow.com/questions/22100373/how-to-evaluate-javascript-in-xamarin-android-monodroid-and-retrieve-result) – poupou Mar 01 '14 at 15:17
  • @poupou I posted both questions. I'm new to this. Originally I asked for how to achieve this using loadurl("javascript:fn") for Android pre-Kitkat and also using evaluatejavascript method in Android KitKat. I subsequently split it into two questions so that the burden would not be on one person for two solutions. – JakeRanderson86 Mar 03 '14 at 14:07
  • Please delete one of your questions. – Rohit Vipin Mathews Sep 18 '15 at 14:22
  • @Rohit do you have a solution? – JakeRanderson86 Jan 07 '16 at 11:59
  • I think you already have 2 answers, and also there is XLabs extended webview which does this out of the box. – Rohit Vipin Mathews Jan 09 '16 at 17:59
  • @rohit as appreciative as I am for both answers neither enables synchronous evaluation. XLabs hybridwebview requires switching project to Xamarin Forms which I don't want to do, neither does it allow synchronous evaluation/wait for result as is found in iOS which is what I and many others are trying to achieve. – JakeRanderson86 Jan 12 '16 at 09:14

2 Answers2

12

@ksasq's answer is essentially correct but needs some small changes.

First of all, make sure you have Xamarin Android 4.12 installed which adds bindings for KitKat.

Then, since WebView.evaluateJavascript hasn't been bound in C# flavor, you have to create a class implements IValueCallback. The tricky part is that class has to be inherited from Java.Lang.Object.

An example of the class would be like:

private class MyClass : Java.Lang.Object, IValueCallback
{
    public void OnReceiveValue(Java.Lang.Object value)
    {
        //Here goes your implementation.
    }
}
hvaughan3
  • 10,955
  • 5
  • 56
  • 76
Aaron He
  • 5,509
  • 3
  • 34
  • 44
  • Thanks @aaronhe I did edit ksasq answer with what you are saying previously. Do you have any suggestions for synchronous javascript evaluation like monotouch evaluatejavascript? I really need a reliable method for achieving this. – JakeRanderson86 Mar 15 '14 at 09:20
  • Thanks @aaronhe it saved a day :) – Saurabh Sashank Jul 07 '17 at 13:08
7

Android's WebView executes JavaScript asynchronously and passes the result of the execution in a ValueCallback later.

I'm not familiar with Xamarin exactly, but if you can share some of your Android C# code, may be able to help better.

From a Java perspective, where my experience lies:

Essentially, you need to instantiate a ValueCallback object that implements the onReceiveValue function. When the javascript that you have evaluated finishes executing, the function you declared will be executed, passing in the result of that evaluation as a paramter that is string of JSON. You should then be able to retrieve the result from that JSON.

Hope this helps!

Update: cobbling together some C# that might help. Caveat: I've never written a line of c# before this. But hopefully if it's not quite right will set you on the right path :-)

class JavaScriptResult : public IValueCallback {
    public void OnReceiveValue(Java.Lang.Object result) {
        Java.Lang.String json = (Java.Lang.String) result;
        // |json| is a string of JSON containing the result of your evaluation
    }
}

Then you can presumably say something along the lines of

web_view.EvaluateJavaScript("function() { alert('hello world'); return 42; }()",
        new JavaScriptResult());
ksasq
  • 4,424
  • 2
  • 18
  • 10
  • Thanks for replying. My problem is I do not know how to instantiate ValueCallback in **Monodroid/Xamarin**. – JakeRanderson86 Mar 05 '14 at 21:43
  • OK, I read a few C# samples and tried to cobble something together. Caveat: never written any C# before this, but hopefully will set you on the right lines :-) See edited answer above. – ksasq Mar 05 '14 at 23:52
  • I updated your JavascriptResult Class as it needs to subclass Java.Lang.Object to run. Looking at the original question do you have any suggestions for how to wait for the return value before proceeding to the next line? – JakeRanderson86 Mar 07 '14 at 09:42
  • Ah OK, sounds good :-) As for waiting, I'm afraid I think that's going to be tricky and deadlock prone. The API is designed to be asynchronous; there isn't an easy way to make it synchronous. – ksasq Mar 07 '14 at 09:45
  • I think what I really need to do is use the private Android method stringByEvaluatingJavaScriptFromString http://stackoverflow.com/a/17830417/3365387. I am now trying to see how to access this on Monodroid – JakeRanderson86 Mar 07 '14 at 13:22
  • Oh my goodness. Please don't do that. That sample solution is a threading nightmare. – ksasq Mar 07 '14 at 14:10
  • is it the method itself or the solution that is the problem/threading nightmare. Should I accept your answer? – JakeRanderson86 Mar 09 '14 at 09:45
  • There are a few problems. It's reflecting into a class that exists on a private background thread, presumably from the application's UI thread so there's no thread safety at all. WebKit is single threaded and this method calls directly into it from another thread. Additionally, the method doesn't exist in Android 4.4 any more, so you can't use that strategy on new versions of the platform. – ksasq Mar 09 '14 at 11:27