Vue d’ensemble des Objective-C liaisons
Détails du fonctionnement du processus de liaison
La liaison d’une Objective-C bibliothèque à utiliser avec Xamarin prend trois étapes :
Écrivez une « définition d’API » C# pour décrire comment l’API native est exposée dans .NET et comment elle est mappée au sous-jacent Objective-C. Cette opération est effectuée à l’aide de constructions C# standard telles que
interface
et de divers attributs de liaison (voir cet exemple simple).Une fois que vous avez écrit la « définition d’API » en C#, vous la compilez pour produire un assembly de « liaison ». Cette opération peut être effectuée sur la ligne de commande ou à l’aide d’un projet de liaison dans Visual Studio pour Mac ou Visual Studio.
Cet assembly de « liaison » est ensuite ajouté à votre projet d’application Xamarin, ce qui vous permet d’accéder à la fonctionnalité native à l’aide de l’API que vous avez définie. Le projet de liaison est complètement distinct de vos projets d’application.
Notes
L’étape 1 peut être automatisée avec l’aide de Objective Sharpie. Il examine l’API Objective-C et génère une « définition d’API » C# proposée. Vous pouvez personnaliser les fichiers créés par Objective Sharpie et les utiliser dans un projet de liaison (ou sur la ligne de commande) pour créer votre assembly de liaison. Objective Sharpie ne crée pas de liaisons par lui-même, il s’agit simplement d’une partie facultative du processus plus large.
Vous pouvez également lire plus de détails techniques sur son fonctionnement, ce qui vous aidera à écrire vos liaisons.
Liaisons de ligne de commande
Vous pouvez utiliser pour btouch-native
Xamarin.iOS (ou bmac-native
si vous utilisez Xamarin.Mac) pour générer des liaisons directement. Il fonctionne en passant les définitions d’API C# que vous avez créées manuellement (ou à l’aide de Objective Sharpie) à l’outil en ligne de commande (btouch-native
pour iOS ou bmac-native
pour Mac).
La syntaxe générale pour appeler ces outils est la suivante :
# Use this for Xamarin.iOS:
bash$ /Developer/MonoTouch/usr/bin/btouch-native -e cocos2d.cs -s:enums.cs -x:extensions.cs
# Use this for Xamarin.Mac:
bash$ bmac-native -e cocos2d.cs -s:enums.cs -x:extensions.cs
La commande ci-dessus génère le fichier cocos2d.dll
dans le répertoire actif et contient la bibliothèque entièrement liée que vous pouvez utiliser dans votre projet. Il s’agit de l’outil que Visual Studio pour Mac utilise pour créer vos liaisons si vous utilisez un projet de liaison (décrit ci-dessous).
Projet de liaison
Un projet de liaison peut être créé dans Visual Studio pour Mac ou Visual Studio (Visual Studio prend uniquement en charge les liaisons iOS) et facilite la modification et la création de définitions d’API pour la liaison (plutôt que l’utilisation de la ligne de commande).
Suivez ce guide de prise en main pour voir comment créer et utiliser un projet de liaison pour produire une liaison.
Objective Sharpie
Objective Sharpie est un autre outil en ligne de commande distinct qui facilite les étapes initiales de la création d’une liaison. Il ne crée pas de liaison par lui-même, mais automatise plutôt l’étape initiale de génération d’une définition d’API pour la bibliothèque native cible.
Lisez la documentation Objective Sharpie pour découvrir comment analyser les bibliothèques natives, les frameworks natifs et CocoaPods dans des définitions d’API qui peuvent être intégrées dans des liaisons.
Fonctionnement de la liaison
Il est possible d’utiliser l’attribut [Register],l’attribut [Export] et l’appel manuel Objective-C du sélecteur pour lier manuellement de nouveaux types (précédemment indépendants). Objective-C
Tout d’abord, recherchez un type que vous souhaitez lier. Pour des raisons de discussion (et de simplicité), nous allons lier le type NSEnumerator (qui a déjà été lié dans Foundation.NSEnumerator ; l’implémentation ci-dessous est juste à titre d’exemple).
Deuxièmement, nous devons créer le type C#. Nous allons probablement le placer dans un espace de noms ; Étant donné Objective-C que ne prend pas en charge les espaces de noms, nous devons utiliser l’attribut [Register]
pour modifier le nom de type que Xamarin.iOS enregistrera auprès du Objective-C runtime. Le type C# doit également hériter de Foundation.NSObject :
namespace Example.Binding {
[Register("NSEnumerator")]
class NSEnumerator : NSObject
{
// see steps 3-5
}
}
Troisièmement, consultez la Objective-C documentation et créez des instances ObjCRuntime.Selector pour chaque sélecteur que vous souhaitez utiliser. Placez-les dans le corps de la classe :
static Selector selInit = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");
Quatrièmement, votre type doit fournir des constructeurs. Vous devez chaîner votre appel de constructeur au constructeur de classe de base. Les [Export]
attributs permettent Objective-C au code d’appeler les constructeurs avec le nom de sélecteur spécifié :
[Export("init")]
public NSEnumerator()
: base(NSObjectFlag.Empty)
{
Handle = Messaging.IntPtr_objc_msgSend(this.Handle, selInit.Handle);
}
// This constructor must be present so that Xamarin.iOS
// can create instances of your type from Objective-C code.
public NSEnumerator(IntPtr handle)
: base(handle)
{
}
Cinquièmement, fournissez des méthodes pour chacun des sélecteurs déclarés à l’étape 3. Ceux-ci utilisent objc_msgSend()
pour appeler le sélecteur sur l’objet natif. Notez l’utilisation de Runtime.GetNSObject() pour convertir un en IntPtr
un (sous-) type correctement typé NSObject
. Si vous souhaitez que la méthode puisse être appelée à partir du Objective-C code, le membre doit être virtuel.
[Export("nextObject")]
public virtual NSObject NextObject()
{
return Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle, selNextObject.Handle));
}
// Note that for properties, [Export] goes on the get/set method:
public virtual NSArray AllObjects {
[Export("allObjects")]
get {
return (NSArray) Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle, selAllObjects.Handle));
}
}
En mettant tout en œuvre :
using System;
using Foundation;
using ObjCRuntime;
namespace Example.Binding {
[Register("NSEnumerator")]
class NSEnumerator : NSObject
{
static Selector selInit = new Selector("init");
static Selector selAllObjects = new Selector("allObjects");
static Selector selNextObject = new Selector("nextObject");
[Export("init")]
public NSEnumerator()
: base(NSObjectFlag.Empty)
{
Handle = Messaging.IntPtr_objc_msgSend(this.Handle,
selInit.Handle);
}
public NSEnumerator(IntPtr handle)
: base(handle)
{
}
[Export("nextObject")]
public virtual NSObject NextObject()
{
return Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle,
selNextObject.Handle));
}
// Note that for properties, [Export] goes on the get/set method:
public virtual NSArray AllObjects {
[Export("allObjects")]
get {
return (NSArray) Runtime.GetNSObject(
Messaging.IntPtr_objc_msgSend(this.Handle,
selAllObjects.Handle));
}
}
}
}