Partager via


Métadonnées des liaisons Java

Une bibliothèque de liaisons .NET pour Android Java tente d’automatiser une grande partie du travail nécessaire pour lier une bibliothèque Android existante à l’aide d’un outil parfois appelé Générateur de liaisons. Lors de la liaison d’une bibliothèque Java, .NET pour Android inspecte les classes Java et génère une liste de tous les packages, types et membres qui doivent être liés. Cette liste d’API est stockée dans un fichier XML qui se trouve dans le {répertoire du projet}\obj{Configuration}\api.xml.

Emplacement du fichier api.xml dans le dossier obj/Debug

Le générateur de liaisons utilise le fichier api.xml comme instructions pour générer les classes wrapper C# nécessaires. L’extrait de code suivant est un exemple du contenu de 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>

Dans cet exemple, api.xml déclare une classe dans le android package nommé Manifest qui étend le java.lang.Object.

Dans de nombreux cas, l’assistance humaine est nécessaire pour que l’API Java se sente plus « .NET like » ou pour corriger les problèmes qui empêchent la compilation de l’assembly de liaison. Par exemple, il peut être nécessaire de modifier les noms de package Java en espaces de noms .NET, renommer une classe ou modifier le type de retour d’une méthode.

Ces modifications ne doivent pas être effectuées en modifiant directement api.xml . Au lieu de cela, les modifications sont enregistrées dans des fichiers XML spéciaux fournis par le modèle bibliothèque de liaison Java. Lors de la compilation de l’assembly de liaison .NET pour Android, le générateur de liaisons est influencé par ces fichiers de mappage lors de la création de l’assembly de liaison

Le fichier Metadata.xml est le plus important de ces fichiers, car il autorise les modifications à usage général apportées à la liaison, telles que :

  • Renommage des espaces de noms, des classes, des méthodes ou des champs afin qu’ils suivent les conventions .NET.

  • Suppression d’espaces de noms, de classes, de méthodes ou de champs qui ne sont pas nécessaires.

  • Déplacement de classes vers différents espaces de noms.

  • L’ajout de classes de prise en charge supplémentaires pour rendre la conception de la liaison respecte les modèles .NET Framework.

Metadata.xml fichier de transformation

Comme nous l’avons déjà appris, le fichier Metadata.xml est utilisé par le Générateur de liaisons pour influencer la création de l’assembly de liaison. Le format de métadonnées utilise la syntaxe XPath .

Cette implémentation est presque une implémentation complète de XPath 1.0 et prend donc en charge les éléments dans la norme 1.0. Ce fichier est un mécanisme puissant basé sur XPath pour modifier, ajouter, masquer ou déplacer n’importe quel élément ou attribut dans le fichier API. Tous les éléments de règle dans la spécification de métadonnées incluent un path attribut pour identifier le ou les nœuds auxquels la règle doit être appliquée. Voici les types d’éléments disponibles :

  • add-node : ajoute un nœud enfant au nœud spécifié par l’attribut path.
  • attr : définit la valeur d’un attribut de l’élément spécifié par l’attribut path.
  • remove-node : supprime les nœuds correspondant à un XPath spécifié.

Voici un exemple de fichier 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>

Voici quelques-uns des éléments XPath les plus couramment utilisés pour les API Java :

  • interface : utilisé pour localiser une interface Java. Exemple : /interface[@name='AuthListener'].

  • class : utilisé pour localiser une classe . Exemple : /class[@name='MapView'].

  • method : permet de localiser une méthode sur une classe ou une interface Java. Exemple : /class[@name='MapView']/method[@name='setTitleSource'].

  • parameter : identifiez un paramètre pour une méthode. Exemple : /parameter[@name='p0']

Ajout de types

L’élément add-node indique au projet de liaison .NET pour Android d’ajouter une nouvelle classe à api.xml. Par exemple, l’extrait de code suivant dirige le générateur de liaison pour créer une classe avec un constructeur et un seul champ :

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

Suppression de types

Il est possible d’indiquer au générateur de liaisons .NET pour Android d’ignorer un type Java et de ne pas le lier. Pour ce faire, ajoutez un remove-node élément XML au fichier Metadata.xml :

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

Renommer des membres

Impossible de renommer les membres en modifiant directement le fichier api.xml , car .NET pour Android nécessite que les noms Java Native Interface (JNI) d’origine parlent à Java. Par conséquent, l’attribut //class/@name ne peut pas être modifié ; si c’est le cas, la liaison ne fonctionnera pas.

Considérez le cas où nous voulons renommer un type. android.Manifest Pour ce faire, nous pouvons essayer de modifier directement api.xml et de renommer la classe comme suit :

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

Cela entraîne la création du code C# suivant pour la classe wrapper :

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

Notez que la classe wrapper a été renommée NewNameen , tandis que le type Java d’origine est toujours Manifest. Il n’est plus possible pour la classe de liaison .NET pour Android d’accéder à toutes les méthodes sur android.Manifest; la classe wrapper est liée à un type Java inexistant.

Pour modifier correctement le nom « managé » d’un type encapsulé (ou méthode), il est nécessaire de définir l’attribut managedName comme indiqué dans cet exemple :

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

L’utilisation managedName est requise lors de la tentative de renommer un membre, tel que des classes, des interfaces, des méthodes et des paramètres.

Renommage des EventArg classes wrapper

Lorsque le générateur de liaison .NET pour Android identifie une onXXX méthode setter pour un type d’écouteur, un événement et EventArgs une sous-classe C# sont générés pour prendre en charge une API aromatisée .NET pour le modèle d’écouteur java. Par exemple, considérez la classe et la méthode Java suivantes :

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

.NET pour Android supprime le préfixe on de la méthode setter et utilise 2DSignNextManuever plutôt comme base pour le nom de la EventArgs sous-classe. La sous-classe sera nommée comme suit :

NavigationManager.2DSignNextManueverEventArgs

Il ne s’agit pas d’un nom de classe C# légal. Pour corriger ce problème, l’auteur de liaison doit utiliser l’attribut argsType et fournir un nom C# valide pour la EventArgs sous-classe :

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

Attributs pris en charge

Les sections suivantes décrivent certains des attributs permettant de transformer des API Java.

argsType

Cet attribut est placé sur les méthodes setter pour nommer la EventArg sous-classe qui sera générée pour prendre en charge les écouteurs Java. Cette procédure est décrite plus en détail dans la section Renommer les classes wrapper EventArg dans ce guide.

eventName

Spécifie un nom pour un événement. Si le nom est vide, il empêche la génération d’événements. Cette procédure est décrite plus en détail dans la section Renommer les classes wrapper EventArg.

managedName

Il est utilisé pour modifier le nom d’un package, d’une classe, d’une méthode ou d’un paramètre. Par exemple, pour remplacer le nom de la classe MyClass Java par NewClassName:

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

L’exemple suivant illustre une expression XPath pour renommer la méthode java.lang.object.toString en Java.Lang.Object.NewManagedName:

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

managedType

managedType est utilisé pour modifier le type de retour d’une méthode. Dans certaines situations, le générateur de liaisons déduit incorrectement le type de retour d’une méthode Java, ce qui entraîne une erreur de temps de compilation. Une solution possible dans cette situation consiste à modifier le type de retour de la méthode.

Par exemple, le générateur bindings croit que la méthode de.neom.neoreadersdk.resolution.compareTo() Java doit retourner un int paramètre et prendre Object en tant que paramètres, ce qui entraîne l’erreur du message d’erreur CS0535 : 'DE. Neom.Neoreadersdk.Resolution' n’implémente pas le membre de l’interface « Java.Lang.IComparable.CompareTo(Java.Lang.Object) ».. L’extrait de code suivant montre comment modifier le type du premier paramètre de la méthode C# générée d’un DE.Neom.Neoreadersdk.Resolution à un 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

Modifie le type de retour d’une méthode. Cela ne modifie pas l’attribut de retour (car les modifications apportées aux attributs de retour peuvent entraîner des modifications incompatibles avec la signature JNI). Dans l’exemple suivant, le type de retour de la append méthode est remplacé par SpannableStringBuilder IAppendable:

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

Obfuscated

Les outils qui obfusent les bibliothèques Java peuvent interférer avec le générateur de liaisons .NET pour Android et sa capacité à générer des classes wrapper C#. Les caractéristiques des classes obfuscatées sont les suivantes :

  • Le nom de la classe comprend un $, c’est-à-dire un$.class
  • Le nom de la classe est entièrement compromis de caractères minuscules, c’est-à-dire a.class

Cet extrait de code est un exemple de génération d’un type C# « non obfuscated » :

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

propertyName

Cet attribut peut être utilisé pour modifier le nom d’une propriété gérée.

Un cas spécialisé d’utilisation propertyName implique la situation où une classe Java n’a qu’une méthode setter pour un champ. Dans ce cas, le générateur de liaison souhaite créer une propriété en écriture seule, ce qui est déconseillé dans .NET. L’extrait de code suivant montre comment « supprimer » les propriétés .NET en définissant la propertyName valeur sur une chaîne vide :

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

Notez que les méthodes setter et getter seront toujours créées par le générateur bindings, elles ne seront simplement pas converties en propriété .NET.

expéditeur

Spécifie le paramètre d’une méthode qui doit être le sender paramètre lorsque la méthode est mappée à un événement. La valeur peut être true ou false. Par exemple :

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

visibility

Cet attribut est utilisé pour modifier la visibilité d’une classe, d’une méthode ou d’une propriété. Par exemple, il peut être nécessaire de promouvoir une protected méthode Java afin qu’elle soit un wrapper C# correspondant :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>