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和谷歌搜索没有相关的命中.真的难倒了.
如果我正确理解你想要做什么,这实际上是不可能的.正如您所暗示的错误消息所示,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运行时,因此您无法独立于该运行时使用它.
此图显示了体系结构的外观,以及运行时如何相互关联:

希望这有助于清理事情!