Monodroid Javascript 回调

2023-11-27

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

本次交流于从 javascript 示例调用 monodroid 方法链接了一些关于使用 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,然后 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”开头;我们稍后再讨论这一点。

还有其他三件事值得注意:

  1. 我们启用 JavaScriptview.Settings.JavaScriptEnabled=true。没有这个,我们就无法使用 JavaScript。
  2. We call 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
    

    这对我来说也毫无意义。

  3. We call 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 可调用包装器是为每一个创建的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
}

When view.AddJavascriptInterface(new Foo(this), "Foo")被调用,这没有关联 JavaScript"Foo"C# 类型的变量。这是关联 JavaScript"Foo"带有与 C# 类型实例关联的 Android Callable Wrapper 实例的变量。 (啊,间接...)

现在我们开始前面提到的“眯眼”。 C#Foo类实现了Java.Lang.IRunnable接口,这是 C# 的绑定java.lang.Runnable界面。 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()方法,not a Run() method.

当 JavaScript 调用时Foo.run(),然后是 Android Callable Wrapperscratch.webview.Foo.run()调用方法,通过 JNI 的乐趣,导致执行Foo.Run()C# 方法,这确实是您最初想要做的。

但我不喜欢 run()!

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

  1. 查找提供所需名称和签名的现有绑定接口或虚拟类方法。然后重写方法/实现接口,事情看起来与上面的示例非常相似。
  2. 推出您自己的 Java 类。询问monodroid 邮件列表更多细节。这个答案越来越长了。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Monodroid Javascript 回调 的相关文章

  • 两个单独表格上的 Td 高度

    我有两个单独的表 我在每个 tr 上使用焦点 悬停函数 该函数同时在两个表上都很好用 我的问题是 td 高度 因为如果第一个表中 td 的描述更大 将显示在中的两行上相同的td和td的高度将被修改 但仅限于第一个表td 如何记住第一个表中
  • 使用 javascript 根据索引合并多个数组

    我需要将两个数组合并为一个数组 我有代码 但它没有按预期工作 它将它们一个接一个地合并 但我需要互锁这些值 div div
  • 解决错误 413 请求实体太大

    我正在从事的项目允许我们的员工将大文件上传到我们的共享主机并获取下载链接 问题是我们的托管拒绝更改共享托管的 LimitRequestBody 还有其他解决方案可以解决 LimitRequestBody 或任何其他方法来完成这项工作吗 有两
  • 继续使用 sketch.js 编辑草图图像 [关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在使用 sketch js 中的示例 http intridea github io sketch js http intridea g
  • EJS.JS ReferenceError:标题未定义

    我遇到了 Express 脚本的问题 我正在调用一个在另一个函数成功时呈现视图的函数 在这个项目中 我使用 Angular Node Express 和 ejs 作为视图引擎 当我渲染视图时 不幸的是我收到以下 ejs 错误 Referen
  • 使用 Javascript 在前端创建基本 URL(开发、API 和生产)

    无论开发和部署如何 如何制作适用于 http https localhost 端口和实际域的基本 url 我想创建一个可以在所有场景或条件下工作的基本 url 无论 http https 协议 端口 本地主机和实际域如何 无论是在开发中还是
  • 如何突出显示 html 文档中文本查询的搜索结果而忽略 html 标签?

    我有一个字符串 其中包含 html 内容 像这样的东西 const text My name is Alan and I span an span div class someClass artist div 我使用以下命令在反应组件中渲染
  • MongoDB:如何在更新之前对查询进行排序

    我正在编写一个 Meteor Node js 应用程序 它在后端使用 MongoDB 在我的代码中的某个时刻 我需要更新specific集合中的文档 我需要使用 Mongo 的 update 方法 但我在传递正确的 复杂的 查询以缩小到该特
  • 在 MongoDB 中对 Null 值进行最后排序

    我使用以下查询根据名为 sortIndex 的字段按升序填充 MongoDB 中的项目 有时 数据库中的项目没有 sortIndex 字段 通过以下查询 具有 null sortIndex 的项目显示在顶部 我想知道如何让它们显示在底部 我
  • 如何调试使用 Testaulous (Karma) 运行的 Jasmine 规范?

    我有一个具有 Jasmine 规格的小项目 我使用 Testaulous 作为我的测试运行程序 我不明白如何调试应用程序代码或规范代码 当我尝试在 Chrome 开发工具中设置断点时 下次规范运行时不会命中它 因为它每次都会使用新的查询字符
  • chrome.extension.getBackgroundPage() 函数示例

    我正在开发一个需要在后台运行的小型 Chrome 扩展 但是 我知道当我使用弹出窗口时这是不可能的 经过一番阅读后 似乎最好的选择是创建popup js为了运行background js using chrome extension get
  • 在 X 轴刻度上渲染 HTML

    我想在 D3 图表的 x 轴上渲染 HTML 基本上 我希望轴上的每个标签都是到数据中另一列的超链接 我试过了 x domain data map function d return a href d Name a 但它根本不起作用 我得到
  • Phantomjs page.content 未检索页面内容

    我使用 Phantomjs 来抓取使用 JavaScript 和 Ajax 加载动态内容的网站 我有以下代码 var page require webpage create page onError function msg trace v
  • Vim、Javascript、DoctorJS (jsctags) 和 Taglist(源代码浏览)

    我已经安装了DoctorJS http doctorjs org 之前jsctags 试图为 Vim 获得一些好的源代码浏览 标签列表 使用Taglist http www vim org scripts script php script
  • 让屏幕阅读器读取使用 JavaScript 添加的新内容

    加载网页时 屏幕阅读器 例如 OS X 中的屏幕阅读器或 Windows 上的 JAWS 中的屏幕阅读器 将读取整个页面的内容 但是假设您的页面是动态的 当用户执行操作时 新内容就会添加到页面中 为了简单起见 假设您在某个位置显示一条消息
  • Angularjs + Typescript,如何将 $routeParams 与 IRouteParamsService 一起使用

    我使用 routeParams 从 URI 中提取属性并为其设置本地变量 当我使用打字稿输入设置 route 参数的类型时 我无法再访问 route 参数 如何访问 routeParams 中的属性 class Controller con
  • Img src 路径以及要传递的标头参数

    我在 jsp 页面中有一个 img 标记 其中 src 路径需要传递标头参数才能获取图像 我们怎样才能实现它呢 您现在可以使用fetch https developer mozilla org en US docs Web API Fetc
  • 检测 JavaScript 代码中的拼写错误

    在Python世界中 使用最广泛的静态代码分析工具之一 pylint has a 特别检查 https stackoverflow com questions 27162315 automated docstring and comment
  • iOS Javascript 引擎 parseFloat(1) 返回负数

    这段代码将使错误出现 function causeBug d var k var n parseFloat 1 var c Math abs d if n lt 0 k else k return k n function for var
  • 根据唯一测试提取站点地图 URL 和 cy.request() 每个 URL (Cypress) [重复]

    这个问题在这里已经有答案了 将 Cypress 与 TypeScript 结合使用 我的代码目标是提取 sitemap xml 中的所有 URL 和 cy request 每个 URL 的状态 200 这个版本的工作原理 describe

随机推荐