通过


Java 绑定元数据

适用于 Android Java 绑定库 的 .NET 会尝试通过工具(有时称为 绑定生成器)自动完成绑定现有 Android 库所需的大部分工作。 绑定 Java 库时,适用于 Android 的 .NET 将检查 Java 类,并生成要绑定的所有包、类型和成员的列表。 此 API 列表存储在可在 {project directory}\obj{Configuration}\api.xmlXML 文件中。

obj/Debug 文件夹中的 api.xml 文件的位置

绑定生成器将使用 api.xml 文件作为指导来生成所需的 C# 包装类。 以下代码片段是 api.xml 文件的内容示例:

<api>
    <package name="android">
        <class abstract="false" deprecated="not deprecated" extends="java.lang.Object"
            extends-generic-aware="java.lang.Object" 
            final="true" 
            name="Manifest" 
            static="false" 
            visibility="public">
            <constructor deprecated="not deprecated" final="false"
                name="Manifest" static="false" type="android.Manifest"
                visibility="public">
            </constructor>
        </class>
...
</api>

在此示例中,api.xml 在扩展 androidManifest 包中声明一个 java.lang.Object 类。

在许多情况下,需要人工协助使 Java API 感觉更像 .NET 或修正阻止绑定程序集编译的问题。 例如,可能需要将 Java 包名称更改为 .NET 命名空间、重命名类或更改方法的返回类型。

不应通过直接修改 api.xml 来实现这些更改。 而是记录更动在由 Java 绑定库模板提供的特殊 XML 文件中。 编译适用于 Android 绑定程序集的 .NET 时,在创建绑定程序集时,绑定生成器将受到这些映射文件的影响

Metadata.xml文件是其中最重要的文件,因为它允许对绑定进行常规用途更改,例如:

  • 重命名命名空间、类、方法或字段,使其遵循 .NET 约定。

  • 删除不需要的命名空间、类、方法或字段。

  • 将类移到不同的命名空间。

  • 添加其他支持类,使绑定的设计遵循 .NET 框架模式。

Metadata.xml 转换文件

正如我们了解到的,绑定生成器使用文件 Metadata.xml 来影响绑定程序集的创建。 元数据格式使用 XPath 语法。

此实现几乎是 XPath 1.0 的完整实现,因此支持 1.0 标准版中的项。 此文件是一种功能强大的基于 XPath 的机制,可用于更改、添加、隐藏或移动 API 文件中的任何元素或属性。 元数据规格中的所有规则元素都包含一个 path 属性,用于标识要向其应用规则的节点(s)。 以下是可用的元素类型:

  • add-node - 将子节点追加到 path 属性指定的节点。
  • attr - 设置 path 属性指定的元素的属性值。
  • remove-node - 移除与指定 XPath 匹配的节点。

下面是 Metadata.xml 文件的一个示例:

<metadata>
    <!-- Normalize the namespace for .NET -->
    <attr path="/api/package[@name='com.evernote.android.job']" 
        name="managedName">Evernote.AndroidJob</attr>

    <!-- Don't need these packages for the .NET for Android binding/public API --> 
    <remove-node path="/api/package[@name='com.evernote.android.job.v14']" />
    <remove-node path="/api/package[@name='com.evernote.android.job.v21']" />

    <!-- Change a parameter name from the generic p0 to a more meaningful one. -->
    <attr path="/api/package[@name='com.evernote.android.job']/class[@name='JobManager']/method[@name='forceApi']/parameter[@name='p0']" 
        name="name">api</attr>
</metadata>

下面列出了 Java API 一些比较常用的 XPath 元素:

  • interface - 用于查找 Java 接口。 例如,/interface[@name='AuthListener']

  • class - 用于查找类。 例如,/class[@name='MapView']

  • method - 用于在 Java 类或接口上查找方法。 例如,/class[@name='MapView']/method[@name='setTitleSource']

  • parameter - 标识方法的参数。 例如,/parameter[@name='p0']

添加类型

add-node元素将告知 .NET for Android 绑定项目向api.xml添加新类。 例如,下面的代码片段将指示绑定生成器使用构造函数和单个字段创建类:

<add-node path="/api/package[@name='org.alljoyn.bus']">
    <class abstract="false" deprecated="not deprecated" final="false" name="AuthListener.AuthRequest" static="true" visibility="public" extends="java.lang.Object">
        <constructor deprecated="not deprecated" final="false" name="AuthListener.AuthRequest" static="false" type="org.alljoyn.bus.AuthListener.AuthRequest" visibility="public" />
        <field name="p0" type="org.alljoyn.bus.AuthListener.Credentials" />
    </class>
</add-node>

删除类型

可以指示适用于 Android 绑定生成器的 .NET 忽略 Java 类型,而不绑定它。 为此,将 XML 元素添加到remove-nodeMetadata.xml文件:

<remove-node path="/api/package[@name='{package_name}']/class[@name='{name}']" />

成员重命名

无法通过直接编辑 api.xml 文件来重命名成员,因为适用于 Android 的 .NET 需要原始 Java 本机接口 (JNI) 名称才能与 Java 通信。 因此,不能更改 //class/@name 属性;如果更改,绑定将不起作用。

请考虑要重命名 android.Manifest 类型的情况。 为实现此目的,我们可能会尝试直接编辑 api.xml 并重命名类,如下所示:

<attr path="/api/package[@name='android']/class[@name='Manifest']" 
    name="name">NewName</attr>

这将导致绑定生成器为包装类创建以下 C# 代码:

[Register ("android/NewName")]
public class NewName : Java.Lang.Object { ... }

请注意,包装类已重命名为 NewName,而原始 Java 类型仍为 Manifest。 .NET for Android 绑定类不再可能访问android.Manifest的任何方法,包装类绑定到不存在的 Java 类型。

若要正确更改包装类型(或方法)的“managed”名称,必须设置 managedName 属性,如以下示例所示:

<attr path="/api/package[@name='android']/class[@name='Manifest']" 
    name="managedName">NewName</attr>

在重命名任何成员(如类、接口、方法和参数)时,必须使用managedName

重命名 EventArg 包装类

当 .NET for Android 绑定生成器标识onXXX侦听器类型的 setter 方法时,将生成 C# 事件和EventArgs子类以支持基于 Java 的侦听器模式的 .NET 风格 API。 例如,请考虑下面的 Java 类和方法:

com.someapp.android.mpa.guidance.NavigationManager.on2DSignNextManuever(NextManueverListener listener);

.NET for Android 将从 setter 方法中删除前缀 on,并将 2DSignNextManuever 用作 EventArgs 子类名称的基础。 子类名称如下所示:

NavigationManager.2DSignNextManueverEventArgs

这不是合法的 C# 类名。 若要更正此问题,绑定作者必须使用 argsType 属性,并为 EventArgs 子类提供有效的 C# 名称:

<attr path="/api/package[@name='com.someapp.android.mpa.guidance']/
    interface[@name='NavigationManager.Listener']/
    method[@name='on2DSignNextManeuver']" 
    name="argsType">NavigationManager.TwoDSignNextManueverEventArgs</attr>

支持的属性

以下各节介绍用于转换 Java API 的一些属性。

argsType

此属性位于 setter 方法上,用于命名将为支持 Java 侦听器而生成的 EventArg 子类。 本指南的重命名 EventArg 包装器类一节中有更详细的介绍。

事件名称

指定事件名称。 如果该名称为空,它将阻止事件生成。 在重命名 EventArg 包装器类部分中对此进行了更详细的描述。

managedName

此属性用于更改包、类、方法或参数的名称。 例如,将 Java 类的名称从 MyClass 更改为 NewClassName

<attr path="/api/package[@name='com.my.application']/class[@name='MyClass']" 
    name="managedName">NewClassName</attr>

下一个示例演示了如何使用 XPath 表达式将方法 java.lang.object.toString 重命名为 Java.Lang.Object.NewManagedName

<attr path="/api/package[@name='java.lang']/class[@name='Object']/method[@name='toString']" 
    name="managedName">NewMethodName</attr>

managedType

managedType 用于更改方法的返回类型。 在某些情况下,绑定生成器将错误地推断 Java 方法的返回类型,这将导致编译时错误。 在此情况下,一种可行的解决方案是更改方法的返回类型。

例如,绑定生成器认为 Java 方法 de.neom.neoreadersdk.resolution.compareTo() 应返回 int 并采用 Object 作为参数,这会导致错误消息错误 CS0535: 'DE.Neom.Neoreadersdk.Resolution' 未实现接口成员 'Java.Lang.IComparable.CompareTo(Java.Lang.Object)'。 下面的代码片段演示如何将生成的 C# 方法的第一个参数类型从 DE.Neom.Neoreadersdk.Resolution 更改为 Java.Lang.Object

<attr path="/api/package[@name='de.neom.neoreadersdk']/
    class[@name='Resolution']/
    method[@name='compareTo' and count(parameter)=1 and
    parameter[1][@type='de.neom.neoreadersdk.Resolution']]/
    parameter[1]" name="managedType">Java.Lang.Object</attr> 

managedReturn

更改方法的返回类型。 这不会更改返回属性(因为更改返回属性会导致对 JNI 签名的不兼容更改)。 在以下示例中,append方法的返回类型从SpannableStringBuilder更改为IAppendable:

<attr path="/api/package[@name='android.text']/
    class[@name='SpannableStringBuilder']/
    method[@name='append']" 
    name="managedReturn">Java.Lang.IAppendable</attr>

混淆

混淆 Java 库的工具可能会干扰 .NET for Android 绑定生成器及其生成 C# 包装器类的功能。 混淆类的特征包括:

  • 类名包括 $,即 a$.class
  • 类名完全由小写字母组成,例如:a.class

此代码片段举例说明如何生成“非混淆”C# 类型:

<attr path="/api/package[@name='{package_name}']/class[@name='{name}']" 
    name="obfuscated">false</attr>

属性名称

此属性可用于更改托管属性的名称。

使用专门用例 propertyName 的情况之一是针对某个 Java 类的字段仅有 setter 方法的情况。 在这种情况下,绑定生成器将需要创建只写属性,而在 .NET 中不建议此做法。 以下代码片段演示了如何通过将 propertyName 设置为空字符串来“删除”.NET 属性:

<attr path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='setResourceDescriptor' 
    and count(parameter)=1 
    and parameter[1][@type='java.lang.String']]" 
    name="propertyName"></attr>
<attr path="/api/package[@name='org.java_websocket.handshake']/class[@name='HandshakeImpl1Client']/method[@name='getResourceDescriptor' 
    and count(parameter)=0]" 
    name="propertyName"></attr>

请注意,Setter 和 getter 方法仍由绑定生成器创建,它们不会转换为 .NET 属性。

发送方

当方法映射到事件时,指定方法的哪个参数应为 sender 参数。 值可为 truefalse。 例如:

<attr path="/api/package[@name='android.app']/
    interface[@name='TimePickerDialog.OnTimeSetListener']/
    method[@name='onTimeSet']/
    parameter[@name='view']" 
    name="sender">true</ attr>

可见性

此属性用于更改类、方法或属性的可见性。 例如,可能需要升级 protected Java 方法,使其对应的 C# 包装器为 public

<!-- Change the visibility of a class -->
<attr path="/api/package[@name='namespace']/class[@name='ClassName']" name="visibility">public</attr>

<!-- Change the visibility of a method --> 
<attr path="/api/package[@name='namespace']/class[@name='ClassName']/method[@name='MethodName']" name="visibility">public</attr>