Monodroid Javascript回拨

前端之家收集整理的这篇文章主要介绍了Monodroid Javascript回拨前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在尝试使用monodroid和webkit来创建一个应用程序.我有一个问题,让html页面调用一个 javascript方法,这将是我的应用程序中的方法的接口.在 http://developer.android.com/guide/webapps/webview.html有一个关于如何在java中执行此操作的教程,但相同的代码不适用于C#.

call monodroid method from javascript example的这个交换链接了一些关于使用JNI来解决monodroid和javascript接口方法问题的线程,但是我无法让它工作.

现在,我正在尝试使用一些代码指令,但没有成功:

// 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,然后调用C#.这没有用.

我想知道是否有人知道问题是什么,或者另一个想法,所以我可以使用monodroid让webkit中的html按钮调用c#方法,或者能够让我的c#代码调用javascript方法.

解决方法

我们退一步吧.您想从JavaScript调用C#代码.如果你不介意眯眼,那就很简单了.

首先,让我们从Layout 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”开头;我们稍后会回到这里.

还有三个值得注意的事项:

>我们使用view.Settings.JavaScriptEnabled = true启用JavaScript.没有这个,我们就不能使用JavaScript.
>我们使用MyWebChromeClient类(稍后定义)的实例调用view.SetWebChromeClient().这是一个“货物狂热编程”:如果我们不提供它,事情就不起作用;我不知道为什么.如果我们改为看似等效的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”JavaScript变量相关联的Foo类:

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 for Android构建过程中,为每个Java.Lang.Object子类创建了Android Callable Wrappers,它声明了所有重写的方法和所有已实现的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”变量与C#类型相关联.这将JavaScript“Foo”变量与与C#类型的实例关联的Android Callable Wrapper实例相关联. (啊,间接……)

现在我们进入前面提到的“眯眼”. C#Foo类实现了Java.Lang.IRunnable接口,该接口是java.lang.Runnable接口的C#绑定.因此,Android Callable Wrapper声明它实现了java.lang.Runnable接口,并声明了Runnable.run方法. Android,以及Android内部的JavaScript,不会“看到”您的C#类型.他们改为看到Android Callable Wrappers.因此,JavaScript代码调用Foo.Run()(大写’R’),它调用Foo.run()(小写’r’),因为Android / JavaScript有权访问的类型声明run()方法,而不是Run()方法.

当JavaScript调用Foo.run()时,调用Android Callable Wrapper scratch.webview.Foo.run()方法,通过JNI的快乐,导致执行Foo.Run()C#方法,真的是你想要做的一切.

但我不喜欢run()!

如果你不喜欢名为run()的JavaScript方法,或者你想要参数或任何其他东西,你的世界会变得更加复杂(至少在Mono for Android 4.2和[Export]支持之前).你需要做两件事之一:

>查找提供所需名称和签名的现有绑定接口或虚拟类方法.然后覆盖方法/实现接口,事情看起来与上面的例子非常相似.
>滚动自己的Java类.请在monodroid mailing list询问更多详情.这个答案越来越长.

猜你在找的JavaScript相关文章