d10*_*fan 8 javascript xamarin.android
我正在尝试使用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");
Run Code Online (Sandbox Code Playgroud)
这段代码应该能够让人们在应用程序内的html页面上点击一个按钮,调用java,然后调用C#.这没有用.
我想知道是否有人知道问题是什么,或者另一个想法,所以我可以使用monodroid让webkit中的html按钮调用ac#方法,或者能够让我的c#代码调用javascript方法.
jon*_*onp 22
我们退一步吧.您想从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>
Run Code Online (Sandbox Code Playgroud)
现在我们可以进入应用程序本身:
[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");
}
}
Run Code Online (Sandbox Code Playgroud)
Activity1.html是我们要展示的HTML内容.唯一有趣的是我们提供了一个/button/@onClick调用JavaScript片段的属性Foo.run().注意方法名称("run"),它以小写的"r"开头; 我们稍后会回到这里.
还有三个值得注意的事项:
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
Run Code Online (Sandbox Code Playgroud)
这对我来说也没有意义.
view.AddJavascriptInterface()将JavaScript名称"Foo"与类的实例相关联Foo.现在我们需要这个MyWebChromeClient类:
class MyWebChromeClient : WebChromeClient {
}
Run Code Online (Sandbox Code Playgroud)
请注意,它实际上并没有做任何事情,因此使用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 Code Online (Sandbox Code Playgroud)
它只是在Run()调用方法时显示一条短消息.
在Mono for Android构建过程中,为每个子类创建了Android Callable WrappersJava.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
}
Run Code Online (Sandbox Code Playgroud)
在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"),因为安卓/ JavaScript有访问的类型声明了一个run()方法,不是一个Run()方法.
当JavaScript调用时Foo.run(),调用Android Callable Wrapper scratch.webview.Foo.run()方法,通过JNI的快乐,导致Foo.Run()C#方法的执行,这实际上是你想要做的第一个.
如果你不喜欢命名的JavaScript方法run(),或者你想要参数或任何其他东西,你的世界变得更加复杂(至少在Mono for Android 4.2和[Export]支持之前).你需要做两件事之一:
小智 10
// 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);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7249 次 |
| 最近记录: |