Xamarin.Android或MAUI使用jar包/aar包

目录

  • 1、在应用中创建绑定项目
  • 2、项目实际使用情况
    • [2.1 原则说明](#2.1 原则说明)
    • [2.2 返回类型不对的问题](#2.2 返回类型不对的问题)
    • [2.3 未能实现抽象成员](#2.3 未能实现抽象成员)
    • [2.4 更改访问修饰符](#2.4 更改访问修饰符)
    • [2.5 定义的变量名称与类名相同](#2.5 定义的变量名称与类名相同)
    • [2.6 实现通用接口的方法](#2.6 实现通用接口的方法)
  • 3、总结
    • [3.1 类/字段/方法等的查找](#3.1 类/字段/方法等的查找)
    • [3.2 其他说明](#3.2 其他说明)
  • 4、参考资料

在实际环境中,常常会用到java编写的jar包或者aar包(例如:github上的包),但重写有时不可能,所以就需要直接应用jar包或aar包。具体应用如下:

1、在应用中创建绑定项目

这儿有几点要注意:

1、一个aar包对应一个绑定库

2、若绑定aar包时,导入aar包后,选中该包,生成操作为:LibraryProjectZip;若导入的是jar包,生成操作为:EmbeddedJar。还有其他的几种生成操作:

  • 1、InputJar
    这个使用的比较少,一般情况是公司A购买了某商业jar包,但是B公司没有购买,但B公司和A公司有合作,B公司的Xamarin.Android项目中就可以使用这个jar包,但是不能将其签入到自己的DLL中,只能以引用的方式使用。这个生成操作,也是对jar包的一种操作。与EmbeddedJar不同的是,此操作,不会将jar包签入到生成的DLL中,因此如果在Xamarin.Android项目中使用,务必保证用户的手机/App中已经有此jar包
  • 2、ReferenceJar
    这个和上面的类似,当我们使用的jar包或aar包,有用到其他的依赖的jar包,那我们就需要将其他的jar包引入到项目中。但其不会签入到生成的DLL文件中,比较而言,常常使用下面的生成操作:EmbeddedReferenceJar
  • 3、EmbeddedReferenceJar
    和2是类似的功能,只不过会签入到生成的DLL。一般使用这个。
  • 4、EmbeddedNativeLibrary
    有时,我们使用的jar包或者aar包,需要使用.so文件,so文件一般是C/C++编写的共享文件。也就说:Xamarin.Android--->jar/aar--->.so文件。也算是jar包的依赖项。因此这种情况,请在绑定库项目中对so文件的生成操作设置为:EmbeddedNativeLibrary
    另外,在Xamarin.Android项目中,在使用生成DLL文件之前,先手动加载so文件(假如:在绑定库项目中有一个pocketsphinx_jni.so文件,那么引用的代码如下:)
csharp 复制代码
Java.Lang.JavaSystem.LoadLibrary("pocketsphinx_jni");
  • 5、JavaDocJar
    下面的这三个使用的比较少。我就直接引用官网的说明

用于指向符合 Maven 包样式的 Java 库的 Javadoc 存档 Jar(通常为 FOOBAR-javadoc**.jar**)

  • 6、JavaDocIndex

用于指向 API 参考文档 HTML 中的 index.html 文件。

  • 7、JavaSourceJar

用于补充 JavaDocJar,以便首先从源生成 JavaDoc,然后将结果视为 JavaDocIndex,用于符合 Maven 包样式的 Java 库(通常为 FOOBAR-sources**.jar**)。

Xamarin.AndroidMAUI引用jar包的资料比较多,大家可以搜搜。例如:这一篇写的很详细:生成绑定库的基本操作

2、项目实际使用情况

以上的都是理想情况,大家使用的很规范、很标准,但是真正使用的时候,情况就比较复杂。例如,项目中使用的北京CA的移动端的jar包。编译之后出现如下问题:

生成绑定库,在编译之后出现大量的问题。对于出现的问题进行记录和说明

2.1 原则说明

因为我们无法修改jar包(是可以的,但本篇文章不涉及)。因此只能在绑定库项目中使用Metadata.xmlEnumMethods.xmlEnumFields.xml中进行修改

2.2 返回类型不对的问题

在问题截图的第一个问题:"AlgorithmParametersSpi.EngineGetParameterSpec(Class)": 返回类型必须是"Object"才能与重写成员"AlgorithmParametersSpi.EngineGetParameterSpec(Class?)"匹配

  • 错误原因:Xamarin生成的方法返回类型,与jar包的不一致
  • 解决方案:修改返回类型
  • 具体修改:在Metadata.xml中修改返回类型:
csharp 复制代码
<attr path="/api/package[@name='cn.org.bjca.gaia.jcajce.provider.asymmetric.dh']/class[@name='AlgorithmParametersSpi']/method[@name='engineGetParameterSpec']"  name="managedReturn">Java.Lang.Object</attr>

2.3 未能实现抽象成员

截图中的第二个问题:

  • 错误信息:"AsymmetricHybridCipher.Update(byte[], int, int)"隐藏继承的抽象成员"CipherSpiExt.Update(byte[], int, int)"
  • 分析及解决:
    java中的抽象类,若是普通类,则必须实现抽象方法;但是我们可以查看Xamarin生成的类,发现其也是抽象类。而抽象类可以不用实现抽象方法。【说白了,你也没法override这个方法,jar包都不是你的,里面的逻辑也不清楚,因此只有一个方法解决,就是删除它,不管它】
    在Metadata.xml中删除它
csharp 复制代码
<remove-node path="/api/package[@name='cn.org.bjca.gaia.pqc.jcajce.provider.util']/class[@name='AsymmetricHybridCipher']/method[@name='doFinal' and count(parameter)=3 and parameter[1][@type='byte[]'] and parameter[2][@type='int'] and parameter[3][@type='int']]" />

2.4 更改访问修饰符

  • 错误信息:"BCMessageDigest.EngineDigest()": 当重写"protected"继承成员"MessageDigestSpi.EngineDigest()"时,无法更改访问修饰符
  • 错误分析及解决:
    主要是java中使用的protected定义类,因此转换将其生成了public,因此出错,将其设置为protected
    Metadata.xml中修改
csharp 复制代码
<attr path="/api/package[@name='cn.org.bjca.gaia.jcajce.provider.digest']/class[@name='BCMessageDigest']/method[@name='engineDigest' and count(parameter)=0]" name="visibility">protected</attr>

2.5 定义的变量名称与类名相同

点击进入问题,就能看到

定了一个short类型的变量,从jar包中生成的类,变量名称与类名相同。

  • 错误问题:ChangeCipherSpec: 成员名不能与它们的封闭类型相同
  • 解决方法:重命名变量就行
    Metadata.xml中修改
csharp 复制代码
<attr path="/api/package[@name='cn.org.bjca.gaia.crypto.tls']/class[@name='ChangeCipherSpec']/field[@name='change_cipher_spec']" name="managedName">changeCipherSpec</attr>

2.6 实现通用接口的方法

与2.3中不同,有时候必须要生成方法,例如下面截图的这个

因为方法要实现CompareTo接口,因此我们要实现CompareTo方法,其方法很简单,双击进入问题,提示要实现方法

还是刚才的说的原则(jar包黑盒原则,即,我们不知道里面的具体实现,因此给系统一个默认实现即可),默认生成一个简单的方法即可。不过在生成之前,先在类里面找找,是否有方法,只不过生成的不正确。本例中,进入类中,发现其实已经有

csharp 复制代码
public virtual unsafe int CompareTo (global::CN.Org.Bjca.Anysign.Android.Api.Core.IndexObj p0)
{
	const string __id = "compareTo.(Lcn/org/bjca/anysign/android/api/core/IndexObj;)I";
	try {
		JniArgumentValue* __args = stackalloc JniArgumentValue [1];
		__args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle);
		var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args);
		return __rm;
	} finally {
		global::System.GC.KeepAlive (p0);
	}
}

但是参数不正确,参数应该为object的,因此修改参数类型

metadata中修改参数类型

csharp 复制代码
<metadata>
	<attr path="/api/package[@name='cn.org.bjca.anysign.android.api.core']/class[@name='IndexObj']/method[@name='compareTo' and count(parameter)=1 and parameter[1][@type='cn.org.bjca.anysign.android.api.core.IndexObj']]/parameter[1]" name="managedType">Java.Lang.Object</attr>
</metadata>

重新编译后,生成的类的方法就是:

csharp 复制代码
[Register ("compareTo", "(Lcn/org/bjca/anysign/android/api/core/IndexObj;)I", "GetCompareTo_Lcn_org_bjca_anysign_android_api_core_IndexObj_Handler")]
public virtual unsafe int CompareTo (global::Java.Lang.Object p0)
{
	const string __id = "compareTo.(Lcn/org/bjca/anysign/android/api/core/IndexObj;)I";
	try {
		JniArgumentValue* __args = stackalloc JniArgumentValue [1];
		__args [0] = new JniArgumentValue ((p0 == null) ? IntPtr.Zero : ((global::Java.Lang.Object) p0).Handle);
		var __rm = _members.InstanceMethods.InvokeVirtualInt32Method (__id, this, __args);
		return __rm;
	} finally {
		global::System.GC.KeepAlive (p0);
	}
}

参数变成了Java.Lang.Object

3、总结

3.1 类/字段/方法等的查找

metadata中修改,需要根据path精准找到内容,因此path的准确性很重要。但生成的文件中,实际上已经有path定义了,可以直接使用。例如:

  • 找到类
  • 找到方法
  • 参数
    唯一有点注意的就是参数。上面的各种方法、构造器、类、字段等都能找到,但是参数只能自己参加。需要在参数后面添加/parameter[1],可以参照2.6中的使用。

3.2 其他说明

基本上问题就是以上几类,只不过error实在太多,时间成本太高,放弃了,不用了。

4、参考资料

1、Xamarin.Android直接调用so文件
2、官网链接

相关推荐
zlbcdn2 年前
Xamarin.Android中“ADB0020: Android ABI 不匹配。你正将应用支持的“armeabi-v7a;arm64-v8a”异常处理
异常处理·xamarin.android·adb0020