Monodroid Javascript Call-back

I am trying to use monodroid with webkit to build an application. I had a problem with the html page invoking a javascript method that would be the interface to the method in my application. There is a tutorial on http://developer.android.com/guide/webapps/webview.html for how to do this in java, but the same code does not work in C #.

This exchange for invoking the monovision method from the javascript example linked several threads about using JNI to get around the problem with the monodroid and javascript method, but I don’t know, t managed to get it working.

Now I am trying to use some code instructions, but fail:

// Java
class RunnableInvoker {
Runnable r;
public RunnableInvoker (Runnable r) {
this.r = r;
}
// must match the javascript name:
public void doSomething() {
r.run ();
}
}

From C#, you'd create a class that implements Java.Lang.IRunnable:

// C#
class SomeAction : Java.Lang.Object, Java.Lang.IRunnable {
Action a;
public void SomeAction(Action a) {this.a = a;}
public void Run () {a();}
}

Then to wire things up:

// The C# action to invoke
var action = new SomeAction(() => {/* ... */});

// Create the JavaScript bridge object:
IntPtr RunnableInvoker_Class = JNIEnv.FindClass("RunnableInvoker");
IntPtr RunnableInvoker_ctor = JNIEnv.GetMethodID (RunnableInvoker_Class, "<init>", "(Ljava/lang/Runnable;)V");
IntPtr instance = JNIEnv.NewObject(RunnableInvoker_Class, RunnableInvoker_ctor, new JValue (action));

// Hook up WebView to JS object
web_view.AddJavascriptInterface (new Java.Lang.Object(instance, JniHandleOwnership.TransferLocalRef), "Android");

, - html- , java, #. .

, - , , - , monodroid, html, webkit, a# # javascript.

+5
7

. # JavaScript. , , .

XML-:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent">
    <WebView
            android:id="@+id/web"
            android:layout_width="fill_parent" 
            android:layout_height="wrap_content" 
    />
</LinearLayout>

:

[Activity (Label = "Scratch.WebKit", MainLauncher = true)]
public class Activity1 : Activity
{
    const string html = @"
<html>
<body>
<p>This is a paragraph.</p>
<button type=""button"" onClick=""Foo.run()"">Click Me!</button>
</body>
</html>";

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        // Set our view from the "main" layout resource
        SetContentView (Resource.Layout.Main);

        WebView view = FindViewById<WebView>(Resource.Id.web);
        view.Settings.JavaScriptEnabled = true;
        view.SetWebChromeClient (new MyWebChromeClient ());
        view.LoadData (html, "text/html", null);
        view.AddJavascriptInterface(new Foo(this), "Foo");
    }
}

Activity1.html - HTML, . , /button/@onClick, JavaScript Foo.run(). ( "run" ) "r"; .

:

  • JavaScript view.Settings.JavaScriptEnabled=true. JavaScript.
  • view.SetWebChromeClient() MyWebChromeClient ( ). " ": , ; . view.SetWebChromeClient(new WebChromeClient()), :

    E/Web Console( 4865): Uncaught ReferenceError: Foo is not defined at data:text/html;null,%3Chtml%3E%3Cbody%3E%3Cp%3EThis%20is%20a%20paragraph.%3C/p%3E%3Cbutton%20type=%22button%22%20onClick=%22Foo.run()%22%3EClick%20Me!%3C/button%3E%3C/body%3E%3C/html%3E:1
    

    .

  • view.AddJavascriptInterface(), JavaScript "Foo" Foo.

MyWebChromeClient:

class MyWebChromeClient : WebChromeClient {
}

, , , WebChromeClient .: -/

, "" , Foo, "Foo" JavaScript:

class Foo : Java.Lang.Object, Java.Lang.IRunnable {

    public Foo (Context context)
    {
        this.context = context;
    }

    Context context;        

    public void Run ()
    {
        Console.WriteLine ("Foo.Run invoked!");
        Toast.MakeText (context, "This is a Toast from C#!", ToastLength.Short)
        .Show();
    }
}

, Run().

Mono Android Android Callable Wrappers Java.Lang.Object, Java-. Foo, Android Callable Wrapper:

package scratch.webkit;

public class Foo
    extends java.lang.Object
    implements java.lang.Runnable
{
    @Override
    public void run ()
    {
        n_run ();
    }

    private native void n_run ();

    // details omitted for clarity
}

view.AddJavascriptInterface(new Foo(this), "Foo") JavaScript "Foo" #. JavaScript "Foo" Android Callable Wrapper, #. (, ...)

"". # Foo Java.Lang.IRunnable, # java.lang.Runnable. , Android Callable Wrapper , java.lang.Runnable Runnable.run. Android , , JavaScript-in-Android, "" #. Android Callable Wrappers. , JavaScript Foo.run() (capital 'R'), Foo.run() ( "r" ), , Android/JavaScript, Run(), Run().

JavaScript Foo.run(), Android Callable Wrapper scratch.webview.Foo.run(), JNI Foo.run() #, , .

run()!

, JavaScript- Run(), , ( , , Mono Android 4.2 [Export], :

  • , , . / , .
  • Java. . , .
+20
// C#
// !!!
using Java.Interop; // add link to Mono.Android.Export

public class Activity1 : Activity
{
    const string html = @"
    <html>
    <body>
    <p>This is a paragraph.</p>
    <button type=""button"" onClick=""Foo.SomeMethod('bla-bla')"">Click Me!</button>
    </body>
    </html>";

    class Foo : Java.Lang.Object // do not need Java.Lang.IRunnable 
    {
        Context context;

        public Foo (Context context)
        {
            this.context = context;
        }

        [Export] // !!! do not work without Export
        [JavascriptInterface] // This is also needed in API 17+
        public string SomeMethod(string param)
        {
            Toast.MakeText (context, "This is a Toast from C#!" + param, ToastLength.Short).Show ();
        }
    }

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        SetContentView (Resource.Layout.Main);

        WebView view = FindViewById<WebView> (Resource.Id.web);
        view.Settings.JavaScriptEnabled = true;

        view.AddJavascriptInterface (new Foo (this), "Foo");
        view.LoadData (html, "text/html", null);
    }
}
+9

@kogr . IRunnable. Mono.Android.Export.dll [Export], .

void, , , .

+2

, jonp, JavaScript # Android/Xamarin, JSON, 't [Export],

Android.Net.UrlQuerySanitizer.IValueSanitizer

string Sanitize(string value);

(JSON) JS #. JavaScript-.

+2

, LoadData AddJavascriptInterface. , WebChromeClient . , :

public class Activity1 : Activity
{
    const string html = @"
    <html>
    <body>
    <p>This is a paragraph.</p>
    <button type=""button"" onClick=""Foo.run()"">Click Me!</button>
    </body>
    </html>";

    protected override void OnCreate (Bundle bundle)
    {
        base.OnCreate (bundle);

        SetContentView (Resource.Layout.Main);

        WebView view = FindViewById<WebView> (Resource.Id.web);
        view.Settings.JavaScriptEnabled = true;

        view.AddJavascriptInterface (new Foo (this), "Foo");
        view.LoadData (html, "text/html", null);
    }

    class Foo : Java.Lang.Object, Java.Lang.IRunnable
    {
        Context context;

        public Foo (Context context)
        {
            this.context = context;
        }

        public void Run ()
        {
            Toast.MakeText (context, "This is a Toast from C#!", ToastLength.Short).Show ();
        }
    }
}
+1

" run()!" jonp asnwer ( !).

[Export], , Xamarin.
, .

Android.Webkit.WebChromeClient, OnJsAlert " " - alert(), .

, WebChromeClient, -.

:.

private class AlertableWebChromeClient : Android.Webkit.WebChromeClient
{
    private const string XAMARIN_DATA_ALERT_TAG = "XAMARIN_DATA\0";

    public override bool OnJsAlert(Android.Webkit.WebView view, string url, string message, Android.Webkit.JsResult result)
    {
        if (message.StartsWith(XAMARIN_DATA_ALERT_TAG))
        {
            //Parse 'message' for data - it can be XML, JSON or whatever

            result.Confirm();
            return true;
        }
        else
        {
            return base.OnJsAlert(view, url, message, result);
        }
    }
}

-:

if (window.xamarin_alert_callback != null) {
    alert("XAMARIN_DATA\0" + JSON.stringify(data_object));
}

xamarin_alert_callback (, WebView.LoadURL(javascript:...) WebView.AddJavascriptInterface(something, "xamarin_alert_callback")), , .

+1

. , Java.

0

All Articles