Metagegevens van Java-bindingen

Een .NET voor Android Java Binding Library probeert veel van het werk te automatiseren dat nodig is voor het binden van een bestaande Android-bibliotheek met behulp van een hulpprogramma dat ook wel de Bindingsgenerator wordt genoemd. Wanneer u een Java-bibliotheek bindt, inspecteert .NET voor Android de Java-klassen en genereert u een lijst met alle pakketten, typen en leden die moeten worden gebonden. Deze lijst met API's wordt opgeslagen in een XML-bestand dat te vinden is op {projectmap}\obj{Configuration}\api.xml.

Locatie van het api.xml-bestand in de map Obj/Foutopsporing

De bindingsgenerator gebruikt het api.xml-bestand als richtlijn voor het genereren van de benodigde C#-wrapperklassen. Het volgende codefragment is een voorbeeld van de inhoud van 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>

In dit voorbeeld declareert api.xml een klasse in het pakket android met de naam Manifest die de java.lang.Object uitbreidt.

In veel gevallen is menselijke hulp vereist om ervoor te zorgen dat de Java-API meer '.NET like' voelt of om problemen op te lossen waardoor de bindingsassembly niet kan worden geassembleerd. Het kan bijvoorbeeld nodig zijn om Java-pakketnamen te wijzigen in .NET-naamruimten, de naam van een klasse te wijzigen of het retourtype van een methode te wijzigen.

Deze wijzigingen mogen niet worden bereikt door api.xml rechtstreeks te wijzigen. In plaats daarvan worden wijzigingen vastgelegd in speciale XML-bestanden die worden geleverd door de sjabloon Java Binding Library. Bij het compileren van de .NET voor Android-bindingsassemblement wordt de Bindingsgenerator beïnvloed door deze toewijzingsbestanden bij het creëren van de bindingsassemblement.

Het bestandMetadata.xml is het belangrijkste van deze bestanden, omdat het algemene wijzigingen in de binding toestaat, zoals:

  • Naamruimten, klassen, methoden of velden wijzigen zodat ze .NET-conventies volgen.

  • Naamruimten, klassen, methoden of velden verwijderen die niet nodig zijn.

  • Klassen verplaatsen naar verschillende naamruimten.

  • Extra ondersteuningsklassen toevoegen om het ontwerp van de binding volgens .NET Framework-patronen te laten verlopen.

bestand Metadata.xml transformeren

Zoals we al hebben geleerd, wordt het bestand Metadata.xml gebruikt door de bindingsgenerator om het maken van de bindingsassembly te beïnvloeden. De indeling voor metagegevens maakt gebruik van XPath-syntaxis .

Deze implementatie is bijna een volledige implementatie van XPath 1.0 en ondersteunt dus items in de 1.0-standaard. Dit bestand is een krachtig XPath-gebaseerd mechanisme voor het wijzigen, toevoegen, verbergen of verplaatsen van elementen of kenmerken in het API-bestand. Alle regelelementen in de metagegevensspecificatie bevatten een path kenmerk om de knooppunten te identificeren waarop de regel moet worden toegepast. Hier volgen de beschikbare elementtypen:

  • add-node – voegt een kindknooppunt toe aan het knooppunt dat is opgegeven door het pad-attribuut.
  • attr : hiermee stelt u de waarde in van een kenmerk van het element dat is opgegeven door het padkenmerk.
  • remove-node : verwijdert knooppunten die overeenkomen met een opgegeven XPath.

Hier volgt een voorbeeld van een Metadata.xml-bestand :

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

Hieronder vindt u enkele van de meestgebruikte XPath-elementen voor de Java-API's:

  • interface – Wordt gebruikt om een Java-interface te vinden. bijvoorbeeld /interface[@name='AuthListener'].

  • class – Wordt gebruikt om een klasse te vinden. bijvoorbeeld /class[@name='MapView'].

  • method – Wordt gebruikt om een methode te vinden in een Java-klasse of -interface. bijvoorbeeld /class[@name='MapView']/method[@name='setTitleSource'].

  • parameter – Identificeer een parameter voor een methode. bijvoorbeeld /parameter[@name='p0']

Typen toevoegen

Het add-node element vertelt het bindingsproject .NET voor Android om een nieuwe klasse toe te voegen aan api.xml. Het volgende fragment geeft de bindingsgenerator opdracht om een klasse te maken met een constructor en één veld.

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

Typen verwijderen

Het is mogelijk om de .NET for Android Bindings Generator te instrueren om een Java-type te negeren en niet te binden. Dit wordt gedaan door een remove-node XML-element toe te voegen aan het Metadata.xml-bestand :

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

De naam van leden wijzigen

Het wijzigen van de naam van leden kan niet worden uitgevoerd door het api.xml-bestand rechtstreeks te bewerken, omdat voor .NET voor Android de oorspronkelijke JNI-namen (Java Native Interface) zijn vereist om met Java te communiceren. Daarom kan het //class/@name kenmerk niet worden gewijzigd. Als dit het is, werkt de binding niet.

Denk na over het geval waarin we de naam van een type willen wijzigen. android.Manifest Hiervoor zouden we kunnen proberen api.xml rechtstreeks te bewerken en de klasse op de volgende manier te hernoemen:

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

Dit resulteert in de bindingsgenerator die de volgende C#-code voor de wrapper-klasse maakt:

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

U ziet dat de naam van de wrapper-klasse is veranderd naar NewName, terwijl het oorspronkelijke Java-type nog steeds Manifest is. Het is niet langer mogelijk voor de bindingsklasse .NET voor Android om toegang te krijgen tot methoden op android.Manifest; de wrapper-klasse is gebonden aan een niet-bestaand Java-type.

Als u de naam van een verpakt type (of methode) op de juiste manier wilt wijzigen, moet u het managedName kenmerk instellen zoals wordt weergegeven in dit voorbeeld:

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

Het gebruik managedName is vereist bij het wijzigen van de naam van een lid, zoals klassen, interfaces, methoden en parameters.

De naam van EventArg wrapperklassen wijzigen

Wanneer de bindingsgenerator voor .NET voor Android een onXXX settermethode voor een listenertype identificeert, worden er een C#-gebeurtenis en EventArgs subklasse gegenereerd ter ondersteuning van een .NET-api met smaak voor het java-listenerpatroon. Bekijk bijvoorbeeld de volgende Java-klasse en -methode:

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

.NET voor Android verwijdert het voorvoegsel on uit de settermethode en gebruikt 2DSignNextManuever in plaats daarvan als basis voor de naam van de EventArgs subklasse. De subklasse krijgt een naam die vergelijkbaar is met:

NavigationManager.2DSignNextManueverEventArgs

Dit is geen juridische C#-klassenaam. Om dit probleem op te lossen, moet de auteur van de binding het argsType kenmerk gebruiken en een geldige C#-naam opgeven voor de EventArgs subklasse:

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

Ondersteunde kenmerken

In de volgende secties worden enkele kenmerken beschreven voor het transformeren van Java-API's.

argsType

Dit kenmerk wordt op settermethoden geplaatst om de EventArg subklasse te noemen die wordt gegenereerd ter ondersteuning van Java-listeners. Dit wordt in meer detail beschreven in de sectie EventArg Wrapper-klassen hernoemen in deze handleiding.

evenementnaam

Hiermee geeft u een naam voor een gebeurtenis. Als de naam leeg is, voorkomt deze het genereren van gebeurtenissen. Dit wordt uitgebreid beschreven in de sectie EventArg Wrapper-klassen hernoemen.

managedName

Dit wordt gebruikt om de naam van een pakket, klasse, methode of parameter te wijzigen. Als u bijvoorbeeld de naam van de Java-klasse MyClass wilt wijzigen in NewClassName:

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

In het volgende voorbeeld ziet u een XPath-expressie voor het wijzigen van de naam van de methode java.lang.object.toString in Java.Lang.Object.NewManagedName:

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

managedType

managedType wordt gebruikt om het retourtype van een methode te wijzigen. In sommige gevallen leidt de bindingsgenerator ten onrechte af wat het retourtype van een Java-methode is, wat resulteert in een compilatietijdfout. Een mogelijke oplossing in deze situatie is het wijzigen van het retourtype van de methode.

De Bindings Generator denkt bijvoorbeeld dat de Java-methode de.neom.neoreadersdk.resolution.compareTo() een int moet retourneren en Object als parameters moet aannemen, wat resulteert in het foutbericht Error CS0535: 'DE.Neom.Neoreadersdk.Resolution' implementeert geen interfacelid 'Java.Lang.IComparable.CompareTo(Java.Lang.Object)'. Het volgende codefragment laat zien hoe u het type van de eerste parameter van de gegenereerde C#-methode wijzigt van een DE.Neom.Neoreadersdk.Resolution in een 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> 

beheerdeRetour

Hiermee wijzigt u het retourtype van een methode. Hierdoor wordt het retourkenmerk niet gewijzigd (omdat wijzigingen in retourkenmerken kunnen leiden tot incompatibele wijzigingen in de JNI-handtekening). In het volgende voorbeeld wordt het retourtype van de append methode gewijzigd vanSpannableStringBuilder:IAppendable

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

verborgen

Hulpprogramma's waarmee Java-bibliotheken worden verborgen, kunnen de .NET voor Android Binding Generator verstoren en de mogelijkheid om C#-wrapperklassen te genereren. Kenmerken van verborgen klassen zijn onder andere:

  • De klassenaam bevat een $, bijvoorbeeld a$.class
  • De klassenaam bestaat volledig uit onderkastletters, dat wil zeggen a.class

Dit codefragment is een voorbeeld van hoe een 'onverduisterd' C#-type te genereren:

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

eigenschapsnaam

Dit kenmerk kan worden gebruikt om de naam van een beheerde eigenschap te wijzigen.

Een gespecialiseerd geval van gebruik propertyName omvat de situatie waarin een Java-klasse slechts een settermethode voor een veld heeft. In dit geval wil de bindingsgenerator een eigenschap maken die alleen kan worden geschreven, iets dat in .NET wordt afgeraden. In het volgende fragment ziet u hoe u de .NET-eigenschappen verwijdert door de propertyName eigenschap in te stellen op een lege tekenreeks:

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

Houd er rekening mee dat de setter- en getter-methoden nog steeds worden gemaakt door de bindingsgenerator. Ze worden alleen niet geconverteerd naar een .NET-eigenschap.

afzender

Hiermee geeft u op welke parameter van een methode de sender parameter moet zijn wanneer de methode wordt toegewezen aan een gebeurtenis. De waarde kan true of false. Voorbeeld:

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

zichtbaarheid

Dit kenmerk wordt gebruikt om de zichtbaarheid van een klasse, methode of eigenschap te wijzigen. Het kan bijvoorbeeld nodig zijn om een protected Java-methode te promoveren, zodat deze bijbehorende C#-wrapper is 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>