Partilhar via


Arquitetura Xamarin.Mac

Este guia explora o Xamarin.Mac e sua relação com um Objective-C nível baixo. Ele explica conceitos como compilação, seletores, registrars, inicialização do aplicativo e gerador.

Visão geral

Os aplicativos Xamarin.Mac são executados no ambiente de execução Mono e usam o compilador do Xamarin para compilar até a Intermediate Language (IL), que é então Just-in-Time (JIT) compilada para código nativo em tempo de execução. Isso é executado lado a lado com o Objective-C Runtime. Ambos os ambientes de tempo de execução são executados sobre um kernel semelhante ao UNIX, especificamente XNU, e expõem várias APIs ao código do usuário, permitindo que os desenvolvedores acessem o sistema nativo ou gerenciado subjacente.

O diagrama abaixo mostra uma visão geral básica dessa arquitetura:

Diagram showing a basic overview of the architecture

Código nativo e gerenciado

Ao desenvolver para o Xamarin, os termos código nativo e gerenciado são frequentemente usados. Código gerenciado é o código que tem sua execução gerenciada pelo .NET Framework Common Language Runtime ou, no caso do Xamarin: o Mono Runtime.

Código nativo é o código que será executado nativamente na plataforma específica (por exemplo, Objective-C ou mesmo código compilado AOT, em um chip ARM). Este guia explora como seu código gerenciado é compilado em código nativo e explica como um aplicativo Xamarin.Mac funciona, fazendo pleno uso das APIs do Mac da Apple por meio do uso de associações, ao mesmo tempo em que tem acesso ao . BCL da NET e uma linguagem sofisticada como C#.

Requisitos

O listado a seguir é necessário para desenvolver um aplicativo do macOS X com Xamarin.Mac:

  • Um Mac com macOS Sierra (10.12) ou superior.
  • A versão mais recente do Xcode (instalada a partir da App Store)
  • A versão mais recente do Xamarin.Mac e Visual Studio para Mac

Aplicativos Mac em execução criados com Xamarin.Mac têm os seguintes requisitos do sistema:

  • Um Mac com Mac OS X 10.7 ou superior.

Compilação

Quando você compila qualquer aplicativo da plataforma Xamarin, o compilador Mono C# (ou F#) será executado e compilará seu código C# e F# em Microsoft Intermediate Language (MSIL ou IL). Em seguida, o Xamarin.Mac usa um compilador Just in Time (JIT) em tempo de execução para compilar código nativo, permitindo a execução na arquitetura correta, conforme necessário.

Isso contrasta com o Xamarin.iOS, que usa a compilação AOT. Ao usar o compilador AOT, todos os assemblies e todos os métodos dentro deles são compilados em tempo de compilação. Com o JIT, a compilação acontece sob demanda apenas para os métodos que são executados.

Com os aplicativos Xamarin.Mac, o Mono geralmente é incorporado ao pacote de aplicativos (e conhecido como Mono incorporado). Ao usar a API Xamarin.Mac clássica, o aplicativo pode usar o System Mono, no entanto, isso não é suportado na API unificada. System Mono refere-se ao Mono que foi instalado no sistema operacional. Na inicialização do aplicativo, o aplicativo Xamarin.Mac usará isso.

Seletores

Com o Xamarin, temos dois ecossistemas separados, .NET e Apple, que precisamos reunir para parecer o mais simplificado possível, para garantir que o objetivo final seja uma experiência de usuário suave. Vimos na seção acima como os dois tempos de execução se comunicam, e você pode muito bem ter ouvido falar do termo 'bindings' que permite que as APIs nativas do Mac sejam usadas no Xamarin. As ligações são explicadas em profundidade na documentação de Objective-C vinculação, portanto, por enquanto, vamos explorar como o Xamarin.Mac funciona sob o capô.

Primeiro, tem que haver uma maneira de expor Objective-C ao C#, o que é feito via seletores. Um seletor é uma mensagem que é enviada para um objeto ou classe. Com Objective-C isso é feito através das funções objc_msgSend. Para obter mais informações sobre como usar seletores, consulte o guia Seletores do iOS.Objective-C Também tem que haver uma maneira de expor o código gerenciado ao Objective-C, o que é mais complicado devido ao fato de que Objective-C não sabe nada sobre o código gerenciado. Para contornar isso, usamos um registrararquivo . Isso explicado com mais detalhes na próxima seção.

Registrar

Como mencionado acima, o código é que expõe o registrar código gerenciado ao Objective-C. Ele faz isso criando uma lista de cada classe gerenciada que deriva de NSObject:

  • Para todas as classes que não estão encapsulando uma classe existente Objective-C , ela cria uma nova Objective-C classe com Objective-C membros espelhando todos os membros gerenciados que têm um [Export] atributo.
  • Nas implementações para cada membro Objective–C, o código é adicionado automaticamente para chamar o membro gerenciado espelhado.

O pseudocódigo abaixo mostra um exemplo de como isso é feito:

C# (código gerenciado):

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

Objective-C (código nativo):

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

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

O código gerenciado pode conter os atributos [Register] e [Export], que o registrar usa para saber que o objeto precisa ser exposto a Objective-C. O atributo [Register] é usado para especificar o nome da classe gerada Objective-C caso o nome gerado padrão não seja adequado. Todas as classes derivadas do NSObject são registradas automaticamente no Objective-C. O atributo [Export] necessário contém uma cadeia de caracteres, que é o seletor usado na classe gerada Objective-C .

Existem dois tipos de registrars usados no Xamarin.Mac – dinâmico e estático:

  • Dinâmico registrars – Este é o padrão registrar para todas as compilações do Xamarin.Mac. A dinâmica registrar faz o registro de todos os tipos em seu assembly em tempo de execução. Ele faz isso usando funções fornecidas pela Objective-CAPI de tempo de execução do . A dinâmica registrar , portanto, tem uma inicialização mais lenta, mas um tempo de construção mais rápido. Funções nativas (geralmente em C), chamadas de trampolins, são usadas como implementações de método ao usar o dinâmico registrars. Eles variam entre diferentes arquiteturas.
  • Estático registrars – O estático registrar gera Objective-C código durante a compilação, que é então compilado em uma biblioteca estática e vinculado ao executável. Isso permite uma inicialização mais rápida, mas leva mais tempo durante o tempo de compilação.

Inicialização do aplicativo

A lógica de inicialização do Xamarin.Mac será diferente dependendo se o Mono incorporado ou do sistema é usado. Para exibir o código e as etapas para a inicialização do aplicativo Xamarin.Mac, consulte o arquivo de cabeçalho de inicialização no repositório público xamarin-macios.

Gerador

O Xamarin.Mac contém definições para cada API do Mac. Você pode navegar por qualquer um deles no repositório github do MaciOS. Essas definições contêm interfaces com atributos, bem como quaisquer métodos e propriedades necessários. Por exemplo, o código a seguir é usado para definir um NSBox no namespace AppKit. Observe que é uma interface com vários métodos e propriedades:

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

    …

}

O gerador, chamado bmac em Xamarin.Mac, usa esses arquivos de definição e usa ferramentas .NET para compilá-los em um assembly temporário. No entanto, esse assembly temporário não é utilizável para chamar Objective-C código. O gerador, em seguida, lê o assembly temporário e gera código C# que pode ser usado em tempo de execução. É por isso que, por exemplo, se você adicionar um atributo aleatório ao seu arquivo de .cs definição, ele não aparecerá no código de saída. O gerador não sabe sobre isso e, portanto bmac , não sabe procurá-lo na montagem temporária para produzi-lo.

Uma vez que o Xamarin.Mac.dll tenha sido criado, o empacotador, mmp, agrupará todos os componentes juntos.

Em alto nível, ele consegue isso executando as seguintes tarefas:

  • Crie uma estrutura de pacote de aplicativos.
  • Copie em seus assemblies gerenciados.
  • Se a vinculação estiver habilitada, execute o vinculador gerenciado para otimizar suas montagens removendo peças não utilizadas.
  • Crie um aplicativo iniciador, vinculando o código do iniciador falado junto com o registrar código se estiver no modo estático.

Em seguida, isso é executado como parte do processo de compilação do usuário que compila o código do usuário em um assembly que faz referência ao Xamarin.Mac.dll e é executado mmp para torná-lo um pacote

Para obter informações mais detalhadas sobre o vinculador e como ele é usado, consulte o Guia do vinculador do iOS.

Resumo

Este guia analisou a compilação de aplicativos Xamarin.Mac e explorou o Xamarin.Mac e sua relação com o Objective-C.