共用方式為


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在名為 Manifest 的封裝中android宣告類別,以擴充 java.lang.Object

在許多情況下,需要人為協助,讓 Java API 感覺更像是 .NET,或修正導致系結元件無法編譯的問題。 例如,可能需要將 Java 套件名稱變更為 .NET 命名空間、重新命名類別,或變更方法的傳回類型。

直接修改 api.xml ,就不應達成這些變更。 相反地,變更會記錄在 Java 系結連結庫範本所提供的特殊 XML 檔案中。 編譯 .NET for Android 系結元件時,建立系結元件時,系結產生器將受到這些對應檔的影響

Metadata.xml檔案是其中最重要的檔案,因為它允許對系結進行一般用途的變更,例如:

  • 重新命名命名空間、類別、方法或字段,使其遵循 .NET 慣例。

  • 拿掉不需要的命名空間、類別、方法或欄位。

  • 將類別移至不同的命名空間。

  • 新增其他支持類別,讓系結的設計遵循 .NET Framework 模式。

Metadata.xml轉換檔案

如我們所瞭解,系結產生器會使用Metadata.xml檔案來影響系結元件的建立。 元數據格式使用 XPath 語法。

此實作幾乎是 XPath 1.0 的完整實作,因此支援 1.0 標準中的專案。 此檔案是以強大的 XPath 為基礎的機制,可用來變更、新增、隱藏或移動 API 檔案中的任何項目或屬性。 元數據規格中的所有規則元素都包含 path 屬性,以識別要套用規則的節點。 以下是可用的項目類型:

  • 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);

適用於 Android 的 .NET 會從 setter 方法卸除前置 on 詞,並改為使用 2DSignNextManuever 作為子類別名稱的基礎 EventArgs 。 子類別會命名如下:

NavigationManager.2DSignNextManueverEventArgs

這不是合法的 C# 類別名稱。 若要更正此問題,系結作者必須使用 argsType 屬性,併為子類別提供有效的 C# 名稱 EventArgs

<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 方法上,以命名 EventArg 將產生以支援 Java 接聽程式之子類別。 本指南將詳細說明重新命名 EventArg 包裝函式類別一節

eventName

指定事件的名稱。 如果名稱是空的,則會防止產生事件。 在重新命名 EventArg 包裝函式類別一節中會詳細說明這一點

managedName

這可用來變更封裝、類別、方法或參數的名稱。 例如,將 Java 類別 MyClass 的名稱變更為 NewClassName

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

下一個範例說明將 方法 java.lang.object.toString 重新命名為 Java.Lang.Object.NewManagedName的 XPath 運算式:

<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

這個屬性可用來變更 Managed 屬性的名稱。

使用 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>

請注意,Bindings Generator 仍然會建立 setter 和 getter 方法,它們只會不會轉換成 .NET 屬性。

sender

指定當方法對應至事件時,方法的哪一個參數應該是 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>