Jak złożyć aplikację mobilną 1C. Przykład opracowania aplikacji mobilnej z wykorzystaniem „Mobile Application Builder”

Ten artykuł jest przeznaczony dla osób zainteresowanych klientem mobilnym. Przyjrzymy się instalacji klienta mobilnego na Androidzie, połączeniu debugowania i złożenia aplikacji apk w konfiguracji „Mobile Application Builder”.

Wreszcie pojawiła się testowa platforma mobilna 8.3.12 i teraz możemy przetestować działanie klienta mobilnego. Nie wiem jak Wy, ale wielu znanych mi programistów czekało na to od czasu publikacji artykułu na temat „1C: Through the Looking Glass” (klient mobilny).

Zakładam, że znasz instalację aplikacji mobilnej i narzędzie do tworzenia aplikacji mobilnych, a także masz już zainstalowany Android SDK, Apache Ant itp. Artykułów na ten temat jest już mnóstwo.

Do naszych eksperymentów weźmy konfigurację demonstracyjną „Aplikacji Zarządzanej” i spróbujmy najpierw połączyć ją z gotowym klientem mobilnym. W moim przypadku dystrybucją klienta jest plik „1cem-client-arm.apk”. W smartfonie należy najpierw włączyć możliwość instalowania aplikacji z nieznanych źródeł. Dla mnie wygląda to tak:

Klient mobilny jest odpowiednikiem klienta sieciowego, dlatego aby uzyskać dostęp do bazy danych, należy ją opublikować na serwerze sieciowym. Tutaj wszystko jest standardowe, publikuję na serwerze internetowym IIS o nazwie „demo”. Moja baza danych jest oparta na plikach, więc muszę nadać uprawnienia do katalogu użytkownikowi IUSR. Cieszę się, że sam system mi o tym przypomniał.

Połącz bazę danych w kliencie mobilnym:

Oczywiście nie dało się od razu wejść do bazy.Chodzi o to, że Administrator otwiera przetwarzanie do pracy z pocztą i próbuje ustawić ikonkę na pasku zadań, czego w kliencie mobilnym nie ma. Ponieważ ta funkcja nie jest również dostępna w kliencie WWW, kod jest otoczony dyrektywami kompilacji „#If Not WebClient then”. Musimy tylko znaleźć wszystkie miejsca, w których używana jest ta dyrektywa i zmienić ją na „#If Not WebClient AND Not MobileClient then”. Na początek to wystarczy i wreszcie możemy zobaczyć działającego klienta mobilnego. Interfejs poleceń wygląda następująco:

Oto lista kontrahentów:

To oczywiście nie wszystkie miejsca, które trzeba dostosować pod klienta mobilnego. Konfigurację możesz sprawdzić za pomocą „Menu główne - Konfiguracja - ---Sprawdź konfigurację”:

Znalazłem 84 błędy, w tym nieobsługiwane obiekty metadanych. Plus te trzy miejsca w kodzie, które już ograniczyłem dyrektywami. Trzeba więc jeszcze popracować nad adaptacją, ale na pewno nie jest to to samo, co napisanie od podstaw aplikacji mobilnej.

Uruchamianie w ramach innych ról odbywa się w ten sam sposób, wystarczy ustawić prawo do uruchamiania klienta mobilnego.

Jeśli nie rozumiemy, na czym polega błąd, debugowanie nam pomoże. Jest dostępny w kliencie mobilnym, ale wykorzystywane jest tylko debugowanie HTTP. Mam bazę danych plików, więc skorzystam z lokalnego serwera debugowania („Narzędzia - Opcje - Debugowanie”) i skonfiguruję automatyczne połączenie dla klienta mobilnego („Debugowanie - Połączenie - Połączenie automatyczne”):

Określ parametry i gotowe:

Konfiguracja wstępnie przygotowanego klienta apk z 1C została zakończona.

Teraz zbudujmy naszą aplikację za pomocą narzędzia do tworzenia aplikacji mobilnych. Szczerze mówiąc, za pierwszym razem spędziłem kilka godzin próbując zbudować aplikację. Montaż był kontynuowany, ale otworzyła się pusta lista baz danych.

I tak mamy archiwum mobilnej wersji platformy. Wrzucamy go do katalogu „Wersje mobilne”:

W ustawieniach kolekcjonera pojawiła się osobna pozycja dla SDK 26 i wyższych (dla takich jak ja, którzy dawno nie aktualizowali, uruchom Menedżera SDK i pobierz nowe pakiety):

Następnie musisz przygotować plik konfiguracyjny. Właśnie z tym krokiem miałem problemy na samym początku. Potem otworzyłem dokumentację i wszystko stało się trochę jaśniejsze. Przewodnik programisty mówi na ten temat następująco: „Każda konfiguracja, która może działać w kliencie mobilnym, zawiera pewne informacje pomocnicze, które pozwalają śledzić podmianę konfiguracji”.
Plik konfiguracyjny musi być podpisany. W tym przypadku dla każdej konfiguracji generowany jest własny klucz prywatny, a klucz publiczny (pole DSAKey) wgrywany jest do pliku 1cemca.xml, z którym porównywany jest sygnatura konfiguracji.

Aby wygenerować klucz i podpis, przejdź do właściwości konfiguracji „Podpis klienta mobilnego” (od razu pod wymaganymi uprawnieniami, jeśli Twoje właściwości są podzielone według kategorii, a nie alfabetycznie) i zobacz ustawienia podpisu:

Najpierw tworzymy klucz prywatny i ukrywamy go przed szpiegami i wrogami. Następnie tworzymy sygnaturę konfiguracji. Na przyszłość instrukcja zaleca przejście do „Menu główne – Konfiguracja – Klient mobilny – Konfigurowanie korzystania z klienta mobilnego”. W oknie dialogowym zaznacz pole wyboru „Weryfikuj podpis klienta mobilnego podczas aktualizacji konfiguracji bazy danych” i kliknij przycisk „OK”. Sądząc po instrukcji, podpis ulegnie zmianie, jeśli zmienimy skład lub nazwy typów obiektów metadanych, a także nazwy i/lub skład kluczy wpisów do rejestru. Te. zmiana formularzy na pewno nie wpływa na podpis i, sądząc po opisie, na zmianę składu szczegółów istniejących spisów i dokumentów (ale nie jest to pewne).

Podpis jest gotowy, możemy kontynuować. Od razu powiem, że procesy w tle nie są dostępne w kliencie mobilnym, dlatego należy je wyłączyć w uprawnieniach klienta mobilnego. Udostępnianie plików z komputera PC również nie jest dostępne. Dodatkowo wyłączyłem geopozycjonowanie, aby podczas montażu nie wystąpił błąd wynikający z braku klawisza do pracy z mapami. Skończyło się na następującej liście uprawnień:

Przykład opracowania aplikacji mobilnej w 1C:Enterprise 8.3 do pracy kuriera sklepu internetowego przy dostawie towarów do klientów. Do programowania wykorzystano konfigurację „Mobile Application Builder”.

Przykład opracowania aplikacji mobilnej dla kuriera sklepu internetowego z wykorzystaniem „Kreatora Aplikacji Mobilnych”

Dlatego opracowaliśmy aplikację mobilną do pracy kuriera sklepu internetowego przy dostawie towarów do klientów. Oczywiście jest to dość schematyczne i nie jest w stanie objąć wszystkich zadań, które faktycznie powstają podczas pracy kuriera. Ale implementuje wszystkie funkcje, które chcieliśmy pokazać w tej książce.

Teraz, po zakończeniu prac programistycznych, pozostaje nam tylko złożyć naszą aplikację mobilną w jeden plik i pobrać ją na tablet.

Chociaż do montażu użyjemy specjalnej konfiguracji Kreator aplikacji mobilnych, który ułatwia proces montażu, nadal nie jest łatwy i szybki do wykonania po raz pierwszy. Dlatego należy uzbroić się w cierpliwość i uważnie i uważnie przestrzegać sekwencji działań opisanych poniżej.


Skąd pobrać i jak zainstalować Kreatora aplikacji mobilnych

Konfiguracja Kreator aplikacji mobilnych dostarczane jako część platformy mobilnej. W pierwszym rozdziale książki, w sekcji „Platforma mobilna 1C: Enterprise”, rozpakowaliśmy archiwum z platformą mobilną na komputer. W tym katalogu znajduje się folder MobileAppMaker z plikiem Setup.exe służącym do instalacji szablonu konfiguracji. Uruchommy ten plik i zainstalujmy szablon konfiguracyjny w katalogu szablonów „1C:Enterprise” (ryc. 5.1).

Ryż. 5.1. Instalowanie szablonu konfiguracji Mobile Application Builder

Następnie dodamy nową bazę informacyjną do listy baz informacyjnych „1C:Enterprise” i utworzymy bazę informacyjną z wcześniej utworzonego szablonu (ryc. 5.2).

Ryż. 5.2. Utworzenie bazy informacyjnej „Mobile Application Builder” z szablonu

Następnie otworzymy tę bazę danych w konfiguratorze i dodamy użytkownika Administrator z właściwościami 1C:Enterprise Authentication, rolami Administratora i Użytkownika oraz językiem rosyjskim (ryc. 5.3).

Ryż. 5.3. Tworzenie użytkownika „Administrator”.

Zapiszmy konfigurację, zamknij ją i otwórz w trybie 1C:Enterprise jako użytkownik Administrator. Teraz ta baza danych jest pusta. Musimy wypełnić go wszystkimi niezbędnymi do montażu parametrami, które zostaną zapisane i wykorzystane przy dalszych montażach.

Najpierw (jeśli baza danych jest pusta) na stronie początkowej aplikacji otwierają się ogólne informacje pomocy dotyczące kreatora aplikacji mobilnych. Dostęp do niego można uzyskać także z menu głównego – Menu główne > Pomoc > Treść pomocy > Kreator aplikacji mobilnych. Dodatkowo z poziomu poszczególnych formularzy konfiguracyjnych otwierane są dodatkowe strony pomocy dotyczące składania aplikacji mobilnych (rys. 5.4).

Ryż. 5.4. Pomoc w konfiguracji narzędzia Mobile Application Builder


Konfigurowanie parametrów rozwiązania aplikacyjnego

Najpierw musimy skonfigurować ustawienia kolektora. W tym celu z menu Narzędzia wywołaj element Ustawienia aplikacji. Nie będziemy teraz budować aplikacji mobilnej dla Apple, dlatego pozostawimy odpowiednie pole wyboru puste.

W formularzu ustawień należy wypełnić tabelę Katalogi komponentów na komputerach biorących udział w procesie kompilacji, która będzie zawierać ścieżki do komponentów oprogramowania niezbędnych do zbudowania aplikacji mobilnej. Aby to zrobić, kliknij przycisk Utwórz znajdujący się nad tą tabelą (ryc. 5.5).

Ryż. 5.5. Tworzenie wpisu w tabeli „Katalogi komponentów...”

Otworzy się formularz Ścieżki komponentów. Dzwoniąc do pomocy z tego formularza, można zobaczyć linki do uzyskania komponentów oprogramowania i ich opisów (rys. 5.6).

Ryż. 5.6. Pomoc w opisywaniu ścieżek do komponentów

Najpierw musisz zainstalować Java SDK i w polu JDK wskazać katalog, w którym ten komponent jest zainstalowany. Pakiet Java SDK można uzyskać pod adresem: http://www.oracle.com/technetwork/java/javase/downloads/index.html. Zalecane jest pobranie pakietu Java Platform Package (JDK).

Na stronie, która zostanie otwarta, u góry kliknij przycisk Pobierz (ryc. 5.7).

Ryż. 5.7. Pobieranie zestawu SDK Java

Na następnej stronie musisz zaakceptować umowę licencyjną (zaznaczyć pole wyboru Akceptuj umowę licencyjną) i kliknąć link z żądaną dystrybucją w kolumnie Pobierz (dla 64-bitowego systemu Windows - jest to plik jdk-8u60-windows-x64. exe), rys. 5.8.

Ryż. 5.8. Pobieranie zestawu SDK Java

Powstały instalator należy uruchomić i zainstalować pakiet Java SDK np. w katalogu: C:\Program Files\Java\jdk1.8.0_60 (rys. 5.9).

Ryż. 5.9. Instalowanie pakietu SDK Java

Następnie ścieżkę tę należy podać w polu JDK formularza ustawiania ścieżek do komponentów aplikacji Mobile Application Builder (rys. 5.10).

Ryż. 5.10. Konfigurowanie ścieżek do komponentów aplikacji Mobile Application Builder

W kolejnych polach formularza konfiguracyjnego, Katalog roboczy i pamięć podręczna konstruktora, należy określić dowolny katalog w języku łacińskim, w którym program budujący będzie umieszczał pliki usług. Użytkownik, w imieniu którego będą budowane aplikacje mobilne, musi posiadać pełne uprawnienia do tego katalogu (rys. 5.11).

Ryż. 5.11. Konfigurowanie ścieżek do komponentów aplikacji Mobile Application Builder

W polu Android SDK podaj ścieżkę do katalogu, w którym znajduje się Menedżer SDK. Zainstalowaliśmy pakiet Android SDK w rozdziale 1, w sekcji „Android SDK” (ryc. 5.12).

Ryż. 5.12. Konfigurowanie ścieżek do komponentów aplikacji Mobile Application Builder

Następnie należy zainstalować Apache ANT i w polu Apache ANT określić katalog, w którym zainstalowany jest ten komponent. Do zbudowania aplikacji mobilnej dla systemu operacyjnego Android wymagany jest Apache ANT. Apache Ant można zdobyć.

Z tej strony musimy pobrać archiwum Apache-ant-1.9.6-bin.zip (ryc. 5.13).

Ryż. 5.13. Pobieranie Apache ANT

Rozpakuj ten plik na swój komputer i określ ścieżkę do niego w postaci ustawienia ścieżek do komponentów (ryc. 5.14).

Ryż. 5.14. Konfigurowanie ścieżek do komponentów aplikacji Mobile Application Builder

Następnie należy zainstalować system PuTTY i w polu PuTTY podać katalog, w którym zainstalowany jest ten komponent. Można uzyskać PuTTY.

PuTTY jest używany, jeśli tworzysz aplikację mobilną dla Apple. Do tworzenia aplikacji mobilnych wymagane są narzędzia pscp.exe i plink.exe. Na wszelki wypadek pobierzmy cały pakiet instalacyjny putty-0.65-installer.exe (ryc. 5.15).

Ryż. 5.15. Pobieranie PuTTY

Powstały instalator należy uruchomić i zainstalować PuTTY, na przykład w katalogu: C:\Program Files (x86)\PuTTY (ryc. 5.16).

Ryż. 5.16. Instalowanie PuTTY

Następnie wskazujemy ścieżkę uzyskaną podczas instalacji PuTTY w formularzu ustawiania ścieżek do komponentów (ryc. 5.17).

Ryż. 5.17. Konfigurowanie ścieżek do komponentów aplikacji Mobile Application Builder

To kończy konfigurację ścieżek komponentów. Kliknij opcję Nagraj i zamknij.


Konfigurowanie opcji dostawcy

Teraz musimy skonfigurować ustawienia dostawcy. W tym celu należy wywołać pozycję Edytuj parametry dostawcy z menu Narzędzia.

Otworzy się formularz Dostawcy, w którym w zakładce Parametry ogólne należy podać dowolną nazwę dostawcy, a także ustawić Prefiks ID aplikacji. Pole to należy wypełnić w języku łacińskim i zaczynać się od wiersza „com”. Zasady wypełniania tego pola znajdziesz w pomocy kontekstowej, którą otwierasz klikając przycisk ze znakiem „?”.

Następnie należy zwrócić uwagę na to, dla jakich systemów operacyjnych budowana jest aplikacja mobilna. W naszym przypadku zaznacz pole wyboru Dla systemu operacyjnego Android.

Aby pracować z powiadomieniami push za pośrednictwem usługi pomocniczej „1C:Enterprise”, określimy parametry dostępu do usługi. W tym celu należy kliknąć przycisk Dodaj nad tabelą na dole formularza dostawcy. W oknie, które zostanie otwarte, Ustawienia dostępu do usługi pomocniczej „1C:Enterprise”, zaznacz opcję Zarejestruj się dla – wybranego użytkownika, wybierz użytkownika-kolekcjonera – Administratora i podaj adres e-mail oraz hasło, pod którymi wcześniej rejestrowaliśmy się w serwisie podczas testowanie pracy z powiadomieniami push. Kliknij przycisk Zapisz i zamknij. Ponadto możesz zarejestrować się w usłudze 1C:Enterprise bezpośrednio z tego formularza za pomocą przycisku Zarejestruj się w usłudze 1C:Enterprise, jeśli nie zostało to jeszcze zrobione (ryc. 5.18).

Ryż. 5.18. Skonfiguruj ustawienia dostawcy aplikacji Mobile App Builder

Ponadto możesz wywołać okno ustawiania parametrów dostępu do usługi 1C:Enterprise z menu Narzędzia, pozycja Parametry dostępu dla usługi 1C:Enterprise.

Następnie należy wypełnić grupę pól Klucz programisty na karcie Ustawienia systemu operacyjnego Android. Aby to zrobić, najpierw utwórz klucz programisty, klikając link Utwórz klucz programisty. W otwartym formularzu Utwórz klucz programisty wypełnij losowo pola (w polu Kraj musisz podać kod Rosji w standardzie ISO - ru) i kliknij przycisk Wygeneruj klucz (ryc. 5.19).

Ryż. 5.19. Skonfiguruj ustawienia dostawcy aplikacji Mobile App Builder

Następnie pola kluczowych parametrów programisty zostaną wypełnione automatycznie (ryc. 5.20).

Ryż. 5.20. Skonfiguruj ustawienia dostawcy aplikacji Mobile App Builder

Wartość w polu SHA1 Hash klucza programisty zostanie później wykorzystana do uzyskania klucza do pracy z mapami Google. Wartość ta jest wymagana jeśli aplikacja mobilna będzie korzystała z narzędzi geolokalizacji na platformie Android.

To kończy konfigurację parametrów dostawcy. Kliknij opcję Nagraj i zamknij.


Ładowanie platformy mobilnej

Teraz musimy pobrać platformę mobilną 1C:Enterprise, pod którą będzie działać zmontowana aplikacja mobilna. Wersje platformy mobilnej może być kilka, jednak nie mogą być one starsze niż wersja 8.3.4.

Katalog Platformy Mobilne przeznaczony jest do pobierania i przechowywania różnych wersji platformy mobilnej. Dla każdej wersji platformy w tym katalogu należy utworzyć oddzielny wpis.

Z panelu poleceń aplikacji otwórz katalog Platformy mobilne i kliknij przycisk Utwórz. Następnie pojawi się okno dialogowe wyboru pliku, w którym należy wybrać plik z archiwum platformy mobilnej mobile.zip, który zapisaliśmy na komputerze przy odbiorze platformy mobilnej w pierwszym rozdziale książki, w sekcji „Platforma mobilna 1C: Przedsiębiorstwo”. Wybierz go i kliknij przycisk Otwórz.

Jeżeli platforma mobilna zostanie pomyślnie załadowana, otworzy się formularz tworzenia pozycji katalogu Platformy mobilne, w którym automatycznie zostaną wypełnione pola Wersja platformy mobilnej i Nazwa oraz pojawi się checkbox Załadowane pliki platformy mobilnej (rys. 5.21).

Kliknij opcję Nagraj i zamknij.


Ładowanie konfiguracji mobilnej

Teraz pozostaje nam załadować opracowaną przez nas mobilną konfigurację Sklepu Internetowego Kurier. Otwórzmy tę konfigurację w konfiguratorze. W palecie właściwości konfiguracyjnych ustaw właściwości Vendor – myfirm i Version – 1.0.0 (rys. 5.22).

Ryż. 5.22. Właściwości konfiguracji mobilnej „Sklepu Internetowego Kurier”

Następnie wgramy tę konfigurację do pliku wykonując polecenie konfiguratora Konfiguracja > Aplikacja mobilna > Zapisz do pliku...

Książka referencyjna Konfiguracje mobilne służy do pobierania i przechowywania różnych wersji konfiguracji aplikacji mobilnych. Katalog ma dwupoziomową strukturę: grupy opisują rozwiązania aplikacyjne, a elementy w grupach reprezentują różne wersje konfiguracji tych rozwiązań aplikacyjnych. Aby pobrać nową wersję konfiguracji należy przejść do grupy odpowiadającej rozwiązaniu aplikacyjnemu i w tej grupie utworzyć nowy element.

Z panelu poleceń aplikacji otwórz katalog Konfiguracje mobilne i kliknij przycisk Utwórz grupę z nazwą naszej konfiguracji Online Store Courier (rys. 5.23).

Ryż. 5.23. Tworzenie grupy katalogów „Konfiguracje mobilne”

Następnie w tej grupie utworzymy nowy element katalogu.

Następnie pojawi się okno wyboru pliku, w którym należy wybrać plik 1cema.xml, w którym właśnie zapisaliśmy naszą konfigurację mobilną. Wybierz go i kliknij przycisk Otwórz.

Jeżeli konfiguracja przebiegła pomyślnie, wszystkie pola formularza zostaną wypełnione automatycznie i nie należy ich zmieniać ręcznie. Tabela uprawnień wskaże wszystkie uprawnienia aplikacji mobilnej do pracy z multimediami, geopozycjonowaniem, powiadomieniami itp., które ustawiliśmy podczas jej tworzenia. Ponadto zostaną wyświetlone komunikaty o niemożności pracy z kalendarzami i kontaktami, których uprawnień nie ustawiliśmy (ryc. 5.24).


Kliknij opcję Nagraj i zamknij.


Opis parametrów aplikacji mobilnej

Teraz pozostaje nam opisać parametry aplikacji mobilnej, które będziemy zbierać w podręczniku Aplikacje mobilne.

Podręcznik powinien mieć dwupoziomową strukturę, gdzie grupa opisuje główne parametry montażu, a element grupy określa parametry montażu dla konkretnej wersji aplikacji mobilnej. Dla każdej aplikacji mobilnej należy utworzyć osobną grupę i dla każdej wersji aplikacji mobilnej znajdującej się w tej grupie należy utworzyć własny element.

Z panelu poleceń aplikacji otwórz katalog Aplikacje mobilne i kliknij przycisk Utwórz grupę. W formularzu, który się otworzy, ustaw nazwę aplikacji mobilnej Sklep Internetowy Kurier.

Mamy jednego dostawcę – moją firmę. Wypełni się automatycznie. Pole wyboru Dla systemu operacyjnego Android również zostanie zaznaczone. Pole Platforma mobilna pozostaw puste – podczas montażu automatycznie zostanie użyta najnowsza wersja platformy.

W polu Identyfikator rozwiązania wprowadź dowolny ciąg znaków w języku łacińskim. Kolejne pole zostanie wypełnione automatycznie (rys. 5.25).

Ryż. 5.25. Tworzenie grupy katalogów „Aplikacje mobilne”

Następnie pole Parametr uzyskania klucza do pracy z mapami Google zostanie automatycznie wypełnione (w tym polu wstawiana jest wartość parametru Hash SHA1 klucza programisty dostawcy Moja Firma z formularza ustawień dostawcy, patrz rys. 5.20 + linia identyfikatora rozwiązania) - będzie nam to potrzebne do uzyskania klucza do pracy z mapami Google. W tym celu musimy skontaktować się z serwisem Google i po otrzymaniu klucza zapisać go w polu Klucz do pracy z mapami Google.

Pamiętam ten wspaniały czas, gdy składanie wersji aplikacji mobilnej sprowadzało się do tego, że trzeba było ustawić debug = false i rozpocząć eksport pliku apk. Mijają 2 minuty, podczas gdy IDE dławi się i wszystko jest gotowe. Wszystkie wysiłki skupiały się na konieczności określenia danych certyfikatu podpisującego. To było całkiem niedawno. Teraz proces budowania tej właśnie aplikacji rozrósł się tak bardzo, że jeśli nagle będę musiał sam wykonać wszystkie operacje, a nawet jeśli wszystko zapamiętam i zrobię to poprawnie (w co nie wierzę), nie zajmie to godziny , co dzisiaj wydaje się zaporowo długie i najprawdopodobniej dzień, po którym terapeuta będzie musiał przepisać mi zwolnienie lekarskie na zmęczenie na dwa tygodnie.

A więc proces budowy aplikacji mobilnej. Spróbuję powiedzieć, z czego się składa - nie dlatego, że ostatnio modne stało się pisanie o CI tego czy innego mobilnego zespołu (z pokerem, syrenami i innymi obowiązkowymi atrybutami), ale dlatego, że jest to doskonałe doświadczenie, które zdobyłem , pracując nad Mail.Ru Mail na Androida i ponieważ takiej możliwości najprawdopodobniej nie byłoby, gdybym pracował w innym zespole, nad innym projektem lub w innej firmie.

Dla każdego procesu ważną decyzją jest wybór systemu, na którym zostanie zbudowany cały montaż. Kompilacje powinny być obsługiwane przez serwer kompilacji. To logiczne. Ale który wybrać?

Pytanie jest niejednoznaczne, każdy wybiera takie czy inne rozwiązanie na podstawie swojego doświadczenia, zadań stojących przed systemem i posiadanych zasobów. Niektórzy lubią darmowe rozwiązania, bo nie muszą tłumaczyć szefowi, dlaczego potrzebujesz 000 dolarów rocznie i dlaczego nie możesz się bez nich obejść. Niektórzy motywują się obecnością społeczności lub doświadczeniem ogromnej liczby zespołów, które skorzystały już z tych rozwiązań i są zadowolone z efektu. Liczba punktów widzenia zwykle odpowiada liczbie osób, które zadały to pytanie. Nie mogę powiedzieć, że czyjś argument jest słuszny lub że czyjś sprzeciw jest nieistotny. Ale niezależnie od poglądów dewelopera, który staje przed takim problemem, większość zgodzi się, że w zasadzie wszystkie popularne rozwiązania na rynku różnią się jedynie łatwością konfiguracji, integracją z powiązanymi systemami, możliwościami rozbudowy i wsparcie ze strony społeczności lub twórców systemu.

Generalnie wybór serwera kompilacji to temat na osobną dyskusję. Powiem tylko, że wybraliśmy rozwiązanie Bamboo Build Server firmy Atlassian. Powodów jest kilka, jednym z nich jest łatwość integracji z narzędziem do śledzenia zgłoszeń, które wykorzystujemy w projekcie, a także z systemami przeglądu kodu i hostingu repozytoriów. Chłopaki są w tym świetni: wszystko jest wygodne, wszystko pod ręką i co najważniejsze, prawie wszystkie dostarczone rozwiązania i opcje idealnie wpisują się w proces rozwoju naszego zespołu

Bambus

Bambus jest rozwiązaniem bardzo powszechnym i stosowanym przez ogromną liczbę zespołów na całym świecie. Szczegółowy opis działania tego narzędzia CI/CD można znaleźć na oficjalnej stronie dokumentacji, ale pozwolę sobie na swobodne przetłumaczenie niewielkiej części tego dokumentu, aby uniknąć rozbieżności terminologicznych.

Zadaniem serwera Continuous Integration jest wykonanie wszystkich prac związanych z asemblacją, testowaniem i wdrażaniem w środowisku testowym projektu. Serwer CI kontaktuje się z repozytorium, otrzymuje konkretną wersję projektu, wykonuje wszystkie niezbędne działania i przekazuje zespołowi projektowemu gotowy wynik kompilacji.

Projekt
  • składa się z jednego lub większej liczby planów budowy
  • udostępnia raport na temat planów budowy wszystkich projektów
  • powiązane z innymi aplikacjami (Jira, Fisheye, Crucible, Stash)
Plan budowy
(Plan)
  • składa się z jednego lub więcej etapów (etap)
  • wszystkie etapy uruchamiane są sekwencyjnie, z wykorzystaniem tych samych repozytoriów
  • zawiera zasady uruchamiania kompilacji, w zależności od innych planów budowy projektu
Scena
(Scena)
  • składa się z jednego lub większej liczby utworów
  • wykonuje pracę równolegle, na bezpłatnych agentach kompilacji uważa się ją za zakończoną, gdy wszystkie prace zostaną zakończone pomyślnie
  • przenosi artefakty do kolejnych etapów budowy.
Stanowisko
(Stanowisko)
  • składa się z jednego lub większej liczby zadań
  • wszystkie zadania wewnątrz są wykonywane sekwencyjnie na tym samym agencie
Zadanie
(Zadanie)
  • dyskretną operację, taką jak sprawdzenie wersji projektu, uruchomienie skryptu itp.


Mniej więcej podobne podziały są dostępne w każdym systemie montażu i zapewniają niezbędną elastyczność w projektowaniu całego procesu. Na pierwszy rzut oka wydaje się to przesadą. Tak było w przypadku naszego projektu, kiedy dopiero zaczynaliśmy używać Bamboo, ale stopniowo wszystko się uspokoiło, pojawiło się jasne zrozumienie, która część całego procesu montażu powinna zostać przeskalowana, a która powinna pozostać wyizolowana i w ramach wykształciła się w miarę harmonijna struktura proponowanych koncepcji.

Ogólnie rzecz biorąc, musisz dobrze zrozumieć, że serwer kompilacji lub serwer CI jest ważną częścią automatyzacji procesu tworzenia oprogramowania. Przypisując do tego modułu wszystkie zadania i prace, które należy wykonać na różnych etapach i poziomach przygotowania aplikacji do wypuszczenia na rynek, otrzymujemy swego rodzaju Application Release Pipeline. To z kolei pozwala łatwo określić, jakie zadania znajdują się w danej kompilacji, na jakim etapie jest teraz wydanie, jakie problemy pojawiają się przy integrowaniu nowej funkcjonalności, na jakim etapie jesteśmy teraz w przygotowaniu poprawki i wiele więcej.

Stopniowo więc zbliżyliśmy się do opisu, jak to się robi w naszym zespole.

Zadania

Nasz projekt budowy podzielony jest na kilka etapów, odzwierciedlających główne zadania na chwilę obecną:
  • Montaż — obejmuje wszystkie opcje montażu, które mogą być potrzebne podczas potoku wydania: alfa, beta, wydanie. Tak, tak, różnią nas zgromadzenia projektowe, a nie tylko ich status. Różnice między produktami: różne zasoby, obecność lub brak ustawień itp.
  • Weryfikacja to najbardziej pojemna i skomplikowana technicznie część całego etapu montażu aplikacji: analiza kodu statycznego, testy jednostkowe, testy funkcjonalne UI, sprawdzenie lokalizacji.
  • Wdrożyć. Aktualnie wyjęty z całości zestawu, wydaje się być na boku. Tym samym w razie potrzeby możemy wdrożyć dowolną wersję/oddział/typ aplikacji w dowolnym środowisku (alfa, beta, wydanie).
W zasadzie na tym można by zakończyć tę historię, ale pewnie będę nachalny i podam szczegóły.

Montaż

Teraz opracowujemy trzy projekty jednocześnie z jedną bazą kodu, nazwijmy je Projekt 1, Projekt 2 i Projekt 3. Oczywiście różnice między nimi nie są tak radykalne jak między szachami a odtwarzaczem wideo, ponieważ wszystkie trzy produkty należą do do kategorii klientów poczty elektronicznej. Mają jednak inną konstrukcję, różnią się funkcjonalnością i inaczej współdziałają z serwerem. Wszystko to dyktuje wymagania dotyczące montażu, testowania i rozwoju produktu.

Przepływ pracy w gałęzi funkcji

Każda kompilacja rozpoczyna się od sprawdzenia wersji projektu w systemie kontroli wersji. Wydawałoby się, po co się na tym skupiać – w końcu każdy może zrobić kasę? Naprawdę. Ale z której gałęzi należy to zrobić?

Do pracy nad produktem używamy Feature Branch Workflow. O tym podejściu możesz przeczytać osobno. Jego główną zaletą jest dla mnie izolacja zmian. Dzięki takiemu podejściu każdy programista może w ramach zadania oddać przynajmniej cały projekt, zgłosić go do testów i jeśli QA wyrazi zgodę, to przetestowany i działający kod zostanie włączony do gałęzi ogólnej. Takie podejście minimalizuje ryzyko przedostania się defektu do wydania, ze względu na zdefiniowaną kolejność działań: najpierw sprawdzenie, potem połączenie w główną gałąź projektu.

Aby przetestować te izolowane zmiany, musimy mieć kompilację, na której możemy przeprowadzić autotesty i którą przekażemy do testów ręcznych do zatwierdzenia przez zespół ds. kontroli jakości. Bamboo zapewnia rozwiązanie, którego potrzebujesz od razu po wyjęciu z pudełka. Nazywa się to planem rozgałęzień i polega na zdefiniowaniu głównej gałęzi kompilacji (na przykład alfa), a wszystkie gałęzie pasujące zgodnie z określonym szablonem są uważane za gałąź funkcji. Tworzony jest dla nich klon planu budowy, z tą różnicą, że kasacja nastąpi z tej gałęzi, a nie z głównej gałęzi planu budowy. Wygląda mniej więcej tak.

W widoku planu budowy możemy przełączać się pomiędzy oddziałem głównym a oddziałami istniejącymi, przeglądając wyniki wszystkich statusów lokalnych.

Sam plan gałęzi wygląda tak samo, z tą różnicą, że zawiera link do zadania.

Przy takim przepływie wątek nieuchronnie zaczyna być przestarzały od momentu jego utworzenia. Aby wcześnie wykryć konflikty z główną gałęzią i przetestować najnowszy kod, musisz stale aktualizować swoją gałąź podczas programowania. Bamboo może to zrobić automatycznie przed rozpoczęciem tworzenia projektu. W przypadku konfliktu kompilacja nie zostanie utworzona, a programista będzie musiał najpierw zaktualizować swoją gałąź, a następnie wypchnąć te zmiany. Wtedy nie będzie konfliktu przed montażem i wszystko pójdzie jak zwykle.

Smaki produktów

Załóżmy, że mamy projekt, który należy złożyć w kilku odmianach, zmieniając zasoby, kod i konfiguracje. Istnieje kilka opcji wdrożenia tego. Kierowaliśmy się tym, że wszystkie warunki kompilacji, wszystkie konfiguracje i inne części opisowe powinny znaleźć się w skrypcie kompilacji. W naszym przypadku Gradle jest idealny do rozwiązania tego problemu. Jest do tego dobra wtyczka na Androida, która pozwala elastycznie konfigurować większość standardowych i niestandardowych parametrów do montażu złożonego projektu.

Zastanówmy się, z ilu opcji montażu aktywnie korzystamy i wspieramy.

Zacznijmy od tego, że mamy trzy główne Smaki Produktu: Projekt 1, Projekt 2 i Projekt 3.

Smak produktu jest reprezentacją gałęzi produktu. W większości przypadków są to różne aplikacje, które mają różne pakiety, różne certyfikaty podpisywania, różne źródła i zasoby. Dla każdej aplikacji mamy kilka opcji kompilacji, a mianowicie:

  • odpluskwić- podpisany kluczem debugowania, można debugować, a nie zaciemniać;
  • alfa/gałąź alfa- zaciemniony zestaw, różni się konfiguracją analityki, zestawami awaryjnymi, zasobami, ustawieniami debugowania dostępnymi w aplikacji;
  • firma beta- wersja beta, która ma włączone logi i dostępny tryb debugowania;
  • beta- kompilacja jak najbardziej zbliżona do wydania, która wyróżnia się analityką, zbieraniem awarii, ma wyłączone logi, tryb debugowania i nie ma ustawień debugowania;
  • uwolnienie- wersja produkcyjna aplikacji, prawie wszystkie dodatkowe opcje są wyłączone, analityka i zbieranie statystyk są skonfigurowane pod kątem projektów bojowych w tych systemach itp.;
  • testowanie jednostki/UI- zestawy posiadające nadpisane manifesty, co umożliwia np. włączenie uprawnień do odczytu SMS-ów wymaganych do automatycznego testowania logowania (autoryzacja, rejestracja, uwierzytelnianie dwuskładnikowe) przy użyciu kodu SMS.
Całkowity:

8 typów kompilacji * 3 smaki produktów = 24 warianty zastosowania

Dlaczego tak dużo? Spróbuję odpowiedzieć. Jednym z typowych wyzwań, jakie trzeba rozwiązać, gdy masz trzy różne produkty opublikowane w różnych środowiskach, jest oddzielenie analiz. I tak trzeba zrobić, w przeciwnym razie statystyki z wersji alfa aplikacji zniekształcą obraz istniejący w produkcji. Używamy HockeyApp do gromadzenia statystyk wypadków. Mamy w nim osobne projekty dla różnych opcji montażu. Ułatwia to oddzielenie, na przykład awarii Projektu 1 od awarii Projektu 2, wersji beta od wersji opublikowanej itp.

W pliku build.gradle naszego projektu ta konfiguracja wygląda następująco.

ProductFlavors (project1 ( ... android.buildTypes ( alfa ( hockeyApp ( ) ) beta ( hockeyApp ( ) ) publicBeta ( ... ) wydanie ( ... ) ) projekt2 ( ... android.buildTypes ( alfa ( hockeyApp ( )) ) ... ) ) projekt3 ( ... android.buildTypes ( alfa ( hockeyApp ( ) ) ... ))
W ten sposób możemy skonfigurować różne wartości dla dowolnych opcji kompilacji. Jeśli chodzi o zasoby i źródła, stosuje się tutaj w przybliżeniu tę samą zasadę, z wyjątkiem jednej funkcji: możliwe jest łączenie zasobów z różnych opcji. Nasz projekt posiada zasoby, które są takie same dla wszystkich aplikacji – na przykład układ ekranu do pisania. Gdyby takie pliki trzeba było kopiować do każdego pakietu zasobów i przechowywać osobno, to przy zmianie układu ekranu pisania listów trzeba byłoby zmienić aż trzy pliki. Na szczęście gradle + wtyczka na Androida może łączyć zasoby.

Opowiem Ci nieco bardziej szczegółowo, jak to się dzieje - być może ktoś będzie w stanie rozwiązać swoje codzienne problemy, stosując to samo podejście.

Zdefiniowaliśmy kilka folderów z zasobami (wszystkie znajdują się w katalogu głównym projektu).

  • rez- wspólne zasoby dla wszystkich wariantów aplikacji: tutaj znajdują się wspólne selektory, znaczniki, motywy, style itp.;
  • res_projekt1- zasoby specyficzne dla Projektu 1: znajdują się tu prawie wszystkie grafiki użyte w aplikacji, linie zawierające nazwę projektu, konkretne logo lub znaczniki - ogólnie wszystko, co dotyczy tylko Projektu 1;
  • res_project23- tutaj jest nieco inny obraz: w pakiecie res _ projekt23 obejmuje wszystkie zasoby, które nie przecinają się z Projektem, ale są takie same dla Projektu 2 i Projektu 3. Takie grupowanie zasobów pomaga rozwiązać problem, gdy produkty Projektów 2 i 3 są do siebie bardzo podobne, a jednocześnie są zupełnie różne z Projektu 1. W przeciwnym razie musiałbym skopiować te same zasoby do folderów res_project2 i res_project3;
  • res_projekt2- zasoby unikalne dla Projektu 2: w tej chwili są to kolory, grafika, teksty. Wszystko inne znajduje się w pakietach ogólnych;
  • res_projekt3- podobnie w przypadku Projektu 3, w tym pakiecie pozostaje tylko unikalny wybór zasobów dla tej aplikacji.

W rezultacie dla każdej opcji kompilacji łączymy kilka pakietów, aby uzyskać wspólny zestaw zasobów dla aplikacji:

  • Projekt 1 = res + res_project1;
  • Projekt 2 = res + res_project23 + res_project2;
  • Projekt 3 = res + res_project23 + res_project3.
To jest podstawa. Aby uzyskać głębszą personalizację, możesz na przykład dodać określone zasoby, kod do kompilacji testowej itp. Całe nasze zamknięcie ze źródłami wygląda mniej więcej tak:

SourceSets ( main ( manifest.srcFile "AndroidManifest.xml" java ( srcDir "src" wyklucza "**/instrumentTest/**" ) Resources.srcDirs = ["src"] AIDSl.srcDirs = ["src"] renderscript.srcDirs = ["src"] res.srcDirs = ["res"] aktywa.srcDirs = ["assets"] ) androidTest ( manifest.srcFile "src/instrumentTest/AndroidManifest.xml" java.srcDir "src/instrumentTest/Java") projekt2 ( res.srcDirs = ["res_project2", "res_project23"] java.srcDirs = ["src_common"] aktywa.srcDirs=["assets_ projekt2] manifest.srcFile "res_ projekt23/AndroidManifest.xml" ) projekt3 ( res.srcDirs = ["res_project3", "res_ projekt23] aktywa.srcDirs=["assets_project3"] java.srcDirs = ["src_project3"] manifest.srcFile "res_ projekt23/AndroidManifest.xml" ) projekt1 ( res.srcDirs = ["res_project1" ] java.srcDirs = ["src_common"] aktywa.srcDirs=["assets_project1"] manifest.srcFile "res_project1/AndroidManifest.xml" ) testowanieUi ( manifest.srcFile "ui_testing/AndroidManifest.xml" ) )
Jeszcze trochę zostało do zrobienia. W konfiguracji projektu kompilacji musisz uruchomić odpowiednie zadanie, aby uzyskać żądany plik .apk, na przykład gradle assembleProject1PublicBeta. Naturalnie przy tak dużej liczbie możliwości montażu postanowiliśmy nie montować ich wszystkich po kolei, lecz zrównoleglić ten proces. W sumie otrzymaliśmy 6 prac równoległych, które są realizowane w ramach etapu montażu. Każda praca publikuje 3 artefakty na produkt.

Zakładam, że ci, którzy przeczytali do tego momentu, mają pytanie: po co zbierać wersję beta i wypuszczać ją przy każdej kompilacji projektu? Pytanie jest rzeczywiście bardzo interesujące. Nie od razu podjęliśmy tę decyzję, ale po długim czasie. Historycznie rzecz biorąc, wersje beta i wydania były budowane oddzielnie, przy użyciu tej samej wersji lub umowy stwierdzającej, że kod jest taki sam. Potem zdaliśmy sobie sprawę, że to podejście jest obarczone wieloma problemami, a najbardziej nieprzyjemnym jest to, że dowiadujesz się o stanie kompilacji po podjęciu decyzji o opublikowaniu wersji beta. Zgodnie z prawem Murphy'ego konstrukcja okazuje się oczywiście czerwona. Z jakiegokolwiek powodu. Im więcej zmian, tym większe prawdopodobieństwo, że wpłyną one negatywnie na kompilację, a my nie będziemy mogli nic z tym zrobić. Można jedynie skrócić odstęp czasu pomiędzy momentem wprowadzenia błędu a momentem jego wykrycia. Najlepiej zrobić to w oderwaniu od gałęzi ogólnej. Jeśli abstrahujemy od projektu i kompilacji wersji beta lub wydania i przyjrzymy się procesowi automatyzacji, to teraz widzę jeden z głównych wskaźników jakości całego podejścia do automatyzacji procesu kompilacji, prawdopodobnie jako możliwość dowiedzieć się o problemach, które pojawiły się tak szybko, jak to możliwe, a co najważniejsze, aby dowiedzieć się ZANIM, w jaki sposób zmiany te dostały się do gałęzi ogólnej.

Badanie

Automatyczne kontrole jakości w aplikacjach mobilnych to z pewnością trend ostatnich lat. Z mojego doświadczenia wynika, że ​​dla wielu jest to nieco nierealne. Wszyscy o tym mówią, ale prawie nikt tego nie widział. Takimi zadaniami w ramach naszego projektu zajmujemy się od 2 lat i przez ten czas wypracowaliśmy już w miarę jasne zrozumienie większości subtelności, z którymi musi sobie radzić każdy programista. Wszystkie te problemy i rozwiązania to dość nowy i nierozstrzygnięty segment aplikacji mobilnych, choć sieć już dawno poszła tą drogą i ma wystarczającą ilość ustandaryzowanych rozwiązań.

Pierwsze pytanie, które zadaje sobie większość ludzi, brzmi: co zautomatyzujemy? Deweloper odpowie: przetestujemy kod, menadżer od razu zacznie argumentować, że trzeba przetestować funkcjonalność. Uważam, że należy przetestować jedno i drugie.

Ogólnie rzecz biorąc, jeśli mówimy o naszej aplikacji, wszystkie kontrole są podzielone na kilka kategorii:

  • Analiza statyczna: nie wiem dlaczego tak mało uwagi poświęca się temu podejściu, jest to bardzo potężne narzędzie, które pozwala zastosować sformalizowane zasady do całego projektu, a nie do poszczególnych zajęć;
  • Testów jednostkowych: dobre, staroświeckie testy jednostkowe zapewniające, że klasa działa dokładnie tak, jak oczekuje jej programista lub użytkownik;
  • Testowanie interfejsu użytkownika: testy funkcjonalne/end-to-end, które sprawdzają efekt końcowy: co zobaczy użytkownik i jak będzie z tym pracować.

Analiza statyczna

Jako analizator statyczny wykorzystujemy gotowe rozwiązania. W przypadku Androida jest to Lint, który ostatnio stał się bardzo skutecznym narzędziem do monitorowania jakości kodu specyficznego dla Androida, zasobów znaczników, grafiki itp. Umożliwia między innymi dodawanie w ramach projektu własnych kontroli specyficznych dla umowy. Jednym z takich kontraktów jest to, że żadne parametry związane z układem nie powinny znajdować się w stylach. Na przykład właściwości układ_margin\layout_alignParentTop lub coś podobnego. Z punktu widzenia składni nikt nie zabrania umieszczania tych właściwości w stylach, ale w tym przypadku sam styl służy nie do definiowania komponentu wizualnego jakiegoś komponentu interfejsu użytkownika, ale do przechowywania pewnych wartości, które następnie nie muszą być zapisane w pliku znaczników. Innymi słowy, styl służy jako kontener na atrybuty. Uznaliśmy, że są to różne rzeczy, które należy rozdzielić, ponieważ po pierwsze LayoutParams nadal odnoszą się do znacznika, a po drugie odnoszą się nie do kontrolki, w której tagu te atrybuty są zapisane, ale do jego rodzica, w którym leży.

Jeśli się temu przyjrzeć, w każdym mniej lub bardziej udanym projekcie, który zawiera przewodniki dotyczące pisania kodu, zasoby znaczników i szablony do rozwiązywania problemów typowych dla tej aplikacji, takich rzeczy jest całkiem sporo. Można je śledzić na etapie przeglądu kodu, dokumentować, przypominać o nich każdorazowo na początku dnia pracy, albo można liczyć na to, że po zapoznaniu się z tymi życzeniami, każdy będzie je realizował w przyszłości. Jak mówią, błogosławiony ten, kto wierzy, ale osobiście dużo spokojniej jest mi pracować, wiedząc, że sama o tym nie zapomnę i niczego nie przeoczę, spiesząc się, by szybko zakończyć nudne zadanie. Trzeba sformalizować takie kontrole, dodać je do procesu kompilacji za pomocą wygodnych raportów i nie martwić się, że podejmując się nowego zadania, nagle odkryjesz kod, który nie przeszedł wszystkich kontroli, przez co włos jeży Ci się na głowie.

Wypisywanie własnych czeków jest dość łatwe, a nawet przyjemne. Po dodaniu kontroli statycznych natychmiast pojawia się mnóstwo pomysłów, jak statycznie zidentyfikować inne problemy. W przypadku Linta pomocne będą w tym przewodniki i oficjalna dokumentacja. Możesz opracowywać reguły bezpośrednio w Android Studio.

Istnieją również długo wynalezione analizatory statyczne dla kodu Java. Nie będę wymieniał wszystkiego, powiem tylko, że używamy FindBugs. Wybierając narzędzie zależało nam na wygodnym formacie, wystarczającej liczbie reguł, według których będzie przeprowadzana kontrola oraz możliwości dodawania własnych reguł. W tej chwili napisaliśmy niezbędne kontrole, takie jak sprawdzanie zamkniętych kursorów, sprawdzanie, czy instancja AccountManager jest zawsze uzyskiwana z kontekstem aplikacji, sprawdzanie, czy wymagana metoda onEventComplete jest wywoływana, gdy szablon używa klasy zdarzenia i inne. Dodanie własnych reguł, które zdefiniują porozumienia wewnątrz zespołu i zapobiegną częstym błędom wynikającym z nieuwagi, to doskonała praktyka, która skraca czas przeglądu i testowania kodu, a także gwarantuje, że takie błędy przynajmniej nie wylądują w wersji produkcyjnej zastosowanie w przyszłości. Jako przewodnik po pisaniu czeków wykorzystaliśmy artykuł FindBugs, część 2: Pisanie niestandardowych detektorów. Jasno pokazuje jak stworzyć własną wtyczkę, dodać detektory i wykorzystać to w procesie weryfikacji. Raport jest dostarczany w postaci sformatowanego dokumentu HTML lub w formie raportu XML, który krótko i treściwie określa, w której klasie/metodzie znaleziono błąd, kod błędu, linię itp. Zwykle to wystarczy, aby zrozumieć, gdzie po prostu nie posprzątałeś :-).

Cudownie, prawda? Ogromny zestaw zasad i typowych błędów jest już gotowy, jest też możliwość jego uzupełnienia, wystarczy tylko znaleźć odwagę i zacząć z niego korzystać.

Któregoś dnia zauważyłem, że w naszym projekcie korzystamy z bibliotek w wersji SNAPSHOT. Oczywiście ma to zastosowanie tylko w gałęzi zadań, gdy zmiany zostaną wprowadzone w używanej bibliotece. Po włączeniu kodu do głównej gałęzi w projekcie nie powinno być żadnych SNAPSHOTów. W tym przypadku przyczyna jest dość prozaiczna i charakteryzuje większość tych błędów. Po przetestowaniu zadania i zdecydowaniu, że ta wersja osiągnęła wszystkie założenia, programista był tak szczęśliwy, że zapomniał połączyć bibliotekę z gałęzią główną, zdefiniować nową wersję tej biblioteki i zmienić wersję w główny projekt. Problem polega na tym, że ani Lint, ani FindBugs nie mogą sprawdzić skryptu kompilacji. Co więcej, nawet jeśli te kontrole zostaną dodane do samego build.gradle, musisz wiedzieć, gdzie jest to dopuszczalne, a gdzie nie. Jest to oczywiście dopuszczalne w filii, w której biblioteka jest aktualnie zmieniana, ale jest niedopuszczalne po wejściu do filii ogólnej. W ten sposób zaczęliśmy używać haków git pre-receive do śledzenia tego, co dzieje się w projekcie na poziomie repozytorium.

Wiem, że wiele zespołów nie uważa za konieczne tracić czasu na ustalanie odpowiednich dla projektu reguł na poziomie systemu kontroli wersji, bo „nie jesteśmy głupcami, nikt nie usunie wszystkich gałęzi w repozytorium” lub z innego powodu powodów, na przykład braku czasu. Dla nas to etap zaliczony: doszliśmy do decyzji, że lepiej poświęcić trochę więcej czasu, ale mieć pewność co do bezpieczeństwa i jakości produktu. Haki przed odbiorem sprawdzają się w tym celu bardzo dobrze: możemy wykryć, że do współdzielonej gałęzi dodawane są zmiany i sprawdzić, czy HEAD tej współdzielonej gałęzi nie zawiera niepożądanego kodu. W najlepszym przypadku nikt nigdy nie będzie wiedział o istnieniu takiej kontroli, ale jak pokazuje praktyka, wystarczy przypadkowy błąd, aby stworzyć możliwość popełnienia istotnego błędu. Hak przed odbiorem jest idealny do sprawdzania wszystkich poprawionych zadań TODO i FIXME, które programista chętnie umieszcza, ale zapomina je naprawić. Dobrze radzi sobie także z typowymi problemami z logowaniem - dodaniem wyjścia funkcji new Throwable() do wszystkich funkcji interesujących programistę, ponieważ w gałęzi znaleziono bardzo złożony błąd wymagający dużej ilości szczegółów. Dla nas umiejętność śledzenia popełnianych błędów jest automatycznie ważna dla zrozumienia, że ​​​​nie staniemy ponownie na tym samym prowizji. Każdy popełnia błędy, liczy się tylko to, jakie wnioski z tego wyciągniesz. Nasz wniosek jest taki, że oprócz korekty należy podjąć wysiłki, aby zapobiec popełnianiu tych błędów w przyszłości.

Testów jednostkowych

Tutaj w zasadzie wszystko jest zwyczajne. Dla niektórych klas pisane są testy, które sprawdzają, czy klasa działa dokładnie tak, jak zamierzono, a jednocześnie pokazują klientowi klasy przykład, jak można ją wykorzystać. Obecnie testy jednostkowe działają na rzeczywistych urządzeniach, ale w razie potrzeby nie nawiązują prawdziwego połączenia. A skoro mowa o konieczności nawiązania połączenia: kiedy programista myśli o tym, jak przetestować konkretny moduł, najczęściej pierwszą rzeczą, o której myśli, jest to, jak zastąpić zależności klas, aby odizolować testowanie od środowiska na żywo. W przypadku połączenia sieciowego może się to wydawać zadaniem trudnym, gdyż komunikacji sieciowej nie zastępuje wywołanie jednej metody, lecz wymaga zhakowania całej warstwy logiki. Przez pewien czas wzbranialiśmy się przed użyciem haka w kodzie aplikacji w celu nadpisania odpowiedzi serwera i wykonania za jego pomocą wszystkich kolejnych akcji. Faktem jest, że takie podejście zwiększa ryzyko, że kod, który będzie testowany, nie będzie tym, który sprawdzi się w aplikacji produkcyjnej. Za każdym razem, gdy pojawia się pytanie, czy warto zmienić interfejs klasy dla ułatwienia testowania, czy warto dodać do procesu wykonywania funkcji dodatkowe warunki, aby „zablokować” jakieś zależności, staram się trzymać następującego stanowiska : po pierwsze, cały napisany kod musi być bezpieczny pod względem funkcji aplikacji. Jeżeli dodatkowe warunki dodane do kodu wymagają osobnej weryfikacji, to testy nie muszą tego robić. To jest główny powód, dla którego nie zadowolił nas zwykły seter, który po prostu zastąpiłby odpowiedź, wziął ją z innego źródła.

W rezultacie podjęliśmy inną, moim zdaniem, bardziej uczciwą decyzję. Tak wygląda jeden z testów, który sprawdza, czy przy określonej odpowiedzi polecenie generuje status „folder_błędów_nie_istnieje”

@AcquireCookie @LargeTest publiczny test nieważnościDeleteNonExistingFolder() ( DeleteFolder usuń = runDeleteFolder(999); asertERROR_FOLDER_NOT_EXIST(usuń); )
W tym teście uczciwie wysyłamy żądanie do serwera, czyli polecenie działa dokładnie tak samo jak w aplikacji. Problem polega na tym, że test jednostkowy zależy od konfiguracji sieci na urządzeniu, na którym jest uruchomiona. A poniżej drugi test, który sprawdza dokładnie to samo, ale podstawiając żądaną odpowiedź, bez wykonywania prawdziwego żądania i bez interakcji z serwerem.

@MockMethod(response = RESPONSE_NOT_EXISTS) publiczna nieważność testDeleteNonExistingFolderMock() ( testDeleteNonExistingFolder(); )
Dzięki temu mamy możliwość kontrolowania wykonania testów – jest to konieczne np. aby status kompilacji nie uwzględniał odpowiedzi serwera. Polegamy na tym, że opisany jest protokół interakcji i upewniając się, że żądanie jest poprawnie sformułowane (oczywiście za pomocą testów jednostkowych), możemy być pewni, że serwer udzieli prawidłowej odpowiedzi. A jeśli odpowiedź jest prawidłowa, pozostaje tylko upewnić się, że aplikacja odpowiednio ją zinterpretuje. Jednak np. w przypadku kompilacji nocnej miło byłoby również upewnić się, że umowa o interakcję z serwerem nie została naruszona. W tym celu uruchomione zostaną wszystkie testy, łącznie z tymi, które faktycznie z nim współdziałają. Zapewni nam to dodatkowe zabezpieczenie na wypadek zerwania umowy na interakcję z serwerem z powodu jakiegoś błędu. Dowiadujemy się o tym z wyników testów, a nie z opinii użytkowników na rynku. Jeśli tak ważne jest dla nas przetestowanie funkcjonalności od początku do końca, możemy uczynić te testy głównymi i uruchamiać je dla każdej kompilacji aplikacji.

Fakt jest taki, że nie chcemy ciągle polegać na serwisie, ale jednocześnie musimy monitorować sytuację i otrzymywać informacje w postaci codziennych raportów, że wszystko jest w porządku, lub że jakaś część aplikacji nie działa zamówienie. Tutaj wolę oddzielić naszą aplikację od usług zewnętrznych, które są krytyczne dla jej pełnego działania, ale nie są naszym obszarem odpowiedzialności. Możemy wykryć w naszej aplikacji problem związany z działaniem usługi strony trzeciej, ale nie jesteśmy w stanie go naprawić. Naszym zadaniem jest zgłoszenie problemu, oczekiwanie na jego rozwiązanie i przeprowadzenie testów usługi, aby upewnić się, że problem został rozwiązany.

Testowanie interfejsu użytkownika

Z punktu widzenia użytkownika są to najbardziej uczciwe testy. Z punktu widzenia dewelopera są one najtrudniejsze. Najbardziej uczciwi, bo testują produkt końcowy, a nie tylko jego część. Zrzucanie winy na kogoś innego nie zadziała: każdy błąd jest błędem aplikacji i nie ma znaczenia, jaka jest jego przyczyna, niedoskonałość Androida w krzywych rękach innego programisty lub coś innego. W każdym razie błąd należy naprawić. Zaletami takich testów czarnej skrzynki jest to, że dla nas tak naprawdę nie ma znaczenia, w jaki sposób dana funkcjonalność jest zaimplementowana, jaką architekturę ma aplikacja itp. Jeśli dwa błędy w aplikacji nakładają się na siebie i w efekcie użytkownik zobaczył poprawny wynik - jesteśmy z niego zadowoleni. Jeśli we wszystkich wielu przypadkach błędy aplikacji pozwalają nam uzyskać prawidłowe wyniki dla użytkownika, odpowiada nam to z punktu widzenia testowania funkcjonalności.

Podczas gdy testy jednostkowe sprawdzają, czy kod działa dokładnie tak, jak zamierzył programista, testy interfejsu użytkownika mają raczej na celu zapewnienie, że zespół odpowiedzialny za produkt upewni się, że skrypty użytkownika są wykonywane poprawnie w aplikacji.

Istnieją również błędy związane ze skryptami użytkownika. Jednym z najlepszych sposobów naprawienia błędu aplikacji, gdy masz już skrypt do jego odtworzenia, jest napisanie testu. Sprawdź, czy problem istnieje. Napraw problem w kodzie aplikacji (jeśli to konieczne, dołącz do niego dodatkowe testy jednostkowe na module, w którym żadne zachowanie nie zostało zamknięte) i upewnij się, że test został teraz zakończony pomyślnie. W tym przypadku nie ma potrzeby angażowania całego aparatu biurokratycznego, w którym kilka osób musi zatwierdzić, że błąd został naprawiony, że nic nowego nie zostało zepsute itp. Rzecz w tym, że jeśli test jest napisany przemyślanie i dokładnie pod kątem celem wykrycia i zidentyfikowania problemu, to jeśli zostanie pomyślnie zakończony, istnieje już powód, aby uznać problem za rozwiązany. Im więcej takich spraw zamykają testy, tym lepsza jakość sprawdzenia, bo tym większe prawdopodobieństwo, że niczego nie przeoczyliśmy.

Oczywiście zrobienie tego wszystkiego jest znacznie trudniejsze niż powiedzenie tego. Ale najpierw: zacznijmy od wyboru frameworka, na którym będziemy budować nasze testy. Znów nie będę otwierał Ameryki pisząc, że frameworków jest obecnie całkiem sporo, ale nie da się polecić jednego, który rozwiąże 99% wszystkich problemów. Możesz zacząć pisać swój własny idealny framework, zakładając, że współczynnik krzywizny Twojej ręki jest mniejszy niż u konkurencji i mając nadzieję, że za miesiąc wszystkie Twoje problemy zostaną rozwiązane, a po sześciu miesiącach, obliczywszy koszt takiego rozwiązania, ponownie wrócić do tego wyboru. Niezbyt lubię wykonywać pracę innych ludzi i może dlatego uważam takie podejście za utopię. Testowanie międzyplatformowe postrzegam również jako utopię, ponieważ różnice między Androidem a iOS są zbyt duże. Napisanie jednego zestawu testów, które sprawdzą zarówno jedną, jak i drugą aplikację, tylko na pierwszy rzut oka wydaje się oczywistym rozwiązaniem. Inna nawigacja w aplikacji, inny układ w obrębie tego samego ekranu, inne zachowanie systemu w reakcji na minimalizację aplikacji, nie mówiąc już o tym, że nawet funkcjonalność może się różnić, bo każdy produkt wysokiej jakości będzie uwzględniał wszystkie cechy aplikacji platformę, aby zapewnić użytkownikowi jak najlepsze doświadczenia.

Historycznie w projekcie korzystaliśmy z Robotium. Jest to bardzo znane rozwiązanie, z którego korzysta duża liczba zespołów zarówno w naszym kraju, jak i za granicą. Co ciekawe, wszystkich jego użytkowników łączy żarliwa niechęć do tego właśnie frameworku. Pisanie testów jest powolne, niestabilne i niewygodne. Ale mimo to wszyscy regularnie wracają do jego używania. Niezależnie od tego, czy jest to espresso! Jest szybki jak wiatr, stabilny jak gospodarka Stanów Zjednoczonych itp. Właśnie na tym polega reputacja giganta wyszukiwarek w przypadku projektów, które bierze pod swoje skrzydła. Na Robotium piszemy od 2 lat, więc z dużym przekonaniem mogę stwierdzić, że za niestabilność i niską prędkość odpowiada raczej klient piszący te testy. Rozwiążmy to. Przyczyną problemów z szybkością często nie jest niedoskonałość algorytmów Robotium, nie ich architektura, ale fakt, że testy zawierają nadużycia tzw. wzorca uśpienia. Jego istotą jest to, że każdy problem można rozwiązać, dodając parametr Sleep(N * 1000) przed linią, w której wykryto problem. Podstawą tego jest następująca prosta rzecz: testy są wykonywane w wątku innym niż główny wątek aplikacji (wątek UI). W związku z tym synchronizacja przeprowadzana za pomocą funkcji Sleep() nie jest dobrym rozwiązaniem problemu. Stąd wynik: nawet jeśli odczekasz 10 sekund między krokami testów, wynik nie będzie gwarantowany. W testach opartych na Instrumentacji istnieje coś, co czeka, aż wątek interfejsu użytkownika aplikacji zakończy aktualnie trwające operacje. Klasa android.app.Instrumentation posiada metodę:

/** * Synchronicznie czekaj, aż aplikacja będzie bezczynna. Nie można wywołać * z głównego wątku aplikacji — użyj (@link #start), aby wykonać * instrumentację we własnym wątku. */ public void waitForIdleSync() ( validNotAppThread(); Idler idler = new Idler(null); mMessageQueue.addIdleHandler(idler); mThread.getHandler().post(new pustyRunnable()); idler.waitForIdle(); )
Użycie go, jak się przekonaliśmy, rozwiązuje większość problemów związanych z nieodnalezieniem widoku, chociaż zrzuty ekranu pokazują, że wszystko jest wyświetlane, a także z widokiem w stanie pośrednim, animującym jego właściwości z jednej wartości na drugą itp.

Naturalnie nie dawały nam spokoju historie, że espresso jest wielokrotnie lepsze. Plan przejścia na te ramy był gotowy już od dawna; Poza tym Google przywiązuje obecnie dość dużą wagę do kwestii testów automatycznych, więc istnieją przesłanki, aby Espresso mogło się aktywniej rozwijać. Determinacji dodało także przekonanie Lead developera, że ​​aby przejść z Robotium na Espresso wystarczy zmienić TestRunnera. Spróbowaliśmy tego i testy faktycznie zadziałały. Teraz możemy pisać nowe skrypty bez zmiany starych testów na raz i nadal korzystać ze wszystkich zalet Espresso. Dla nas to zdeterminowało przejście na nowy framework. Uruchomiliśmy testy i zamarliśmy w oczekiwaniu na wyniki.

Espresso rzeczywiście było szybsze, choć nie było radykalnych zmian. Teraz wszystkie nasze testy są podzielone na ~26 pakietów i w każdym zauważono przyspieszenie. Ale całkowite zmiany w szybkości zaliczania testów mieszczą się w granicach 4%. Moim zdaniem nie jest to istotna zaleta. Znacznie więcej, moim zdaniem, umożliwia napisanie analogu waitForIdleSync do dowolnego oczekiwania w aplikacji: nie tylko do zadań interfejsu i animacji, ale także do zadań ładowania danych z sieci i z dysku - do dowolnych interakcji w wyniku czego musimy działać, sprawdzając kod testowy. Ta funkcja nazywa się CustomIdlingResource i naprawdę wyróżnia Espresso w porównaniu do Robotium. Pomimo tego, że pomysł jest bardzo prosty, a mianowicie umożliwienia zarejestrowania własnej implementacji interfejsu oczekiwania w stanie bezczynności, niestandardowy zasób bezczynności pozwala zarządzać synchronizacją pomiędzy testami a aplikacją. Można w ten sposób zaczekać, aż w aplikacji zakończą się np. wszystkie operacje asynchroniczne, co wraz ze stanem bezczynności głównego wątku oznacza, że ​​można zakończyć oczekiwanie i rozpocząć sprawdzanie stanu aplikacji.

Oczywiście Espresso nie jest baśniowym dżinem. Nie może rozwiązać wszystkich Twoich problemów, nie może napisać za Ciebie testów i nie poradzi sobie z zadaniami utrzymania infrastruktury testowej, przeprowadzania testów i zbierania raportów.

Oprócz testowania rzeczywistej funkcjonalności aplikacji, częstym wyzwaniem w kontekście zautomatyzowanych testów jakości jest interakcja produktu z innymi aplikacjami, które mogą być zainstalowane na telefonie użytkownika. Jako przykład możesz wziąć na przykład Udostępnianie z innej aplikacji (jest to dość istotne w przypadku klienta poczty e-mail) lub pasek stanu powiadomienia. W obu przypadkach skrypt wpływa na inną aplikację działającą w innym procesie. Wszystkie frameworki podobne do Robotium/Espresso stają się ślepe, gdy tylko zaangażowany jest inny proces. Na szczęście istnieje już rozwiązanie umożliwiające pisanie testów funkcjonalnych interfejsu użytkownika między aplikacjami i nosi nazwę UI Automator. Gdybyśmy wcześniej musieli wybierać między tym czy innym frameworkiem lub wspierać różne projekty, z których każdy byłby dostosowany do różnych testów, to wraz z wydaniem Biblioteki wsparcia testowania, ogłoszonej na ostatniej konferencji Google I/O 2015, może połączyć zalety każdego podejścia i zastosować narzędzia, które będą wymagane w każdym indywidualnym przypadku. Oznacza to, że np. dla klienta poczty e-mail możemy zautomatyzować następujący skrypt:

  1. Uruchom aplikację, przejdź do listy liter.
  2. Otwórz pisanie nowego listu, wprowadź temat, odbiorcę, dołącz załączniki.
  3. Otrzymuj powiadomienia push na połączoną skrzynkę pocztową.
  4. Przejdź do powiadomienia i sprawdź treść nowego pisma.
  5. Wyjdź z ekranu nowego listu przyciskiem Wstecz Upewnij się, że wróciliśmy do ekranu pisania listu i że wszystkie wypełnione pola zostały zapisane.
W tym przykładzie możemy bezpiecznie wykorzystać poprzedni framework do poruszania się po modelach listy listów, czytania listu, pisania nowego listu itp., a w krokach 3 i 4 możemy użyć frameworku uiAutomator do sprawdzenia powiadomienia tekst, upewnij się, że powiadomienie zawiera niezbędne przyciski i podążaj za powiadomieniem do aplikacji. Wtedy w teście w dalszym ciągu będziemy korzystać z API Espresso i nie będziemy musieli pisać kolejnej implementacji istniejących modeli dla drugiego frameworka. Dla mnie jako programisty to najlepsza wiadomość, jaka mogła się pojawić w kontekście bibliotek do automatyzacji testów.

Oczywiście wszystko to wydaje się proste tylko na pierwszy rzut oka. Za kulisami kryła się gromada zebranych grabieży i wkraczanie w najbardziej nieprzyjemne substancje – momentami wydawało się, że całego tego pomysłu po prostu nie da się zrealizować.

W przyszłości osobno porozmawiamy o tym, jak zbudowana jest infrastruktura, jak zapewniona jest gotowość urządzeń do pracy przez całą dobę, jak rozkładają się testy dla różnych smaków produktów na różne złożenia, jak testowane są różne wdrożenia w zależności od wersji system operacyjny, wielkość urządzenia itp. . Przecież przed nami dwa długie lata zmagań z adb, usb, VirtualBox i wieloma innymi narzędziami i technologiami. Przed nami jeszcze więcej pracy, niż już wykonano, ale rozumiemy, że to wszystko nie poszło na marne.

Jakoś cicho i bez specjalnych opisów pracy 1C wypuściło konfigurację „Mobile Application Collector”, która ma stać się swego rodzaju organizatorem rozwoju aplikacji mobilnych.

W aktualnej najnowszej wersji 1.0.3.17 występuje kilka drobnych problemów, które na pierwszy rzut oka wyglądają jak błędy.

Pierwszym problemem, jaki napotykamy, jest niemożność uruchomienia konfiguracji bez użytkownika, pojawia się następujący błąd:

„Wersja konfiguracyjna różni się od wersji bazy danych. Konieczna jest aktualizacja konfiguracji poprzez uruchomienie aplikacji jako użytkownik z uprawnieniami Administratora

Problem ten można rozwiązać w bardzo prosty sposób, wystarczy uruchomić konfigurator i dodać użytkownika z uprawnieniami „Administratora”.

Drugi problem pojawia się, gdy próbujemy utworzyć element w katalogu „Konfiguracje mobilne”. Klikamy przycisk „Utwórz” i pojawia się błąd „Elementy można tworzyć tylko w grupach”:

Nie ma problemu, klikamy przycisk „Utwórz grupę” i nagle ponownie pojawia się komunikat o błędzie „Elementy można tworzyć tylko w grupach”.

Rozwiązaniem jest wykonanie następujących czynności:

Na górnym panelu znajduje się przycisk „Utwórz”, który wywołuje podmenu. Kliknij w nim element „Konfiguracja mobilna”:

Po czym otwiera się dość przyjazne okno, w którym możesz tworzyć grupy:

Występuje również problem podczas tworzenia pozycji katalogu „Aplikacje mobilne”, pojawia się następujący komunikat o błędzie:

„Prefiks identyfikatora aplikacji nie jest ustawiony w ustawieniach dostawcy”:

Wyjście jest również dość blisko:

I zaczynamy wprowadzać dane do elementu katalogu „Dostawcy rozwiązań mobilnych”.

Przedrostek musi zawierać „kropkę” w środku. I kliknij „Utwórz klucz programisty”.