Podstawy aplikacji

Migracja aplikacji Google Play z dwóch dekad do Jetpack Compose

Głośniki

  • Kirill Grouchnikov

    Inżynier oprogramowania

  • Jon Boekenoogen

    Inżynier oprogramowania

Informacje

Informacje o wystąpieniu

W tym roku Android oficjalnie przeszedł na Compose jako podstawowe narzędzie do tworzenia wszystkich interfejsów użytkownika, a starsze widoki zostały przeniesione w tryb konserwacji. W przypadku Google Play ta podróż rozpoczęła się w 2020 roku. Migracja do Jetpack Compose, która objęła prawie 2 dekady pracy inżynierów i miliardy użytkowników, została przeprowadzona dzięki sprawdzonym metodom, ścisłej współpracy z głównym zespołem Compose i ciągłemu rozwojowi narzędzi.

Dowiedz się, jak modernizacja Google Play za pomocą Compose przyniosła wymierne korzyści w zakresie szybkości i długoterminowej stabilności. Podczas tej sesji dowiesz się, jak połączyć przepływy pracy związane z projektowaniem w Figma z implementacją Compose, zautomatyzować jakość, aby zapobiec niepotrzebnym rekompozycjom, oraz tworzyć ekspresyjne interfejsy z dynamicznymi kolorami, bogatą typografią i warstwowymi kształtami. Poznasz sprawdzone strategie, które pozwolą Ci szybciej klasyfikować błędy i pewnie skalować migrację do Compose.

Podsumowanie

  • W ciągu 6 lat Google Play przeniosło 97% wyświetleń użytkowników na ekrany korzystające wyłącznie z Compose. W ciągu ostatnich 14 miesięcy wskaźnik zacinania się na głównych stronach spadł o 30%.
  • Stopniowe wdrażanie zmniejsza ryzyko biznesowe w przypadku dużych baz kodu. Zespoły mogą najpierw zapoznać się z funkcją na ekranach o niskim natężeniu ruchu, a następnie przejść do hostowania ComposeView bezpośrednio w głównym elemencie aktywności.
  • Dynamiczne motywy działają całkowicie w kodzie przy użyciu nakładek MaterialTheme i biblioteki Material Color Utilities. Pozwala to uniknąć niszczenia aktywności, chociaż generowanie schematów kolorów podczas kompilacji pomaga ograniczyć opóźnienia w czasie działania.
  • Jednokierunkowy przepływ danych i deklaratywny interfejs użytkownika upraszczają architekturę i eliminują kilka typów sytuacji wyścigu. Równoległe uruchamianie źródeł danych i przekształceń interfejsu skróciło czas oczekiwania na wczytanie Google Play o kilkadziesiąt milisekund.
  • Automatyczne testy Lint wymuszają przestrzeganie zasad dotyczących jakości kodu i systemu projektowania. Google Play używa ich do blokowania kolorów zakodowanych na stałe i oznaczania potencjalnych problemów z wydajnością, takich jak BoxWithConstraints.

Gemini Notebook

Tematy

  • jetpack-compose
  • migracja
  • wydajność
  • przypisywanie tematów
  • unidirectional-data-flow
  • lint-rules
  • developer-velocity

Transkrypcja

Pobierz transkrypcję

Wprowadzenie i wdrożenie Sklepu Google Play

  • Cześć!

  • Mam na imię Jon.

  • Jestem członkiem zespołu Sklepu Google Play.

  • To mój współpracownik Kirill.

  • Dzisiaj opowiemy o tym, jak przenieśliśmy dużą część kodu z systemu View i Fragment do Compose.

  • Zaczynajmy!

  • Jak przebiegało wdrażanie i jaka była jego skala?

  • Baza kodu naszej aplikacji rozwija się organicznie od około 2007 roku.

  • Mamy ponad kilka milionów linii kodu produkcyjnego, 200 ekranów i 500 unikalnych komponentów interfejsu, które są używane na wielu różnych ekranach.

  • W 2020 roku zdaliśmy sobie sprawę, że szybkość, niezawodność i wydajność deweloperów nie spełniają naszych oczekiwań.

  • Zdecydowaliśmy się więc na nowoczesny stos technologiczny interfejsu.

  • Oceniliśmy wiele różnych bibliotek.

  • W tym czasie rozmawialiśmy też z kilkoma znajomymi z AndroidX o Compose. Postanowiliśmy wdrożyć Compose i zostać pierwszym dużym partnerem tej technologii.

  • Jak poszło?

  • 6 lat później 97% wyświetleń w aplikacji Sklep Play odbywa się na ekranach, które korzystają wyłącznie z Compose.

  • Od 2020 roku wszystkie aplikacje na telefony i duże ekrany są tworzone wyłącznie w Compose.

  • Nawet nasze rozszerzone formaty, takie jak XR, TV, Auto i Wear, przeszły na Compose od 2025 roku.

  • Compose odegrał dużą rolę w tym sukcesie i dlatego nadal go używamy.

  • Mają bardzo rozbudowany, kompleksowy zestaw testów, który pomógł nam wdrażać nowe wersje Compose 2 razy w tygodniu.

  • Dzięki wykorzystaniu wersji alfa i nowych interfejsów API możemy korzystać z nowych poprawek błędów i ulepszeń wydajności, a także odkrywać nowe interfejsy API i zapewniać użytkownikom nowe wrażenia.

  • Jeśli chodzi o wydajność, Compose naprawdę zapewnia płynne działanie naszej aplikacji na wszystkich głównych ekranach.

  • To jest strona wyników wyszukiwania, strona główna, strona z informacjami.

  • Te dane – wydajność, zacinanie się i opóźnienie wczytywania – są bardzo ważne dla naszej firmy i dla wygody użytkowników.

  • W ciągu ostatnich 14 miesięcy odnotowaliśmy więc poprawę o 30%.

Plan migracji

  • Ale jak do tego doszło?

  • To właśnie o tym chcemy dziś porozmawiać.

  • Porozmawiajmy o planie migracji.

  • Dlatego w Google Play podjęliśmy wieloetapowe działania.

  • Nie chcieliśmy od razu stawiać wszystkiego na jedną kartę.

  • Podjęliśmy kilka kroków, aby zrozumieć ryzyko i wpływ na naszą działalność, a także nabrać pewności, zanim w pełni zaangażujemy się w to rozwiązanie.

  • Nazwę je: raczkowanie, chodzenie, trucht i bieganie.

  • Dlatego faza raczkowania polegała na zapoznaniu się z Compose.

  • Zaczęliśmy od strony o małym natężeniu ruchu.

  • Może to być strona ustawień, licencje innych firm itp.

  • Twoim głównym celem jest zapoznanie się z biblioteką Compose.

  • Możesz więc przyzwyczaić się do wierszy, kolumn, tekstu, obrazów i wszystkich tego typu elementów.

  • Następnie musisz zacząć przenosić całą infrastrukturę aplikacji i zrozumieć, jak działa ona w Compose.

  • Mogło to być rejestrowanie wyświetleń, kliknięć, motywy, a jednocześnie zmienialiśmy sposób wczytywania danych.

  • Wszystkie te rzeczy są ważne.

  • Jedną z rzeczy, które okazały się pomocne, było zapewnienie spójnego wyglądu wszystkich ekranów. Utworzyliśmy kilka testów jednostkowych i testów funkcjonalnych, aby sprawdzić, czy obiekty motywów w Compose są bezpośrednio mapowane na style XML, typografię, kolory i inne elementy.

  • Gdy już się oswoiliśmy i poczuliśmy się pewniej, postanowiliśmy zacząć chodzić.

  • W naszym przypadku polegało to na wybraniu mniejszego komponentu na ekranie o bardzo dużym natężeniu ruchu i ocenie, jak wygląda taka migracja.

  • Zalecamy użycie elementu, który znajduje się w RecyclerView, aby zrozumieć wszelkie problemy ze zgodnością między systemem View i Compose, a także sprawdzić wydajność i zacinanie się.

  • Sam komponent nie musi być bardzo złożony, ale warto mieć coś, co wykorzystuje układy, tekst, obrazy i inne elementy, które zwykle się pojawiają.

  • W tym obszarze należy zwrócić uwagę na niewielki wzrost zacinania się i opóźnienia, który może się pojawić, ponieważ teraz działają 2 stosy.

  • Masz stos renderowania, który jest w całości w Compose, i stos, który jest w widokach.

  • Będzie więc dochodzić do przepełnienia pamięci, dodatkowego ładowania klas i innych problemów.

  • Jednak w miarę jak będziesz wdrażać coraz więcej funkcji Compose, ten problem zniknie.

  • Jeśli jednak naprawdę potrzebujesz tego ekranu, możesz go wstępnie rozgrzać, aby go dostosować i zmniejszyć koszty w krótkiej perspektywie.

  • Po spacerze przechodzimy do joggingu.

  • To jest etap, gdy już bardzo dobrze się znamy.

  • Zamiast tworzyć pojedynczy komponent na stronie o dużym natężeniu ruchu, utwórz całą stronę o dużym natężeniu ruchu.

  • W tym przypadku zachowaliśmy bibliotekę nawigacji i użyliśmy fragmentów, ale każdy ekran został w pełni zaimplementowany w Compose.

  • Wystarczyło, że fragment zwrócił sam widok ComposeView.

  • Możesz więc oczekiwać mniejszego czasu oczekiwania i mniejszej liczby zacięć.

  • Nie ma już tak dużego problemu z pamięcią i ładowaniem klas, o którym mówiłem.

  • Compose wykonuje też pewne poziomy buforowania na poziomie ComposeView.

  • Jeśli więc masz RecyclerView z wieloma kartami, które wyglądają spójnie i mogą mieć te same ikony, wszystkie te ikony i zasoby są współdzielone przez wszystkie elementy w ComposeView.

  • Potem zaczęliśmy biegać.

  • Wtedy naprawdę dajesz z siebie wszystko.

  • Gdy większość ruchu z aplikacji pochodzi z Compose, przechodzimy na wyższy poziom.

  • Nad ekranami znajduje się Aktywność.

  • Przenieś więc ComposeView do katalogu głównego aktywności.

  • Duża część kodu będzie wyglądać podobnie.

  • Nadal próbujesz wykonać instrukcję nawigacji, w której chcesz na przykład przejść z jednego ekranu na drugi.

  • Ale zamiast wykonywać transakcje Fragment, wywołujesz funkcję typu „composable”.

  • Możesz to zrobić na podstawie biblioteki Nav2 lub Nav3, w zależności od tego, którą wybierzesz.

  • W naszym przypadku nie wszystkie ekrany zostały przeniesione.

  • Wspomniałem, że mamy ich sporo.

  • Dlatego stworzyliśmy zgodność z fragmentami, dzięki której można mieć ekran oparty na fragmentach i wykorzystywać do tego opakowania AndroidFragment w Compose.

  • Czego można się spodziewać? Ponownie: zacinanie się i opóźnienia są ważne dla naszej działalności, więc cały czas przesuwamy granice i będziecie widzieć poprawę, ponieważ teraz mamy buforowanie na różnych ekranach i znacznie mniej problemów z przeładowaniem pamięci.

  • Zyskujesz też nowe możliwości.

  • Przykładem jest ten GIF po prawej stronie, na którym widać przejścia między ekranami z udostępnionymi elementami.

  • Mamy więc obraz, który powiększa się, gdy przechodzisz z jednego ekranu na drugi, co zapewnia ciągłość.

  • Podczas całego przejścia możesz też wykorzystać wszystkie możliwości animacji w Compose.

  • Teraz przekażę głos Kirillowi, który opowie o kolejnych funkcjach.

Motywy i wydajność

  • Dziękuję, Jon.

  • Chcę porozmawiać o temacie, który jest mi bardzo bliski, czyli o motywach i stylach aplikacji na Androida. Zajmuję się tym już od dłuższego czasu.

  • W świecie widoków był kod Java, a nieco później kod Kotlin, a następnie zasoby XML, takie jak kolory, ciągi znaków, wymiary, układy oraz motywy i style.

  • Wszystkie te zasoby XML były kompilowane do tabeli zasobów, która była dołączana do pliku APK i była w zasadzie statyczna.

  • Istnieje interfejs API Resources.Theme.applyStyle, którego można używać dynamicznie w czasie działania, aby stosować niestandardowe style na poziomie hierarchii interfejsu.

  • Głównym ograniczeniem było to, że trzeba było to zrobić przed wypełnieniem treści. Oznaczało to, że jeśli chcieliśmy dynamicznie zastosować ten styl do istniejącego elementu interfejsu, musieliśmy usunąć i ponownie utworzyć całą aktywność, co nie było zbyt wygodne dla użytkownika.

  • Ponieważ stosowane były te wstępnie skompilowane bloki XML, trudno było łączyć wiele warunkowych nakładek dynamicznych na podstawie flag eksperymentu lub innych potrzeb biznesowych.

  • Trudno było zbudować właściwy model mentalny hierarchii stylów w świecie XML.

  • I wreszcie nie było jednego ujednoliconego widoku w Android Studio ani w żadnym innym narzędziu dla programistów, który pozwalałby na wypełnienie luki między światem Javy, światem kodu i światem XML.

  • Trudno było to wszystko ogarnąć, zbudować odpowiedni model mentalny i znaleźć przyczynę, dla której mój styl nie jest stosowany, dlaczego mam niewłaściwy kolor itd.

  • W nowym świecie, czyli w świecie Compose, a konkretnie w systemie Material Design i bibliotece Compose Material, ale też w innych systemach projektowania, mamy funkcję kompozycyjną MaterialTheme, którą stosuje się na samej górze hierarchii interfejsu na ekranie. Można ją też zastosować jako nakładkę na dowolny mniejszy element interfejsu.

  • Jeśli spojrzysz na ekran po prawej stronie, u góry zobaczysz poziom złoty w programie Play Points. Jest to mała karta ze wskaźnikiem postępu i kilkoma tekstami.

  • Nakładamy tę nakładkę Material Theme z niestandardowym schematem kolorów wygenerowanym przez bibliotekę Material Color Utilities, która jest dostępna na GitHubie.

  • Przekazujemy ten brązowo-żółto-złoty kolor jako punkt wyjścia, a system generuje pełne spektrum tokenów kolorów Material, podstawowy na podstawowym, dodatkowy na dodatkowym, które następnie wykorzystujemy w implementacji tej karty.

  • Dzięki temu deweloperzy aplikacji na Androida mogą w pełni korzystać z funkcji dynamicznych motywów.

  • Wszystko odbywa się w kodzie, w języku Kotlin, co oznacza, że znacznie łatwiej jest zbudować właściwy model mentalny działania całości i znacznie łatwiej jest debugować.

  • Wewnętrznie te nakładki są dołączane jako elementy lokalne kompozycji do konkretnych węzłów interfejsu w hierarchii, w których chcesz je zastosować.

  • Uwagi dotyczące wydajności: wygenerowanie pełnego schematu kolorów za pomocą biblioteki Material Color Utilities nie jest bezpłatne.

  • Wiąże się to z pewnymi kosztami.

  • Jeśli więc masz coś na tyle skomplikowanego, że wymaga wielu takich elementów, na przykład bento box lub coś podobnego, w zależności od potrzeb produktu, i masz wiele schematów kolorów generowanych w czasie działania, zaczyna się to sumować i zwiększać opóźnienia oraz powodować zacinanie się.

  • Po pierwsze, chcesz zacząć mierzyć, jak wpływa to na wydajność, a po drugie, możesz przenieść część tego obciążenia z czasu działania na czas kompilacji.

  • Możesz użyć tej samej biblioteki Material Color Utilities podczas kompilacji, aby wstępnie wygenerować te schematy kolorów na podstawie potrzeb związanych z marką lub produktem i odciążyć proces kompilacji.

  • Wspomniane przeze mnie zmienne lokalne kompozycji, które śledzą, gdzie dokładnie znajdują się nakładki w drzewie hierarchii interfejsu, są znacznie tańsze, ale nadal nie są bezpłatne.

  • W zależności od tego, ile ich używasz, może to być kilkadziesiąt lub kilkaset.

  • W pewnym momencie warto zacząć przyglądać się kosztom wszystkich tych połączonych zmiennych lokalnych kompozycji.

  • To jest przykład tego, o czym wspominałem, czyli prawdziwie dynamicznych możliwości motywów w Compose w czasie działania.

  • Mamy tu 4 ćwiartki, te same elementy wizualne, tę samą, nazwijmy to, kartę wydarzenia.

  • Mamy baner powitalny, który zajmuje całą kartę, etykietę w lewym górnym rogu, przycisk w prawym dolnym rogu i kilka tekstów.

  • Po prawej stronie każdej ćwiartki widać objaśnienie tokenów kolorów, które są używane jako specyfikacja projektu dla każdego elementu.

  • Implementacja karty jest dokładnie taka sama we wszystkich 4 przypadkach.

  • Jedyną różnicą jest nakładka Material Theme, która otacza kartę i jest generowana lub konfigurowana z dynamicznie tworzonym schematem kolorów na podstawie dominującego koloru obrazu: niebieskiego, fioletowego, żółtego i czerwonego.

  • Wszystko inne pozostaje bez zmian.

  • Nie musisz usuwać i ponownie tworzyć aktywności.

  • Możesz go stosować warunkowo na podstawie flag eksperymentu lub innych potrzeb biznesowych.

  • Jak już wspominałem, jest to znacznie bardziej dynamiczny, prawdziwie dynamiczny świat stosowania dostosowań kolorów w aplikacji.

  • Teraz Jon przedstawi kolejną sekcję.

Skalowanie niezawodności i szybkości

  • Tak.

  • To kolejny przykład elastyczności, o której mówił Kirill.

  • Porozmawiajmy o niezawodności i szybkości.

  • Dlatego wszyscy deweloperzy i firmy chcą szybko tworzyć kod wysokiej jakości.

  • Zobaczmy, jak Compose pomógł Google Play to osiągnąć.

  • Przede wszystkim, wiem, że to duży diagram, ale prostota architektury ma ogromne zalety dla wszystkich autorów i osób utrzymujących kod, zarówno ludzi, jak i agentów.

  • Nie będę się w to zagłębiać, ale jednym z modeli mentalnych, które Compose próbuje wprowadzić, jest jednokierunkowy przepływ danych. To naprawdę miało duży wpływ na nasz zespół.

  • Jeśli nie wiesz, jak to działa, podstawą jest źródło danych.

  • Źródło danych dostarcza dane.

  • Te dane mogą zostać przekształcone w określony interfejs, który jest generowany jako model interfejsu.

  • Compose może łatwo to zaobserwować, wywołując właściwość wartości w tym stanie.

  • To są strzałki w górnej części tego diagramu.

  • Zdarzenia przepływają w odwrotnym kierunku.

  • Jeśli użytkownik kliknie przycisk, nastąpi powrót do transformatora interfejsu, który zaktualizuje źródło danych, wygeneruje nową wartość i uruchomi transformacje. W ten sposób powstaje pętla.

  • Wszystko działa w tej stosunkowo prostej pętli.

  • Zauważyliśmy, że dzięki temu skraca się czas na optymalizację.

  • Nie ma już takich pytań jak: „Gdzie są te wszystkie wywołania wątku głównego lub innych wątków?”.

  • Jest to jedna ogólna pętla.

  • Compose sprawia, że obserwowanie danych jest bardzo proste, a dane mają gwarancję silnej spójności w warstwach architektury.

  • Model mentalny ograniczył wiele rozmów o źródłach prawdy w naszym zespole i całkowicie wyeliminował kilka rodzajów sytuacji wyścigu.

  • Kolejną ogromną zaletą w porównaniu z naszą poprzednią architekturą model-widok-kontroler jest to, że równoległe wykonywanie źródeł danych i przekształceń interfejsu stało się bardzo proste.

  • Dzięki temu udało nam się skrócić czas oczekiwania na wczytanie w Sklepie o kilkadziesiąt milisekund.

  • To było dla nas imponujące.

  • Oprócz jednokierunkowego przepływu danych kolejną ogromną zaletą Compose jest deklaratywny interfejs użytkownika.

  • Kirill już trochę o tym wspomniał.

  • Deweloperzy w Google Play również są bardzo zadowoleni z tej funkcji.

  • Przepływ sterowania interfejsem jest teraz w jednym pliku.

  • Po prawej stronie mamy przykład, który jest dość prosty.

    @Composable
    fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
      Row(modifier) {
        Text("20% off sale")
        if (LocalExpts.current.useButtonV2) {
          ButtonV2("Buy", onClick = onClick)
        } else {
          ButtonV1("Buy", onClick = onClick)
        }
      }
    }
  • Przełączamy się między 2 implementacjami przycisku na podstawie flagi eksperymentu.

  • Zamiast czytać wiele plików widoku, fragmentów i plików XML, wystarczy przeczytać go od góry do dołu, co znacznie ułatwia pracę.

  • Koszt zagnieżdżania funkcji kompozycyjnych jest też znacznie niższy niż w przypadku zagnieżdżonych hierarchii widoków. Pozwoliło nam to na naturalne uporządkowanie kodu, dzięki czemu jest on bardziej czytelny, i nie musimy już walczyć o każdy ułamek wydajności.

  • Inne korzyści, które zauważyliśmy, to znacznie prostsze wywołania zwrotne cyklu życia i mniejsza liczba wywołań, o które trzeba się martwić.

  • Zamiast cyklu życia widoku, cyklu życia fragmentu i cyklu życia aktywności masz efekt jednorazowy i efekt uboczny, które działają w bardzo spójny sposób, zależnie od tego, gdzie je umieścisz.

  • To dla nas ogromna korzyść.

Przygotowanie do korzystania z dużych modeli językowych

  • Moim zdaniem te 2 zmiany architektoniczne naprawdę przygotowały grunt pod LLM i umożliwiły generowanie kodu o bardzo wysokiej jakości.

  • Pewnie wielu z Was próbowało już tego ze swoim ulubionym LLM.

  • Możesz zrobić zrzut ekranu z adnotacjami dotyczącymi kolorów i typografii, a następnie go przesłać. Model może wygenerować wiersze, kolumny, tekst i przyciski, i robi to całkiem dobrze.

  • Ma jednak pewne ograniczenia.

  • A Play nie rozumie Twojej bazy kodu, prawda?

  • Nie wie, jakie komponenty zostały już utworzone i powinny zostać ponownie użyte, ani nie zna nazw tokenów projektowych.

  • Zapewnia tylko zakodowane na stałe kolory i ciągi znaków.

  • Jakie treści powinny pochodzić z urządzenia, a jakie z serwera? Jak zapewnić wydajność dzięki LazyList, a nie tylko tworzeniu ogromnej kolumny?

  • Aby rozwiązać niektóre z tych problemów, dodaliśmy do zrzutów ekranu trochę więcej metadanych.

  • Są to nazwy interfejsu, ramki ograniczające, dzięki którym wiemy, gdzie zaczynają się i kończą komponenty, tokeny projektowe dla semantycznych nazw kolorów i typografii, umiejętności, a także pewne prompty, które wskazują, gdzie dany element zostanie umieszczony, aby można było uwzględnić te kwestie związane z wydajnością.

  • oraz bardzo ogólną sygnaturę funkcji, dzięki której można określić, które treści są dynamiczne, a które statyczne.

  • W ten sposób otrzymasz coś podobnego do tego, co było wcześniej, ale z przeniesieniem do stanu „po”.

  • Nie mam tu ramek ograniczających, ponieważ dodałyby one do diagramu dużo szumu.

  • Możesz jednak zobaczyć, że te zakodowane na stałe kolory i nazwy typografii zostały zastąpione przez „title large” i „on surface”.

  • Nazwy komponentów, takie jak nagłówek karty i plakietka ikony, są wyraźnie oznaczone.

  • Dzięki temu można je znaleźć w bazie kodu.

  • Wiele z nich pochodzi z powszechnie używanych bibliotek projektowych, o których Kirill opowie za chwilę.

  • Nie musisz więc cały czas oznaczać wszystkich tych produktów etykietami własnymi.

  • Łączysz to z sygnaturą metody, taką jak ta na dole, OfferCard, i wtedy wiadomo, że tytuł, endDate i obraz są dynamiczne.

  • Nie powinniśmy ich kodować na stałe.

  • Oprócz tych nazw semantycznych możemy teraz przełączać się między wszystkimi różnymi aplikacjami kolorów, o których mówił Kirill.

  • Dzięki temu generujemy znacznie więcej kodu.

  • Teraz Kirill opowie o tym, jak dbamy o jakość.

Automatyzacja jakości

  • Po prawej.

  • Dziękuję, Jon.

  • Kontynuując temat LLM i programowania wspomaganego przez Agent Assist, zaczynamy od projektowania UX.

  • Niezależnie od tego, jakiego narzędzia do projektowania używasz – czy jest to Figma, czy coś innego – warto mieć udostępniony szablon, z którego korzystają wszyscy projektanci. Powinien on zawierać tokeny kolorów, typografii i kształtów z wybranego systemu projektowania.

  • Może to Material.

  • Może to być Twój niestandardowy system projektowania.

  • Jeśli chodzi o tokeny kolorów, chcesz, aby te szablony miały wbudowaną obsługę przełączania się między trybem jasnym i trybem ciemnym oraz między trybami normalnego, średniego i wysokiego kontrastu, które zostały wprowadzone na poziomie Androida kilka lat temu.

  • Dzięki temu projektanci mogą szybko przełączać się między różnymi kombinacjami, aby zobaczyć, jak reagują na nie specyfikacje projektowe.

  • Następnie, gdy projekt jest finalizowany i przekazywany do wdrożenia, w tym procesie eksportu chcesz mieć możliwość śledzenia, czy każdy kolor, każdy element typograficzny i każdy kształt używa pasującego tokena, a nie zakodowanej na stałe wartości RGB, rodziny czcionek czy rozmiaru czcionki.

  • I wreszcie, co okazało się bardzo przydatne w skali Google Play, mamy nie tylko dziesiątki, ale nawet kilkaset komponentów, klastrów, kart i kontenerów, które są używane na różnych ekranach.

  • Przydatne jest śledzenie wszystkich tych informacji w jednym miejscu, które nazywamy katalogiem komponentów, a następnie wytrenowanie niestandardowego agenta na podstawie tego katalogu.

  • Przydaje się to, gdy zaczynasz nowy ekran, może nową ścieżkę użytkownika, może nowy obszar produktu, i z tych wstępnych eksploracji projektowych, może slajdów, może specyfikacji Figma, możesz przekazać to agentowi, a agent pomaga szybko zidentyfikować, które komponenty już istnieją, dzięki czemu nie trzeba ich przeprojektowywać i ponownie specyfikować, więc nie trzeba ich ponownie wdrażać od zera.

  • To znacznie obniża koszty projektowania i wdrażania.

  • Jeśli chodzi o wdrożenie, w dużym stopniu polegamy na podstawowych i niestandardowych regułach Lint.

  • Chcę zwrócić uwagę na kilka podstawowych reguł Lint. FrequentlyChangingValueDetector pomaga identyfikować źródła niepotrzebnych rekompozycji, które mogą powodować opóźnienia i zacinanie się. Druga reguła to ScaffoldPaddingDetector, która służy do oznaczania przypadków, w których używamy funkcji Scaffold w Compose Material, ale ignorujemy przychodzące dopełnienia.

  • Nie jest to źródło opóźnień ani zacinania się, ale w niektórych przypadkach może prowadzić do bardzo trudnych do debugowania problemów, takich jak nieprawidłowe wyrównanie układu w niektórych przypadkach, gdy jest on wyświetlany od krawędzi do krawędzi lub gdy jest składany i rozkładany.

  • I na koniec BoxWithConstraints, który wiąże się z pewnymi kwestiami dotyczącymi wydajności.

  • Prawidłowe rozmieszczenie wszystkich elementów może zająć 2 klatki.

  • Nie blokujemy go całkowicie, ale oznaczamy jako ostrzeżenie Lint, aby deweloper pracujący nad danym ekranem wiedział, że dokonuje konkretnego wyboru, używając BoxWithConstraints, lub mógł wybrać coś innego dla tego konkretnego układu.

  • W przypadku automatyzacji motywów również używamy tokenów kolorów, typografii i kształtów.

  • Mamy regułę Lint, która blokuje używanie zakodowanych na stałe kolorów i typografii.

  • Mamy regułę Lint, która oznacza użycie komponentów Material 2.

  • Chcemy używać tylko Material 3, najnowszej i najlepszej wersji, w tym nowych komponentów ekspresyjnych, które zostały wprowadzone w zeszłym i w tym roku.

  • Mamy niestandardową regułę Lint, która uniemożliwia odczytywanie kolorów np. ze starszych plików XML.

  • Chcemy, aby nowe ekrany były tworzone przede wszystkim lub wyłącznie za pomocą Compose.

  • A komponenty Text, zwłaszcza w systemie projektowania Material Design, mają zastępcze style i kolory.

  • Odczytują je z koloru i typografii treści lokalnych, ale nie chcemy na tym polegać.

  • Chcemy, aby każdy tekst celowo używał określonego stylu, stylu typografii i określonego koloru ze specyfikacji projektu.

  • To jest reguła Lint, którą mamy.

  • Ostatnia reguła, podobna do ScaffoldPaddingDetector, to niestandardowa reguła Lint, która wymusza, aby każda funkcja typu „composable” używała swojego modyfikatora wejściowego.

  • Again, to prevent like, you know, new usages from being like incorrectly placed, or not respecting the incoming background, or whatever it might be.

Podsumowanie

  • Oto 3 główne punkty, które chcielibyśmy, abyście zapamiętali z tej prezentacji.

  • Po pierwsze, dziś, pod koniec 2026 roku, Compose jest naszym zdaniem dojrzałym zestawem narzędzi UI, który sprawdził się na dużą skalę.

  • Android sam w sobie jest oparty na Compose.

  • Na początku tego roku podczas Google I/O ogłosiliśmy, że wszystkie biblioteki UI i wszystkie przepływy agentów są oparte na Compose.

  • Jak Jon wspomniał wcześniej w prezentacji, zalecamy stopniową migrację, zwłaszcza w przypadku dużych baz kodu, aby przyspieszyć procesy programistyczne i procesy agentów.

  • Dziękujemy za uwagę. Za kilka minut razem z Jonem będziemy na zewnątrz, aby odpowiedzieć na Wasze pytania.

  • Jeszcze raz dziękuję za poświęcony czas.

Kod

Fragmenty kodu

Fragment kodu w języku Kotlin w filmie „Scaling reliability and velocity”
@Composable
fun PurchaseRow(onClick: () -> Unit, modifier: Modifier) {
  Row(modifier) {
    Text("20% off sale")
    if (LocalExpts.current.useButtonV2) {
      ButtonV2("Buy", onClick = onClick)
    } else {
      ButtonV1("Buy", onClick = onClick)
    }
  }
}