gpt4 book ai didi

javascript - Monodroid Javascript 回调

转载 作者:数据小太阳 更新时间:2023-10-29 03:58:27 26 4
gpt4 key购买 nike

我正在尝试将 monodroid 与 webkit 一起使用来创建应用程序。我在让 html 页面调用 javascript 方法时遇到问题,这将是我应用程序中方法的接口(interface)。在 http://developer.android.com/guide/webapps/webview.html 上有一个教程。有关如何在 java 中执行此操作,但相同的代码不适用于 C#。

此交换在 call monodroid method from javascript example链接了一些关于使用 JNI 来解决 monodroid 和 javascript 接口(interface)方法问题的线程,但我无法让它工作。

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

// 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# 代码。如果你不介意眯着眼睛,这很简单。

首先,让我们从布局 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。
  • 我们调用view.SetWebChromeClient()带有 MyWebChromeClient 的实例类(稍后定义)。这有点像“ cargo 崇拜编程”:如果我们不提供它,事情就不起作用;我不知道为什么。如果我们改为执行看似等效的 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):
    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 for Android 构建过程中, Android Callable Wrappers为每个 Java.Lang.Object 创建子类,它声明了所有被覆盖的方法和所有实现的 Java 接口(interface)。这包括上述 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接口(interface),它是 java.lang.Runnable 的 C# 绑定(bind)界面。因此,Android Callable Wrapper 声明它实现了 java.lang.Runnable接口(interface),并声明 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()!

    如果您不喜欢 JavaScript 方法名为 run() ,或者你想要参数,或者任何数量的其他东西,你的世界会变得更加复杂(至少在 Mono for Android 4.2 和 [Export] 支持之前)。您需要做以下两件事之一:
  • 查找提供所需名称和签名的现有绑定(bind)接口(interface)或虚拟类方法。然后重写方法/实现接口(interface),事情看起来和上面的例子很相似。
  • 滚动您自己的 Java 类。询问 monodroid mailing list更多细节。这个答案越来越长了。
  • 关于javascript - Monodroid Javascript 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9745168/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com