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

Nik*_*sev 5 c# java android interop xamarin.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;
    }
}
Run Code Online (Sandbox Code Playgroud)

该活动应仅作为概念验证,因此其简单性.现在,我希望能够从基于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应用程序加载它(我已经关注了这篇博文).找到了ACW类,但是当我尝试创建它的实例时,我收到以下错误:DexClassLoader

找不到本机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();
}
Run Code Online (Sandbox Code Playgroud)

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

Gre*_*les 5

如果我正确理解你想要做什么,这实际上是不可能的.正如您所暗示的错误消息所示,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 ();
    }
}
Run Code Online (Sandbox Code Playgroud)

也就是说,由于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架构

希望这有助于清理事情!