Udostępnij za pośrednictwem


Architektura aplikacji systemu iOS

Aplikacje platformy Xamarin.iOS działają w środowisku wykonywania mono i używają pełnej kompilacji AOT (AOT) do kompilowania kodu C# w języku zestawu ARM. Jest to uruchamiane obok środowiska uruchomieniowegoObjective-C. Oba środowiska uruchomieniowe działają na podstawie jądra przypominającego system UNIX, w szczególności XNU, i uwidaczniają różne interfejsy API kodu użytkownika, co umożliwia deweloperom dostęp do bazowego systemu natywnego lub zarządzanego.

Na poniższym diagramie przedstawiono podstawowe omówienie tej architektury:

This diagram shows a basic overview of the Ahead of Time (AOT) compilation architecture

Kod natywny i zarządzany: wyjaśnienie

Podczas opracowywania dla platformy Xamarin są często używane terminy natywne i zarządzane . Kod zarządzany to kod , który ma swoje wykonanie zarządzane przez środowisko uruchomieniowe języka wspólnego programu .NET Framework lub w przypadku platformy Xamarin: środowisko uruchomieniowe Mono. Nazywamy to językiem pośrednim.

Kod natywny to kod, który będzie uruchamiany natywnie na określonej platformie (na przykład lub Objective-C nawet skompilowany kod AOT na chipie ARM). W tym przewodniku opisano sposób kompilowania kodu zarządzanego przez usługę AOT do kodu natywnego oraz wyjaśniono, jak działa aplikacja platformy Xamarin.iOS, umożliwiając pełne korzystanie z interfejsów API systemu iOS firmy Apple przy użyciu powiązań, a jednocześnie dostęp do usługi . Lista BCL platformy NET i zaawansowany język, taki jak C#.

AOT

Podczas kompilowania dowolnej aplikacji platformy Xamarin kompilator Mono C# (lub F#) zostanie uruchomiony i skompiluje kod C# i F# w języku Microsoft Intermediate Language (MSIL). Jeśli używasz platformy Xamarin.Android, aplikacji Xamarin.Mac, a nawet aplikacji Xamarin.iOS w symulatorze, środowisko uruchomieniowe języka wspólnego platformy .NET (CLR) kompiluje zestaw MSIL przy użyciu kompilatora just in time (JIT). W czasie wykonywania jest to kompilowane w kodzie natywnym, który może działać w odpowiedniej architekturze aplikacji.

Istnieje jednak ograniczenie zabezpieczeń systemu iOS ustawione przez firmę Apple, które nie zezwala na wykonywanie dynamicznie generowanego kodu na urządzeniu. Aby upewnić się, że stosujemy się do tych protokołów bezpieczeństwa, program Xamarin.iOS używa kompilatora AHEAD (AOT) do kompilowania kodu zarządzanego. Powoduje to utworzenie natywnego pliku binarnego systemu iOS, opcjonalnie zoptymalizowanego przy użyciu maszyny WIRTUALNEJ LLVM dla urządzeń, które można wdrożyć na procesorze arm firmy Apple. Przybliżony diagram tego, jak to pasuje do siebie, przedstawiono poniżej:

A rough diagram of how this fits together

Korzystanie z usługi AOT ma wiele ograniczeń, które zostały szczegółowo opisane w przewodniku Dotyczącym ograniczeń . Zapewnia również szereg ulepszeń dotyczących trybu JIT poprzez zmniejszenie czasu uruchamiania oraz różne optymalizacje wydajności

Po zapoznaniu się z tym, jak kod jest kompilowany ze źródła do kodu natywnego, przyjrzyjmy się pod maską, aby zobaczyć, jak platforma Xamarin.iOS umożliwia pisanie w pełni natywnych aplikacji systemu iOS

Selektory

Dzięki platformie Xamarin mamy dwa oddzielne ekosystemy, .NET i Apple, które musimy połączyć, aby wydawać się tak usprawnione, jak to możliwe, aby zapewnić, że celem końcowym jest bezproblemowe środowisko użytkownika. W powyższej sekcji pokazano, jak komunikują się dwa środowiska uruchomieniowe, i być może bardzo dobrze znasz termin "powiązania", który umożliwia używanie natywnych interfejsów API systemu iOS na platformie Xamarin. Powiązania zostały szczegółowo wyjaśnione w naszej Objective-C dokumentacji powiązania , więc na razie przyjrzyjmy się, jak działa system iOS pod maską.

Najpierw musi istnieć sposób uwidocznienia języka Objective-C C#, który odbywa się za pośrednictwem selektorów. Selektor to komunikat, który jest wysyłany do obiektu lub klasy. Dzięki Objective-C temu odbywa się za pośrednictwem funkcji objc_msgSend . Aby uzyskać więcej informacji na temat korzystania z selektorów, zapoznaj się z Objective-C przewodnikiem Selektory . Istnieje również sposób uwidocznienia kodu zarządzanego na Objective-Celement , co jest bardziej skomplikowane ze względu na fakt, że Objective-C nie wie nic o zarządzanym kodzie. Aby obejść ten błąd, użyjemy polecenia Registrars. Bardziej szczegółowo wyjaśniono je w następnej sekcji.

Registrars

Jak wspomniano powyżej, jest to registrar kod, który uwidacznia zarządzany kod w pliku Objective-C. W tym celu należy utworzyć listę każdej klasy zarządzanej pochodzącej z obiektu NSObject:

  • Dla wszystkich klas, które nie otaczają istniejącej Objective-C klasy, tworzy nową Objective-C klasę z elementami Objective-C członkowskimi dublującym wszystkie zarządzane elementy członkowskie, które mają atrybut [Export].

  • W implementacjach każdego elementu członkowskiego Objective-C kod jest dodawany automatycznie w celu wywołania elementu członkowskiego zarządzanego przez dublowanie.

Poniższy kod przykładowy przedstawia przykład tego, jak to zrobić:

C# (kod zarządzany)

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

Objective-C:

@interface MyViewController : UIViewController { }

    -(void)myFunc;
@end

@implementation MyViewController {}

    -(void) myFunc
    {
        /* code to call the managed MyViewController.MyFunc method */
    }
@end

Kod zarządzany może zawierać atrybuty [Register] i [Export], których registrar używa, aby wiedzieć, że obiekt musi być uwidoczniony na Objective-C. Atrybut [Register] służy do określania nazwy wygenerowanej Objective-C klasy w przypadku, gdy domyślna wygenerowana nazwa nie jest odpowiednia. Wszystkie klasy pochodzące z obiektu NSObject są automatycznie rejestrowane za pomocą Objective-Cklasy . Wymagany [Export] atrybut zawiera ciąg, który jest selektorem używanym w wygenerowanej Objective-C klasie.

Istnieją dwa typy registrars używane w środowisku Xamarin.iOS — dynamiczny i statyczny:

  • Dynamiczny — dynamiczna registrars funkcja wykonuje registrar rejestrację wszystkich typów w zestawie w czasie wykonywania. Robi to przy użyciu funkcji udostępnianych przez Objective-Cinterfejs API środowiska uruchomieniowego. W związku z tym dynamika registrar ma wolniejsze uruchamianie, ale krótszy czas kompilacji. Jest to ustawienie domyślne dla symulatora systemu iOS. Funkcje natywne (zwykle w języku C), nazywane trampolinami, są używane jako implementacje metod podczas korzystania z dynamicznego registrarselementu . Różnią się one między różnymi architekturami.

  • Static registrars — statyczny registrarObjective-C generuje kod podczas kompilacji, który jest następnie kompilowany w bibliotece statycznej i połączony z plikiem wykonywalnym. Umożliwia to szybsze uruchamianie, ale trwa dłużej w czasie kompilacji. Jest ona używana domyślnie w przypadku kompilacji urządzeń. registrar Statyczny może być również używany z symulatorem mtouch systemu iOS, przekazując --registrar:static jako atrybut w opcjach kompilacji projektu, jak pokazano poniżej:

    Setting Additional mtouch arguments

Aby uzyskać więcej informacji na temat specyfiki systemu rejestracji typów systemu iOS używanego przez platformę Xamarin.iOS, zapoznaj się z przewodnikiem Type (Typ Registrar ).

Uruchamianie aplikacji

Punkt wejścia wszystkich plików wykonywalnych platformy Xamarin.iOS jest dostarczany przez funkcję o nazwie xamarin_main, która inicjuje mono.

W zależności od typu projektu wykonywane są następujące czynności:

  • W przypadku zwykłych aplikacji systemu iOS i tvOS wywoływana jest zarządzana metoda Main dostarczana przez aplikację Xamarin. Ta zarządzana metoda Main wywołuje UIApplication.Mainmetodę , która jest punktem wejścia dla elementu Objective-C. UIApplication.Main jest powiązaniem Objective-Cmetody "s UIApplicationMain ".
  • W przypadku rozszerzeń wywoływana jest funkcja natywna — NSExtensionMain lub (NSExtensionmain dla rozszerzeń systemu WatchOS) dostarczana przez biblioteki firmy Apple. Ponieważ te projekty to biblioteki klas, a nie projekty wykonywalne, nie ma zarządzanych metod Main do wykonania.

Cała ta sekwencja uruchamiania jest kompilowana w bibliotece statycznej, która jest następnie połączona z końcowym plikiem wykonywalnym, aby aplikacja wiedziała, jak wysiąść z ziemi.

W tym momencie nasza aplikacja została uruchomiona, mono działa, jesteśmy w kodzie zarządzanym i wiemy, jak wywoływać kod natywny i być wywoływany z powrotem. Następną rzeczą, którą musimy zrobić, jest rozpoczęcie dodawania kontrolek i interakcyjnego tworzenia aplikacji.

Generator

Rozszerzenie Xamarin.iOS zawiera definicje dla każdego pojedynczego interfejsu API systemu iOS. Możesz przeglądać dowolne z nich w repozytorium GitHub systemu MaciOS. Te definicje zawierają interfejsy z atrybutami, a także wszelkie niezbędne metody i właściwości. Na przykład poniższy kod służy do definiowania paska narzędzi UIToolbar w przestrzeni nazw UIKit. Zwróć uwagę, że jest to interfejs z wieloma metodami i właściwościami:

[BaseType (typeof (UIView))]
public interface UIToolbar : UIBarPositioning {
    [Export ("initWithFrame:")]
    IntPtr Constructor (CGRect frame);

    [Export ("barStyle")]
    UIBarStyle BarStyle { get; set; }

    [Export ("items", ArgumentSemantic.Copy)][NullAllowed]
    UIBarButtonItem [] Items { get; set; }

    [Export ("translucent", ArgumentSemantic.Assign)]
    bool Translucent { [Bind ("isTranslucent")] get; set; }

    // done manually so we can keep this "in sync" with 'Items' property
    //[Export ("setItems:animated:")][PostGet ("Items")]
    //void SetItems (UIBarButtonItem [] items, bool animated);

    [Since (5,0)]
    [Export ("setBackgroundImage:forToolbarPosition:barMetrics:")]
    [Appearance]
    void SetBackgroundImage ([NullAllowed] UIImage backgroundImage, UIToolbarPosition position, UIBarMetrics barMetrics);

    [Since (5,0)]
    [Export ("backgroundImageForToolbarPosition:barMetrics:")]
    [Appearance]
    UIImage GetBackgroundImage (UIToolbarPosition position, UIBarMetrics barMetrics);

    ...
}

Generator o nazwie btouch w środowisku Xamarin.iOS pobiera te pliki definicji i używa narzędzi platformy .NET do kompilowania ich do zestawu tymczasowego. Jednak ten zestaw tymczasowy nie jest używany do wywoływania Objective-C kodu. Następnie generator odczytuje zestaw tymczasowy i generuje kod języka C#, który może być używany w czasie wykonywania. Dlatego na przykład jeśli dodasz losowy atrybut do pliku definicji .cs, nie będzie on wyświetlany w wyjściowym kodzie. Generator nie wie o tym i btouch dlatego nie wie, aby wyszukać go w zestawie tymczasowym, aby go wygenerować.

Po utworzeniu Xamarin.iOS.dll aplikacja mtouch połączy wszystkie składniki.

Osiąga to na wysokim poziomie, wykonując następujące zadania:

  • Tworzenie struktury pakietu aplikacji.
  • Skopiuj do zarządzanych zestawów.
  • Jeśli łączenie jest włączone, uruchom zarządzany konsolidator, aby zoptymalizować zestawy przez zgrywanie nieużywanych części.
  • Kompilacja AOT.
  • Utwórz natywny plik wykonywalny, który generuje serię bibliotek statycznych (po jednym dla każdego zestawu), które są połączone z natywnym plikiem wykonywalnym, tak aby natywny plik wykonywalny składał się z kodu uruchamiania, registrar kodu (jeśli statycznego) i wszystkich danych wyjściowych kompilatora AOT

Aby uzyskać bardziej szczegółowe informacje na temat konsolidatora i sposobu jego użycia, zapoznaj się z przewodnikiem konsolidatora .

Podsumowanie

W tym przewodniku przedstawiono kompilację aplikacji platformy Xamarin.iOS w usłudze AOT oraz zapoznano się z platformą Xamarin.iOS i jej relacją ze szczegółowymi Objective-C informacjami.