Architecture Xamarin.Mac

Ce guide explore Xamarin.Mac et sa relation à un Objective-C niveau bas. Il explique les concepts tels que la compilation, les sélecteurs, le registrarslancement de l’application et le générateur.

Vue d’ensemble

Les applications Xamarin.Mac s’exécutent dans l’environnement d’exécution Mono et utilisent le compilateur de Xamarin pour compiler vers le langage intermédiaire (IL), qui est ensuite compilé juste-à-temps (JIT) en code natif au moment de l’exécution. Cela s’exécute côte à côte avec le Objective-C runtime. Les deux environnements d’exécution s’exécutent sur un noyau de type UNIX, en particulier XNU, et exposent diverses API au code utilisateur, ce qui permet aux développeurs d’accéder au système natif ou managé sous-jacent.

Le diagramme ci-dessous présente une vue d’ensemble de base de cette architecture :

Diagram showing a basic overview of the architecture

Code natif et managé

Lors du développement pour Xamarin, les termes natifs et le code managé sont souvent utilisés. Le code managé est du code qui a son exécution gérée par le Common Language Runtime .NET Framework, ou dans le cas de Xamarin : le Runtime Mono.

Le code natif est du code qui s’exécute en mode natif sur la plateforme spécifique (par exemple, Objective-C ou même du code compilé AOT, sur une puce ARM). Ce guide explore la façon dont votre code managé est compilé en code natif et explique comment fonctionne une application Xamarin.Mac, en utilisant pleinement les API Mac d’Apple via l’utilisation de liaisons, tout en ayant accès à . BCL de NET et langage sophistiqué comme C#.

Spécifications

Les éléments suivants sont requis pour développer une application macOS avec Xamarin.Mac :

  • Mac exécutant macOS Sierra (10.12) ou version ultérieure.
  • La dernière version de Xcode (installée à partir de l’App Store)
  • La dernière version de Xamarin.Mac et Visual Studio pour Mac

L’exécution d’applications créées Mac avec Xamarin.Mac a la configuration requise suivante :

  • Mac exécutant Mac OS X 10.7 ou version ultérieure.

Compilation

Lorsque vous compilez n’importe quelle application de plateforme Xamarin, le compilateur Mono C# (ou F#) s’exécute et compile votre code C# et F# dans microsoft Intermediate Language (MSIL ou IL). Xamarin.Mac utilise ensuite un compilateur juste-à-temps (JIT) au moment de l’exécution pour compiler du code natif, ce qui permet l’exécution sur l’architecture appropriée en fonction des besoins.

Contrairement à Xamarin.iOS qui utilise la compilation AOT. Lorsque vous utilisez le compilateur AOT, tous les assemblys et toutes les méthodes qu’ils contiennent sont compilés au moment de la génération. Avec JIT, la compilation se produit à la demande uniquement pour les méthodes qui sont exécutées.

Avec les applications Xamarin.Mac, Mono est généralement incorporé dans le bundle d’applications (et appelé Mono incorporé). Lorsque vous utilisez l’API Xamarin.Mac classique, l’application peut utiliser System Mono, mais cela n’est pas pris en charge dans l’API unifiée. System Mono fait référence à Mono qui a été installé dans le système d’exploitation. Lors du lancement de l’application, l’application Xamarin.Mac l’utilisera.

Sélecteurs

Avec Xamarin, nous avons deux écosystèmes distincts, .NET et Apple, que nous devons rassembler pour sembler aussi rationalisé que possible, pour garantir que l’objectif final est une expérience utilisateur fluide. Nous avons vu dans la section ci-dessus comment les deux runtimes communiquent, et vous avez peut-être très bien entendu entendu parler du terme « liaisons » qui permet aux API Mac natives d’être utilisées dans Xamarin. Les liaisons sont expliquées en détail dans la Objective-C documentation de liaison. Pour l’instant, nous allons explorer le fonctionnement de Xamarin.Mac sous le capot.

Tout d’abord, il doit y avoir un moyen d’exposer Objective-C à C#, ce qui est fait via des sélecteurs. Un sélecteur est un message envoyé à un objet ou à une classe. Pour Objective-C ce faire, utilisez les fonctions objc_msgSend . Pour plus d’informations sur l’utilisation des sélecteurs, reportez-vous au guide des sélecteurs iOS.Objective-C Il doit également y avoir un moyen d’exposer du code managé à Objective-C, ce qui est plus compliqué en raison du fait que Objective-C rien ne connaît le code managé. Pour contourner ce problème, nous utilisons un registrar. Cela a été expliqué plus en détail dans la section suivante.

Registrar

Comme mentionné ci-dessus, il s’agit du registrar code qui expose le code managé à Objective-C. Pour ce faire, créez une liste de chaque classe managée qui dérive de NSObject :

  • Pour toutes les classes qui n’encapsulent pas une classe existanteObjective-C, elle crée une Objective-C classe avec Objective-C des membres miroir tous les membres gérés qui ont un [Export] attribut.
  • Dans les implémentations de chaque membre Objective-C, le code est ajouté automatiquement pour appeler le membre managé miroir ed.

Le pseudo-code ci-dessous montre un exemple de la façon dont cela est effectué :

C# (code managé) :

class MyViewController : UIViewController{
    [Export ("myFunc")]
    public void MyFunc ()
    {
    }
 }

Objective-C (code natif) :

@interface MyViewController : UIViewController
 - (void)myFunc;
@end

@implementation MyViewController
- (void)myFunc {
    // Code to call the managed C# MyFunc method in MyViewController
}
@end

Le code managé peut contenir les attributs et [Register] [Export], que les registrar utilisations permettent de savoir que l’objet doit être exposé à Objective-C. L’attribut [Register] est utilisé pour spécifier le nom de la classe générée Objective-C si le nom généré par défaut n’est pas approprié. Toutes les classes dérivées de NSObject sont automatiquement inscrites auprès Objective-Cde . L’attribut [Export] requis contient une chaîne, qui est le sélecteur utilisé dans la classe générée Objective-C .

Il existe deux types d’utilisation registrars dans Xamarin.Mac : dynamique et statique :

  • Dynamique registrars : il s’agit de la valeur par défaut registrar pour toutes les builds Xamarin.Mac. La dynamique registrar effectue l’inscription de tous les types dans votre assembly au moment de l’exécution. Pour ce faire, utilisez des fonctions fournies par Objective-Cl’API runtime. La dynamique registrar a donc un démarrage plus lent, mais un temps de génération plus rapide. Les fonctions natives (généralement en C), appelées trampolines, sont utilisées comme implémentations de méthode lors de l’utilisation de la dynamique registrars. Ils varient d’une architecture à l’autre.
  • Statique registrars : la statique registrar génère Objective-C du code pendant la build, qui est ensuite compilée dans une bibliothèque statique et liée à l’exécutable. Cela permet un démarrage plus rapide, mais prend plus de temps pendant la génération.

Lancement de l’application

La logique de démarrage Xamarin.Mac diffère selon que Mono incorporé ou système est utilisé. Pour afficher le code et les étapes du lancement de l’application Xamarin.Mac, reportez-vous au fichier d’en-tête de lancement dans le dépôt public xamarin-macios.

Générateur

Xamarin.Mac contient des définitions pour chaque API Mac. Vous pouvez parcourir l’un de ces éléments sur le dépôt github MaciOS. Ces définitions contiennent des interfaces avec des attributs, ainsi que toutes les méthodes et propriétés nécessaires. Par exemple, le code suivant est utilisé pour définir un NSBox dans l’espace de noms AppKit. Notez qu’il s’agit d’une interface avec plusieurs méthodes et propriétés :

[BaseType (typeof (NSView))]
public interface NSBox {

    …

    [Export ("borderRect")]
    CGRect BorderRect { get; }

    [Export ("titleRect")]
    CGRect TitleRect { get; }

    [Export ("titleCell")]
    NSObject TitleCell { get; }

    [Export ("sizeToFit")]
    void SizeToFit ();

    [Export ("contentViewMargins")]
    CGSize ContentViewMargins { get; set; }

    [Export ("setFrameFromContentFrame:")]
    void SetFrameFromContentFrame (CGRect contentFrame);

    …

}

Le générateur, appelé bmac dans Xamarin.Mac, prend ces fichiers de définition et utilise les outils .NET pour les compiler dans un assembly temporaire. Toutefois, cet assembly temporaire n’est pas utilisable pour appeler Objective-C du code. Le générateur lit ensuite l’assembly temporaire et génère du code C# qui peut être utilisé au moment de l’exécution. C’est pourquoi, par exemple, si vous ajoutez un attribut aléatoire à votre fichier de définition .cs, il ne s’affiche pas dans le code généré. Le générateur ne le sait pas, et ne sait donc bmac pas le rechercher dans l’assembly temporaire pour le générer.

Une fois le Xamarin.Mac.dll créé, le packager, mmpregroupe tous les composants.

À un niveau élevé, elle effectue cette opération en exécutant les tâches suivantes :

  • Créez une structure d’offre groupée d’applications.
  • Copiez dans vos assemblys managés.
  • Si la liaison est activée, exécutez l’éditeur de liens managé pour optimiser vos assemblys en supprimant les parties inutilisées.
  • Créez une application de lanceur, la liaison dans le code du lanceur a parlé avec le registrar code s’il est en mode statique.

Il s’exécute ensuite dans le cadre du processus de génération utilisateur qui compile le code utilisateur dans un assembly qui référence les Xamarin.Mac.dll et s’exécute mmp pour le rendre un package

Pour plus d’informations sur l’éditeur de liens et la façon dont il est utilisé, reportez-vous au guide de l’éditeur de liens iOS.

Résumé

Ce guide a examiné la compilation des applications Xamarin.Mac et a exploré Xamarin.Mac et sa relation avec Objective-C.