Share via


Architettura di Xamarin.Mac

Questa guida illustra Xamarin.Mac e la relativa relazione con Objective-C a un livello basso. Vengono illustrati concetti quali compilazione, selettori, registrarsavvio dell'app e generatore.

Panoramica

Le applicazioni Xamarin.Mac vengono eseguite all'interno dell'ambiente di esecuzione mono e usano il compilatore di Xamarin per eseguire la compilazione fino al linguaggio intermedio (IL), che viene quindi compilato in jit (Just-in-Time) nel codice nativo in fase di esecuzione. Questa operazione viene eseguita side-by-side con il Objective-C runtime. Entrambi gli ambienti di runtime vengono eseguiti su un kernel simile a UNIX, in particolare XNU, ed espongono varie API al codice utente che consente agli sviluppatori di accedere al sistema nativo o gestito sottostante.

Il diagramma seguente illustra una panoramica di base di questa architettura:

Diagram showing a basic overview of the architecture

Codice nativo e gestito

Quando si sviluppa per Xamarin, vengono spesso usati i termini codice nativo e gestito . Il codice gestito è codice che ha l'esecuzione gestita da Common Language Runtime di .NET Framework o nel caso di Xamarin: Mono Runtime.

Il codice nativo è codice che verrà eseguito in modo nativo nella piattaforma specifica (ad esempio, Objective-C o anche codice compilato AOT, in un chip ARM). Questa guida illustra il modo in cui il codice gestito viene compilato in codice nativo e illustra il funzionamento di un'applicazione Xamarin.Mac, che usa tutte le API Mac di Apple tramite l'uso di associazioni, pur avendo accesso a . BCL di NET e un linguaggio sofisticato, ad esempio C#.

Requisiti

Per sviluppare un'applicazione macOS con Xamarin.Mac è necessario quanto segue:

  • Mac che esegue macOS Sierra (10.12) o versione successiva.
  • La versione più recente di Xcode (installata dall'App Store)
  • La versione più recente di Xamarin.Mac e Visual Studio per Mac

Per eseguire le applicazioni Mac create con Xamarin.Mac sono necessari i requisiti di sistema seguenti:

  • Mac che esegue Mac OS X 10.7 o versione successiva.

Compilazione

Quando si compila un'applicazione di piattaforma Xamarin, il compilatore Mono C# (o F#) verrà eseguito e compilerà il codice C# e F# in Microsoft Intermediate Language (MSIL o IL). Xamarin.Mac usa quindi un compilatore JIT (Just in Time) in fase di esecuzione per compilare codice nativo, consentendo l'esecuzione sull'architettura corretta in base alle esigenze.

A differenza di Xamarin.iOS che usa la compilazione AOT. Quando si usa il compilatore AOT, tutti gli assembly e tutti i metodi all'interno di essi vengono compilati in fase di compilazione. Con JIT, la compilazione avviene su richiesta solo per i metodi eseguiti.

Con le applicazioni Xamarin.Mac, Mono viene in genere incorporato nel bundle dell'app (e denominato Embedded Mono). Quando si usa l'API Xamarin.Mac classica, l'applicazione potrebbe invece usare System Mono, ma questa operazione non è supportata nell'API unificata. System Mono fa riferimento a Mono installato nel sistema operativo. All'avvio dell'applicazione, l'app Xamarin.Mac userà questa operazione.

Selettori

Con Xamarin, sono disponibili due ecosistemi separati, .NET e Apple, che è necessario riunire per sembrare il più semplice possibile, per garantire che l'obiettivo finale sia un'esperienza utente fluida. Nella sezione precedente è stato illustrato il modo in cui i due runtime comunicano e si potrebbe aver sentito molto bene il termine "binding" che consente l'uso delle API Mac native in Xamarin. Le associazioni sono illustrate in modo approfondito nella Objective-C documentazione di associazione, quindi per il momento si esaminerà il funzionamento di Xamarin.Mac sotto le quinte.

Prima di tutto, è necessario esporre Objective-C a C#, operazione eseguita tramite selettori. Un selettore è un messaggio che viene inviato a un oggetto o a una classe. Questa Objective-C operazione viene eseguita tramite le funzioni di objc_msgSend . Per altre informazioni sull'uso dei selettori, vedere la guida ai selettori iOSObjective-C. Esiste anche un modo per esporre il codice gestito a Objective-C, che è più complicato a causa del fatto che Objective-C non conosce nulla del codice gestito. Per aggirare questo problema, si usa un oggetto registrar. Questo argomento è illustrato in modo più dettagliato nella sezione successiva.

Registrar

Come accennato in precedenza, è il registrar codice che espone il codice gestito a Objective-C. A tale scopo, creare un elenco di ogni classe gestita che deriva da NSObject:

  • Per tutte le classi che non eseguono il wrapping di una classe esistente Objective-C , crea una nuova Objective-C classe con Objective-C membri che eseguono il mirroring di tutti i membri gestiti con un [Export] attributo .
  • Nelle implementazioni per ogni membro Objective-C, il codice viene aggiunto automaticamente per chiamare il membro gestito con mirroring.

Lo pseudo-codice seguente mostra un esempio di come viene eseguita questa operazione:

C# (codice gestito):

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

Objective-C (codice nativo):

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

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

Il codice gestito può contenere gli attributi [Register] e [Export], usati registrar da per sapere che l'oggetto deve essere esposto a Objective-C. L'attributo [Register] viene usato per specificare il nome della classe generata Objective-C nel caso in cui il nome generato predefinito non sia adatto. Tutte le classi derivate da NSObject vengono registrate automaticamente con Objective-C. L'attributo [Export] obbligatorio contiene una stringa, ovvero il selettore usato nella classe generata Objective-C .

Esistono due tipi di registrars usati in Xamarin.Mac: dinamici e statici:

  • Dynamic registrars : impostazione predefinita registrar per tutte le build di Xamarin.Mac. La dinamica registrar esegue la registrazione di tutti i tipi nell'assembly in fase di esecuzione. A tale scopo, usare le funzioni fornite dall'API Objective-Cdi runtime. Il dinamico registrar ha quindi un avvio più lento, ma un tempo di compilazione più veloce. Le funzioni native (in genere in C), chiamate trampolini, vengono usate come implementazioni del metodo quando si usa il dinamico registrars. Variano tra architetture diverse.
  • Statico: il codice statico registrars genera Objective-C codice durante la compilazione, che viene quindi compilato in una libreria statica registrar e collegato all'eseguibile. Ciò consente un avvio più rapido, ma richiede più tempo durante il tempo di compilazione.

Avvio dell'applicazione

La logica di avvio di Xamarin.Mac varia a seconda che venga usato Mono incorporato o di sistema. Per visualizzare il codice e i passaggi per l'avvio dell'applicazione Xamarin.Mac, vedere il file di intestazione di avvio nel repository pubblico xamarin-macios.

Generatore

Xamarin.Mac contiene definizioni per ogni API Mac. È possibile esplorare uno di questi nel repository GitHub MaciOS. Queste definizioni contengono interfacce con attributi, nonché i metodi e le proprietà necessari. Ad esempio, il codice seguente viene usato per definire un NSBox nello spazio dei nomi AppKit. Si noti che si tratta di un'interfaccia con diversi metodi e proprietà:

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

    …

}

Il generatore, chiamato bmac in Xamarin.Mac, accetta questi file di definizione e usa gli strumenti .NET per compilarli in un assembly temporaneo. Tuttavia, questo assembly temporaneo non è utilizzabile per chiamare Objective-C il codice. Il generatore legge quindi l'assembly temporaneo e genera codice C# che può essere usato in fase di esecuzione. Questo è il motivo per cui, ad esempio, se si aggiunge un attributo casuale al file di definizione .cs, non verrà visualizzato nel codice restituito. Il generatore non lo conosce e quindi bmac non sa cercarlo nell'assembly temporaneo per restituirlo.

Dopo aver creato il Xamarin.Mac.dll, il packager, mmp, aggrega tutti i componenti.

A livello generale, questo risultato viene ottenuto eseguendo le attività seguenti:

  • Creare una struttura di bundle dell'app.
  • Copiare negli assembly gestiti.
  • Se il collegamento è abilitato, eseguire il linker gestito per ottimizzare gli assembly rimuovendo le parti inutilizzate.
  • Creare un'applicazione di avvio, collegando il codice dell'utilità di avvio con il registrar codice se in modalità statica.

Viene quindi eseguito come parte del processo di compilazione dell'utente che compila il codice utente in un assembly che fa riferimento al Xamarin.Mac.dll ed esegue mmp per renderlo un pacchetto

Per informazioni più dettagliate sul linker e su come viene usato, vedere la guida del linker iOS.

Riepilogo

In questa guida è stata esaminata la compilazione di app Xamarin.Mac ed è stata esaminata la relazione con Xamarin.Mac e la relativa relazione con Objective-C.