Xamarin.Mac-Architektur

Dieser Leitfaden untersucht Xamarin.Mac und seine Beziehung zu Objective-C einem niedrigen Niveau. Es werden Konzepte wie Kompilierung, Selektoren, registrarsApp-Start und der Generator erläutert.

Übersicht

Xamarin.Mac-Anwendungen werden in der Mono-Ausführungsumgebung ausgeführt und verwenden den Compiler von Xamarin zum Kompilieren in Zwischensprache (IL), der dann just-in-Time (JIT) zur Laufzeit in systemeigenem Code kompiliert wird. Dies wird parallel zur Objective-C Runtime ausgeführt. Beide Laufzeitumgebungen werden auf einem UNIX-ähnlichen Kernel ausgeführt, insbesondere XNU, und machen verschiedene APIs für den Benutzercode verfügbar, sodass Entwickler auf das zugrunde liegende systemeigene oder verwaltete System zugreifen können.

Das folgende Diagramm zeigt eine grundlegende Übersicht über diese Architektur:

Diagram showing a basic overview of the architecture

Systemeigener und verwalteter Code

Bei der Entwicklung für Xamarin werden häufig die Begriffe systemeigener und verwalteter Code verwendet. Verwalteter Code ist Code, der von der .NET Framework Common Language Runtime verwaltet wird, oder in Xamarins Fall: der Mono-Runtime.

Systemeigener Code ist Code, der nativ auf der spezifischen Plattform ausgeführt wird (z Objective-C . B. AOT kompilierter Code, auf einem ARM-Chip). In diesem Leitfaden wird erläutert, wie Ihr verwalteter Code in systemeigenem Code kompiliert wird, und erläutert, wie eine Xamarin.Mac-Anwendung funktioniert, indem Sie die Mac-APIs von Apple über die Verwendung von Bindungen nutzen und gleichzeitig Zugriff auf . BCL von NET und eine anspruchsvolle Sprache wie C#.

Anforderungen

Sie benötigen Folgendes, um eine macOS-Anwendung mit Xamarin.Mac zu erstellen:

  • Ein Mac mit macOS Sierra (10.12) oder höher.
  • Die neueste Version von Xcode (installiert aus dem App Store)
  • Die neueste Version von Xamarin.Mac und Visual Studio für Mac

Für das Ausführen von mit Xamarin-Mac erstellten Mac-Anwendungen müssen die folgenden Systemanforderungen erfüllt werden:

  • Ein Mac mit Mac OS X 10.7 oder höher.

Kompilierung

Wenn Sie eine Xamarin-Plattformanwendung kompilieren, wird der Mono C#-Compiler (oder F#) ausgeführt und kompiliert Ihren C#- und F#-Code in Microsoft Intermediate Language (MSIL oder IL). Xamarin.Mac verwendet dann zur Laufzeit einen Just in Time (JIT) -Compiler, um nativen Code zu kompilieren und die Ausführung bei Bedarf auf der richtigen Architektur zu ermöglichen.

Dies ist im Gegensatz zu Xamarin.iOS, das die AOT-Kompilierung verwendet. Bei Verwendung des AOT-Compilers werden alle Assemblys und alle darin enthaltenen Methoden zur Buildzeit kompiliert. Bei JIT erfolgt die Kompilierung nur bei Bedarf für die ausgeführten Methoden.

Bei Xamarin.Mac-Anwendungen wird Mono in der Regel in das App-Bündel eingebettet (und als Embedded Mono bezeichnet). Bei Verwendung der klassischen Xamarin.Mac-API kann die Anwendung stattdessen System Mono verwenden, dies wird jedoch in der einheitlichen API nicht unterstützt. System Mono bezieht sich auf Mono, das im Betriebssystem installiert wurde. Beim Starten der Anwendung verwendet die Xamarin.Mac-App dies.

Selektoren

Mit Xamarin haben wir zwei separate Ökosysteme, .NET und Apple, die wir zusammenbringen müssen, um so optimiert wie möglich zu erscheinen, um sicherzustellen, dass das Endziel eine reibungslose Benutzererfahrung ist. Wir haben im Abschnitt oben gesehen, wie die beiden Laufzeiten kommunizieren, und Sie haben möglicherweise sehr gut von dem Begriff "Bindungen" gehört, der es den nativen Mac-APIs ermöglicht, in Xamarin verwendet zu werden. Bindungen werden in der Objective-C Bindungsdokumentation ausführlich erläutert, also lassen Sie uns jetzt untersuchen, wie Xamarin.Mac unter der Haube funktioniert.

Zunächst muss es eine Möglichkeit geben, C# verfügbar zu Objective-C machen, die über Selektoren durchgeführt wird. Eine Auswahl ist eine Nachricht, die an ein Objekt oder eine Klasse gesendet wird. Dies Objective-C erfolgt über die objc_msgSend Funktionen. Weitere Informationen zur Verwendung von Selektoren finden Sie im iOS-AuswahlhandbuchObjective-C. Es muss auch eine Möglichkeit geben, verwalteten Code Objective-Cverfügbar zu machen, was aufgrund der Tatsache komplizierter ist, dass Objective-C nichts über den verwalteten Code weiß. Um dies zu umgehen, verwenden wir eine registrar. Dies wird im nächsten Abschnitt ausführlicher erläutert.

Registrar

Wie oben Erwähnung, ist der Code, der registrar verwalteten Code Objective-Cverfügbar macht. Dazu wird eine Liste jeder verwalteten Klasse erstellt, die von NSObject abgeleitet wird:

  • Für alle Klassen, die keine vorhandene Objective-C Klasse umschließen, erstellt sie eine neue Objective-C Klasse mit Objective-C Mitgliedern Spiegel alle verwalteten Member, die über ein [Export] Attribut verfügen.
  • In den Implementierungen für jedes Objective-C-Element wird Code automatisch hinzugefügt, um das Spiegel verwaltete Mitglied aufzurufen.

Der folgende Pseudocode zeigt ein Beispiel dafür, wie dies geschieht:

C# (verwalteter Code):

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

Objective-C (systemeigener Code):

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

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

Der verwaltete Code kann die Attribute [Register][Export]und , die registrar verwendet werden, um zu wissen, dass das Objekt verfügbar Objective-Cgemacht werden muss. Das [Register]-Attribut wird verwendet, um den Namen der generierten Objective-C Klasse anzugeben, falls der generierte Standardname nicht geeignet ist. Alle von NSObject abgeleiteten Klassen werden automatisch bei Objective-C. Das erforderliche [Export]-Attribut enthält eine Zeichenfolge, die als Selektor in der generierten Objective-C Klasse verwendet wird.

Es gibt zwei Arten von registrars Verwendung in Xamarin.Mac – dynamisch und statisch:

  • Dynamisch – registrars Dies ist die Standardeinstellung registrar für alle Xamarin.Mac-Builds. Die Dynamische registrar führt die Registrierung aller Typen in Ihrer Assembly zur Laufzeit durch. Dazu werden Funktionen verwendet, die von Objective-Cder Laufzeit-API bereitgestellt werden. Die Dynamische registrar hat daher einen langsameren Start, aber eine schnellere Buildzeit. Systemeigene Funktionen (in der Regel in C), die als Trampoline bezeichnet werden, werden bei Verwendung der dynamischen registrarsAls Methodenimplementierungen verwendet. Sie variieren zwischen verschiedenen Architekturen.
  • Statisch registrars – Die statische registrar Generiert Objective-C Code während des Builds, der dann in eine statische Bibliothek kompiliert und mit der ausführbaren Datei verknüpft wird. Dies ermöglicht einen schnelleren Start, dauert aber während der Buildzeit länger.

Anwendungsstart

Xamarin.Mac-Startlogik unterscheidet sich je nachdem, ob eingebettetes oder System Mono verwendet wird. Informationen zum Anzeigen des Codes und der Schritte für den Start der Xamarin.Mac-Anwendung finden Sie in der Startheaderdatei im öffentlichen xamarin-macios-Repository.

Generator

Xamarin.Mac enthält Definitionen für jede Mac-API. Sie können eines dieser Elemente im MaciOS-GitHub-Repository durchsuchen. Diese Definitionen enthalten Schnittstellen mit Attributen sowie alle erforderlichen Methoden und Eigenschaften. Beispielsweise wird der folgende Code verwendet, um ein NSBox-Objekt im AppKit-Namespace zu definieren. Beachten Sie, dass es sich um eine Schnittstelle mit einer Reihe von Methoden und Eigenschaften handelt:

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

    …

}

Der Generator, der in Xamarin.Mac aufgerufen wird bmac , verwendet diese Definitionsdateien und verwendet .NET-Tools, um sie in einer temporären Assembly zu kompilieren. Diese temporäre Assembly kann jedoch nicht zum Aufrufen von Objective-C Code verwendet werden. Der Generator liest dann die temporäre Assembly und generiert C#-Code, der zur Laufzeit verwendet werden kann. Wenn Sie ihrer Definition beispielsweise ein zufälliges Attribut .cs Datei hinzufügen, wird es nicht im ausgegebenen Code angezeigt. Der Generator weiß nicht darüber und weiß daher bmac nicht, ob er in der temporären Assembly gesucht wird, um ihn auszugeben.

Nachdem die Xamarin.Mac.dll erstellt wurde, mmpwird der Packager alle Komponenten zusammen bündeln.

Auf hoher Ebene wird dies erreicht, indem die folgenden Aufgaben ausgeführt werden:

  • Erstellen Sie eine App-Bündelstruktur.
  • Kopieren Sie ihre verwalteten Assemblys.
  • Wenn die Verknüpfung aktiviert ist, führen Sie den verwalteten Linker aus, um Die Assemblys zu optimieren, indem Sie nicht verwendete Teile entfernen.
  • Erstellen Sie eine Startprogrammanwendung, und verknüpfen Sie den Startprogrammcode zusammen mit dem registrar Code im statischen Modus.

Dies wird dann als Teil des Benutzerbuildprozesses ausgeführt, der Benutzercode in eine Assembly kompiliert, die Xamarin.Mac.dll ist und ausgeführt wird mmp , um es zu einem Paket zu machen.

Ausführlichere Informationen zum Linker und zur Verwendung finden Sie im iOS Linker-Handbuch .

Zusammenfassung

In diesem Leitfaden wurde die Kompilierung von Xamarin.Mac-Apps untersucht und Xamarin.Mac und seine Beziehung zu Objective-C.