如何在Android应用程序中调用Mono for Android类?

我在Mono for Android项目中创建了一个相当简单的Activity:

[Activity(Label = "AndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")] public class Activity1 : Activity { private string value = "intitial"; [Export] public string GetString() { return value; } [Export] public void SetString(string newValue) { value = newValue; } } 

该活动应仅作为概念validation,因此其简单性。 现在,我希望能够从“普通的”基于Java的Android应用程序调用方法GetString()。

在Xamarin的文档中 ,我已经阅读了Java to Managed interop,这似乎正是我正在寻找的。 如果我理解正确,当Mono for Android应用程序编译时,它会生成称为Android Callable Wrappers(ACW)的Java类。 然后我应该能够从基于Java的Android应用程序调用这些ACW上的方法。

问题是,我如何从基于Java的Android应用程序引用编译的Mono for Android应用程序( apk文件)?

这是我现在卡住的地方,无法找到任何具体的例子。 这里有类似的问题( 这个和这个 )以及一些博客,但它们只是归结为“使用ACW”。 但到底怎么样? 也许我错过了一些明显的东西,不是Android家伙。

我试过的是动态加载我从我的Mono for Android apk中拉出来的dex文件。 我只是把它放在存储卡上,然后尝试使用基于Java的Android应用程序中的DexClassLoader加载它(我已经关注了这篇博文 )。 找到了ACW类,但是当我尝试创建它的实例时,我收到以下错误:

找不到本机Lmno / android / Runtime; .register(Ljava / lang / String; Ljava / lang / Class; Ljava / lang / String;)的实现

我想我必须以某种方式将Mono for Android运行时包含到基于Java的应用程序,但我不知道如何。

编辑:这是我试图加载dex的代码:

 DexClassLoader cl = new DexClassLoader(dexInternalStoragePath.getAbsolutePath(), optimizedDexOutputPath.getAbsolutePath(), null, getClassLoader()); try { Class classActivity1 = cl.loadClass("androidapplication1.Activity1"); // the following line throws the exception Object a = classActivity1.newInstance(); Method getStringMethod = classActivity1.getMethod("GetString"); Object result = getStringMethod.invoke(angel); result = null; } catch (Exception e) { e.printStackTrace(); } 

EDIT2:我现在在这里读到,应该可以直接从Java开始用Mono for Android编写的活动。 我仍然不清楚如何从Java引用Android的Mono,而谷歌搜索没有相关的命中率。 真的难倒了。

如果我正确理解你想要做什么,这实际上是不可能的。 正如您所暗示的错误消息所示,Mono for Android应用程序中的Activity依赖于Mono运行时才能正常运行。 在这种情况下,可调用包装器本身并没有用,因为它只是一个调用Mono运行时的瘦Java包装器类。 如果在构建项目后查看obj / Debug / android / src文件夹,您实际上可以自己查看生成的可调用包装器。 例如:

 package androidapplication9; public class Activity1 extends android.app.Activity implements mono.android.IGCUserPeer { static final String __md_methods; static { __md_methods = "n_onCreate:(Landroid/os/Bundle;)V:GetOnCreate_Landroid_os_Bundle_Handler\n" + ""; mono.android.Runtime.register ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", Activity1.class, __md_methods); } public Activity1 () { super (); if (getClass () == Activity1.class) mono.android.TypeManager.Activate ("AndroidApplication9.Activity1, AndroidApplication9, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", "", this, new java.lang.Object[] { }); } public void onCreate (android.os.Bundle p0) { n_onCreate (p0); } private native void n_onCreate (android.os.Bundle p0); java.util.ArrayList refList; public void monodroidAddReference (java.lang.Object obj) { if (refList == null) refList = new java.util.ArrayList (); refList.add (obj); } public void monodroidClearReferences () { if (refList != null) refList.clear (); } } 

也就是说,由于Android的工作方式,您可以让Java应用程序启动一个在Mono for Android应用程序中定义的活动,就像您启动外部Java活动一样。 当然,这依赖于正在安装的两个应用程序,但会导致Mono for Android应用程序和Mono运行时实际启动以运行该活动。

编辑

更新以回答您在评论中提出的问题。 ExportAttribute基本上只是让你对ACW的生成方式有了更多的控制,允许你指定ACW中应该存在特定的方法或字段以及它应该具有的名称。 当你想在布局中使用像android:onClick属性这样的东西时,这很有用,例如,默认情况下ACW不包含你想要引用的方法。

在Mono for Android应用程序的上下文之外,你无法使用ACW,因为Mono运行时不会出现。 用C#编写的代码在Mono运行时之上执行,在编译期间不会在幕后翻译成Java或类似的东西。 在运行时,有两个运行时并排,Dalvik(Android的运行时)和Mono,可调用的包装器允许两者来回通信。 因此,即使Mono for Android类库仍然依赖于Mono运行时,因此您无法独立于该运行时使用它。

此图显示了体系结构的外观,以及运行时如何相互关联:

Mono for Android架构

希望这有助于清理事情!