Udostępnij za pośrednictwem


Przewodnik: wiązanie biblioteki Kotlin z systemem Android

Ważne

Obecnie badamy użycie powiązań niestandardowych na platformie Xamarin. Weź udział w tej ankiecie , aby poinformować o przyszłych wysiłkach programistycznych.

Platforma Xamarin umożliwia deweloperom mobilnym tworzenie natywnych dla wielu platform aplikacji mobilnych przy użyciu programu Visual Studio i języka C#. Składniki zestawu SDK platformy systemu Android można używać w pudełku, ale w wielu przypadkach chcesz również używać zestawów SDK innych firm napisanych dla tej platformy, a platforma Xamarin umożliwia wykonywanie tych czynności za pośrednictwem powiązań. Aby zintegrować strukturę systemu Android innej firmy z aplikacją platformy Xamarin.Android, należy utworzyć dla niej powiązanie platformy Xamarin.Android, aby można było go używać w aplikacjach.

Platforma Android wraz z natywnymi językami i narzędziami stale ewoluuje, w tym niedawne wprowadzenie języka Kotlin, który ostatecznie zastąpi język Java. Istnieje wiele zestawów SDK 3d, które zostały już zmigrowane z języka Java do Kotlin i stanowi dla nas nowe wyzwania. Mimo że proces powiązania Kotlin jest podobny do języka Java, wymaga dodatkowych kroków i ustawień konfiguracji, aby pomyślnie skompilować i uruchomić jako część aplikacji platformy Xamarin.Android.

Celem tego dokumentu jest przedstawienie wysokiego poziomu podejścia do rozwiązania tego scenariusza i przedstawienie szczegółowego przewodnika krok po kroku z prostym przykładem.

Tło

Kotlin został wydany w lutym 2016 roku i został umieszczony jako alternatywa dla standardowego kompilatora Java w programie Android Studio do 2017 roku. Później w 2019 roku Google ogłosiło, że język programowania Kotlin stał się preferowanym językiem dla deweloperów aplikacji systemu Android. Ogólne podejście do powiązania jest podobne do procesu wiązania zwykłych bibliotek Języka Java z kilkoma ważnymi krokami specyficznymi dla języka Kotlin.

Wymagania wstępne

Aby ukończyć ten przewodnik, potrzebne są następujące elementy:

Tworzenie biblioteki natywnej

Pierwszym krokiem jest utworzenie natywnej biblioteki Kotlin przy użyciu programu Android Studio. Biblioteka jest zwykle dostarczana przez dewelopera innej firmy lub dostępna w repozytorium Maven firmy Google i innych repozytoriach zdalnych. Na przykład w tym samouczku jest tworzone powiązanie biblioteki Kotlin selektora bąbelków:

GitHub BubblePicker demo

  1. Pobierz kod źródłowy z usługi GitHub dla biblioteki i rozpakuj go do lokalnego selektora bąbelków.

  2. Uruchom program Android Studio i wybierz opcję Otwórz istniejący projekt programu Android Studio , wybierając folder lokalny bąbelkowy selektora bąbelków:

    Android Studio Open Project

  3. Sprawdź, czy program Android Studio jest aktualny, w tym Gradle. Kod źródłowy można pomyślnie skompilować w programie Android Studio w wersji 3.5.3, Gradle w wersji 5.4.1. Instrukcje dotyczące aktualizowania narzędzia Gradle do najnowszej wersji narzędzia Gradle można znaleźć tutaj.

  4. Sprawdź, czy jest zainstalowany wymagany zestaw SDK systemu Android. Kod źródłowy wymaga zestawu Android SDK w wersji 25. Otwórz opcję menu Menedżer zestawów SDK narzędzi>, aby zainstalować składniki zestawu SDK.

  5. Zaktualizuj i zsynchronizuj główny plik konfiguracji build.gradle znajdujący się w folderze głównym folderu projektu:

    • Ustaw wersję Kotlin na 1.3.10

      buildscript {
          ext.kotlin_version = '1.3.10'
      }
      
    • Zarejestruj domyślne repozytorium Maven firmy Google, aby można było rozwiązać zależność biblioteki pomocy technicznej:

      allprojects {
          repositories {
              jcenter()
              maven {
                  url "https://maven.google.com"
              }
          }
      }
      
    • Po zaktualizowaniu pliku konfiguracji jest on poza synchronizacją, a narzędzie Gradle wyświetla przycisk Synchronizuj teraz , naciśnij go i poczekaj na ukończenie procesu synchronizacji:

      Android Studio Gradle Sync Now

      Napiwek

      Pamięć podręczna zależności narzędzia Gradle może być uszkodzona. Czasami występuje to po przekroczeniu limitu czasu połączenia sieciowego. Ponowne pobieranie zależności i synchronizowanie projektu (wymaga sieci).

      Napiwek

      Stan procesu kompilacji narzędzia Gradle (demona) może być uszkodzony. Zatrzymanie wszystkich demonów narzędzia Gradle może rozwiązać ten problem. Zatrzymaj procesy kompilacji narzędzia Gradle (wymaga ponownego uruchomienia). W przypadku uszkodzonych procesów narzędzia Gradle można również spróbować zamknąć środowisko IDE, a następnie zabić wszystkie procesy Języka Java.

      Napiwek

      Projekt może używać wtyczki innej firmy, która nie jest zgodna z innymi wtyczkami w projekcie lub wersją narzędzia Gradle żądanej przez projekt.

  6. Otwórz menu Gradle po prawej stronie, przejdź do menu zadań bąbelkowych>, wykonaj zadanie kompilacji, naciskając go dwukrotnie i poczekaj na ukończenie procesu kompilacji:

    Android Studio Gradle Execute Task

  7. Otwórz przeglądarkę plików folderów głównych i przejdź do folderu kompilacji: Bubble-Picker —> bubblepicker — build —>> outputs —> aar, save the bubblepicker-release.aar file as bubblepicker-v1.0.aar, ten plik będzie używany w dalszej części procesu powiązania:

    Android Studio AAR Output

Plik AAR to archiwum systemu Android, które zawiera skompilowany kod źródłowy i zasoby Kotlin, wymagane przez system Android do uruchomienia aplikacji przy użyciu tego zestawu SDK.

Przygotowywanie metadanych

Drugim krokiem jest przygotowanie pliku transformacji metadanych, który jest używany przez platformę Xamarin.Android do generowania odpowiednich klas języka C#. Projekt powiązania platformy Xamarin.Android odnajdzie wszystkie klasy natywne i elementy członkowskie z danego archiwum systemu Android, a następnie generuje plik XML z odpowiednimi metadanymi. Następnie ręcznie utworzony plik przekształcenia metadanych jest stosowany do wcześniej wygenerowanego punktu odniesienia w celu utworzenia końcowego pliku definicji XML używanego do generowania kodu C#.

Metadane używają składni XPath i są używane przez generator powiązań w celu wywierania wpływu na tworzenie zestawu powiązania. Artykuł Java Binding Metadata (Metadane powiązania języka Java) zawiera więcej informacji na temat przekształceń, które można zastosować:

  1. Utwórz pusty plik Metadata.xml :

    <?xml version="1.0" encoding="UTF-8"?>
    <metadata>
    </metadata>
    
  2. Zdefiniuj przekształcenia xml:

  • Natywna biblioteka Kotlin ma dwie zależności, których nie chcesz uwidaczniać w świecie języka C#, definiują dwa przekształcenia, aby je całkowicie zignorować. Należy powiedzieć, że natywne elementy członkowskie nie zostaną usunięte z wynikowego pliku binarnego, a tylko klasy języka C# nie zostaną wygenerowane. Dekompiler języka Java może służyć do identyfikowania zależności. Uruchom narzędzie i otwórz utworzony wcześniej plik AAR, w wyniku czego zostanie wyświetlona struktura archiwum systemu Android, odzwierciedlając wszystkie zależności, wartości, zasoby, manifest i klasy:

    Java Decompiler Dependencies

    Przekształcenia pomijania przetwarzania tych pakietów są definiowane przy użyciu instrukcji XPath:

    <remove-node path="/api/package[starts-with(@name,'org.jbox2d')]" />
    <remove-node path="/api/package[starts-with(@name,'org.slf4j')]" />
    
  • Klasa natywna BubblePicker ma dwie metody getBackgroundColor i setBackgroundColor następująca transformacja zmieni ją na właściwość języka C# BackgroundColor :

    <attr path="/api/package[@name='com.igalata.bubblepicker.rendering']/class[@name='BubblePicker']/method[@name='getBackground' and count(parameter)=0]" name="propertyName">BackgroundColor</attr>
    <attr path="/api/package[@name='com.igalata.bubblepicker.rendering']/class[@name='BubblePicker']/method[@name='setBackground' and count(parameter)=1 and parameter[1][@type='int']]" name="propertyName">BackgroundColor</attr>
    
  • Typy UInt, UShort, ULong, UByte niepodpisane wymagają specjalnej obsługi. W przypadku tych typów Kotlin automatycznie zmienia nazwy metod i typy parametrów, które są odzwierciedlane w wygenerowanym kodzie:

    public open fun fooUIntMethod(value: UInt) : String {
        return "fooUIntMethod${value}"
    }
    

    Ten kod jest kompilowany w następującym kodzie bajtowym Java:

    @NotNull
    public String fooUIntMethod-WZ4Q5Ns(int value) {
    return "fooUIntMethod" + UInt.toString-impl(value);
    }
    

    Ponadto powiązane typy, takie jak UIntArray, UShortArray, ULongArray, UByteArray , również są dotknięte Kotlin. Nazwa metody jest zmieniana tak, aby zawierała dodatkowy sufiks i parametry są zmieniane na tablicę elementów podpisanych wersji tego samego typu. W poniższym przykładzie parametr typu UIntArray jest konwertowany automatycznie na int[] , a nazwa metody zostanie zmieniona z fooUIntArrayMethod na fooUIntArrayMethod--ajY-9A. Ten ostatni jest wykrywany przez narzędzia platformy Xamarin.Android i generowany jako prawidłowa nazwa metody:

    public open fun fooUIntArrayMethod(value: UIntArray) : String {
        return "fooUIntArrayMethod${value.size}"
    }
    

    Ten kod jest kompilowany w następującym kodzie bajtowym Java:

    @NotNull
    public String fooUIntArrayMethod--ajY-9A(@NotNull int[] value) {
        Intrinsics.checkParameterIsNotNull(value, "value");
        return "fooUIntArrayMethod" + UIntArray.getSize-impl(value);
    }
    

    Aby nadać jej zrozumiałą nazwę, do Metadata.xml można dodać następujące metadane, które zaktualizują nazwę z powrotem do pierwotnie zdefiniowanego w kodzie Kotlin:

    <attr path="/api/package[@name='com.microsoft.simplekotlinlib']/class[@name='FooClass']/method[@name='fooUIntArrayMethod--ajY-9A']" name="managedName">fooUIntArrayMethod</attr>
    

    W przykładzie bubblePicker nie ma żadnych elementów członkowskich używających typów niepodpisanych, dlatego nie są wymagane żadne dodatkowe zmiany.

  • Składowe Kotlin z parametrami ogólnymi domyślnie przekształcone w parametry języka Java.Lang.Object Typu. Na przykład metoda Kotlin ma ogólny parametr <T>:

    public open fun <T>fooGenericMethod(value: T) : String {
    return "fooGenericMethod${value}"
    }
    

    Po wygenerowaniu powiązania platformy Xamarin.Android metoda jest uwidoczniona w języku C#, jak pokazano poniżej:

    [Register ("fooGenericMethod", "(Ljava/lang/Object;)Ljava/lang/String;", "GetFooGenericMethod_Ljava_lang_Object_Handler")]
    [JavaTypeParameters (new string[] {
        "T"
    })]
    
    public virtual string FooGenericMethod (Java.Lang.Object value);
    

    Typy ogólne Java i Kotlin nie są obsługiwane przez powiązania platformy Xamarin.Android, dlatego jest tworzona uogólniona metoda języka C#, aby uzyskać dostęp do ogólnego interfejsu API. Jako obejście można utworzyć bibliotekę kotlin otoki i uwidocznić wymagane interfejsy API w sposób silny bez typów ogólnych. Alternatywnie możesz utworzyć pomocników po stronie języka C#, aby rozwiązać ten problem w taki sam sposób za pomocą silnych interfejsów API.

    Napiwek

    Przekształcając metadane, wszelkie zmiany można zastosować do wygenerowanego powiązania. Artykuł Binding Java Library (Wiązanie biblioteki Języka Java) zawiera szczegółowe informacje na temat sposobu generowania i przetwarzania metadanych.

Tworzenie biblioteki powiązań

Następnym krokiem jest utworzenie projektu powiązania platformy Xamarin.Android przy użyciu szablonu powiązania programu Visual Studio, dodanie wymaganych metadanych, odwołań natywnych, a następnie skompilowanie projektu w celu utworzenia biblioteki eksploatacyjnych:

  1. Otwórz Visual Studio dla komputerów Mac i utwórz nowy projekt biblioteki powiązań platformy Xamarin.Android, nadaj mu nazwę w tym przypadku testBubblePicker.Binding i ukończ pracę kreatora. Szablon powiązania platformy Xamarin.Android znajduje się w następującej ścieżce: Biblioteka powiązań biblioteki systemu > Android>:

    Visual Studio Create Binding

    W folderze Przekształcenia znajdują się trzy główne pliki transformacji:

    • Metadata.xml — umożliwia wprowadzanie zmian w ostatnim interfejsie API, takich jak zmiana przestrzeni nazw wygenerowanego powiązania.
    • EnumFields.xml — zawiera mapowanie między stałymi języka Java int i wyliczeniami języka C#.
    • EnumMethods.xml — umożliwia zmianę parametrów metody i zwracanych typów z stałych int języka Java na wyliczenia języka C#.

    Pozostaw puste pliki EnumFields.xml i EnumMethods.xml , a następnie zaktualizuj Metadata.xml , aby zdefiniować przekształcenia.

  2. Zastąp istniejący plik Transformations/Metadata.xml plikiem Metadata.xml utworzonym w poprzednim kroku. W oknie właściwości sprawdź, czy akcja kompilacji pliku jest ustawiona na TransformationFile:

    Visual Studio Metadata

  3. Dodaj plik bubblepicker-v1.0.aar utworzony w kroku 1 do projektu powiązania jako odwołanie natywne. Aby dodać odwołania do biblioteki natywnej, otwórz program finder i przejdź do folderu z archiwum systemu Android. Przeciągnij i upuść archiwum do folderu Jars w Eksplorator rozwiązań. Alternatywnie możesz użyć opcji Dodaj menu kontekstowego w folderze Jars i wybrać pozycję Istniejące pliki.... Wybierz, aby skopiować plik do katalogu na potrzeby tego przewodnika. Upewnij się, że akcja kompilacji jest ustawiona na Wartość LibraryProjectZip:

    Visual Studio Native Reference

  4. Dodaj odwołanie do pakietu NuGet Xamarin.Kotlin.StdLib. Ten pakiet jest powiązaniem dla standardowej biblioteki Kotlin. Bez tego pakietu powiązanie będzie działać tylko wtedy, gdy biblioteka Kotlin nie używa żadnych typów specyficznych dla języka Kotlin. W przeciwnym razie wszystkie te elementy członkowskie nie będą widoczne dla języka C#, a każda aplikacja, która podejmie próbę użycia powiązania, ulegnie awarii w czasie wykonywania.

    Napiwek

    Ze względu na ograniczenie platformy Xamarin.Android można dodać narzędzia powiązania tylko jednego archiwum systemu Android (AAR) dla projektu powiązania. Jeśli należy uwzględnić wiele plików AAR, wymagane jest wiele projektów platformy Xamarin.Android, po jednym na każdy AAR. Gdyby tak było w przypadku tego przewodnika, poprzednie cztery akcje tego kroku musiałyby zostać powtórzone dla każdego archiwum. Alternatywną opcją jest ręczne scalanie wielu archiwów systemu Android jako pojedynczego archiwum i w rezultacie można użyć jednego projektu powiązania platformy Xamarin.Android.

  5. Ostateczną akcją jest skompilowanie biblioteki i nie ma żadnych błędów kompilacji. W przypadku błędów kompilacji można je rozwiązać i obsłużyć przy użyciu pliku Metadata.xml, który został utworzony wcześniej, dodając metadane przekształcenia XML, które będą dodawać, usuwać lub zmieniać nazwy elementów członkowskich biblioteki.

Korzystanie z biblioteki powiązań

Ostatnim krokiem jest korzystanie z biblioteki powiązań platformy Xamarin.Android w aplikacji platformy Xamarin.Android. Utwórz nowy projekt platformy Xamarin.Android, dodaj odwołanie do biblioteki powiązań i renderuj interfejs użytkownika selektora bąbelków:

  1. Utwórz projekt platformy Xamarin.Android. Użyj aplikacji systemu Android dla systemu> Android > jako punktu początkowego, a następnie wybierz opcję Najnowsze i Największe, aby uniknąć problemów ze zgodnością. Wszystkie poniższe kroki są przeznaczone dla tego projektu:

    Visual Studio Create App

  2. Dodaj odwołanie do projektu powiązania lub dodaj odwołanie do utworzonej wcześniej biblioteki DLL:

    Visual Studio Add Binding Reference.png

  3. Dodaj odwołanie do pakietu NuGet Xamarin.Kotlin.StdLib dodanego wcześniej do projektu powiązania platformy Xamarin.Android. Dodaje obsługę dowolnych typów specyficznych dla języka Kotlin, które wymagają przekazania w środowisku uruchomieniowym. Bez tego pakietu można skompilować aplikację, ale ulegnie awarii w czasie wykonywania:

    Visual Studio Add StdLib NuGet

  4. Dodaj kontrolkę BubblePicker do układu systemu Android dla elementu MainActivity. Otwórz plik testBubblePicker/Resources/layout/content_main.xml i dołącz węzeł sterowania BubblePicker jako ostatni element głównej kontrolki RelativeLayout:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout …>
        …
        <com.igalata.bubblepicker.rendering.BubblePicker
            android:id="@+id/picker"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:backgroundColor="@android:color/white" />
    </RelativeLayout>
    
  5. Zaktualizuj kod źródłowy aplikacji i dodaj logikę inicjowania do MainActivityelementu , który aktywuje zestaw SDK selektora bąbelków:

    protected override void OnCreate(Bundle savedInstanceState)
    {
        ...
        var picker = FindViewById<BubblePicker>(Resource.Id.picker);
        picker.BubbleSize = 20;
        picker.Adapter = new BubblePickerAdapter();
        picker.Listener = new BubblePickerListener(picker);
        ...
    }
    

    BubblePickerAdapter i BubblePickerListener to dwie klasy do utworzenia od podstaw, które obsługują dane bąbelków i interakcję sterowania:

    public class BubblePickerAdapter : Java.Lang.Object, IBubblePickerAdapter
    {
        private List<string> _bubbles = new List<string>();
        public int TotalCount => _bubbles.Count;
        public BubblePickerAdapter()
        {
            for (int i = 0; i < 10; i++)
            {
                _bubbles.Add($"Item {i}");
            }
        }
    
        public PickerItem GetItem(int itemIndex)
        {
            if (itemIndex < 0 || itemIndex >= _bubbles.Count)
                return null;
    
            var result = _bubbles[itemIndex];
            var item = new PickerItem(result);
            return item;
        }
    }
    
    public class BubblePickerListener : Java.Lang.Object, IBubblePickerListener
    {
        public View Picker { get; }
        public BubblePickerListener(View picker)
        {
            Picker = picker;
        }
    
        public void OnBubbleDeselected(PickerItem item)
        {
            Snackbar.Make(Picker, $"Deselected: {item.Title}", Snackbar.LengthLong)
                .SetAction("Action", (Android.Views.View.IOnClickListener)null)
                .Show();
        }
    
        public void OnBubbleSelected(PickerItem item)
        {
            Snackbar.Make(Picker, $"Selected: {item.Title}", Snackbar.LengthLong)
            .SetAction("Action", (Android.Views.View.IOnClickListener)null)
            .Show();
        }
    }
    
  6. Uruchom aplikację, która powinna renderować interfejs użytkownika selektora bąbelków:

    BubblePicker demo

    Przykład wymaga dodatkowego kodu do renderowania stylu elementów i obsługi interakcji, ale kontrolka BubblePicker została pomyślnie utworzona i aktywowana.

Gratulacje! Pomyślnie utworzono aplikację platformy Xamarin.Android i bibliotekę powiązań, która korzysta z biblioteki Kotlin.

Teraz powinna istnieć podstawowa aplikacja platformy Xamarin.Android korzystająca z natywnej biblioteki Kotlin za pośrednictwem biblioteki powiązań platformy Xamarin.Android. W tym przewodniku celowo użyto podstawowego przykładu, aby lepiej podkreślić wprowadzone kluczowe pojęcia. W rzeczywistych scenariuszach prawdopodobnie będzie konieczne uwidocznienie większej liczby interfejsów API i zastosowanie do nich przekształceń metadanych.