Numeracja wersji aplikacji Android

Może się wydawać, że numeracja wersji aplikacji jest bardzo prosta. Na początku możemy wydać wersję rozpoczynającą się od numerka 1.0, a potem kiedy wprowadzimy do kodu jakieś zmiany, wydajemy wersję aplikacji oznaczoną jako 1.1. Jest to oczywiście prawda, jednak postaram się na przykładzie aplikacji na Androida wyjaśnić, jak według mnie powinno to dokładnie wyglądać, biorąc również pod uwagę to, że oprócz nazwy wersji aplikacji mamy konieczność określenia jej kodu wersji.

Nazwa wersji aplikacji

Aby określić nazwę wersji aplikacji, przechodzimy do pliku build.gradle i definiujemy ją w atrybucie versionName, który to przyjmuje jako wartość ciąg znaków. Traktujemy ją jako zapis wersji naszej aplikacji, która będzie jak najbardziej zrozumiała dla użytkownika. Oznacza to, że możemy tutaj wpisać dowolną nazwę, jaka tylko będzie dla nas odpowiednia i nic nie stoi na przeszkodzie, żeby wyglądała ona następująco:

versionName "pierwsza-wersja"

Jednak ogólnie przyjęta zasada numeracja wersji oprogramowania mówi, żeby zapisywać ją według konkretnego schematu:

<major>.<minor>.<release>

A teraz co te wszystkie magiczne określenia znaczą:

  • major: zmiana tego numeru odbywa się najrzadziej i następuje ona zazwyczaj podczas zmiany koncepcji, całkowitej zmiany designu lub zasad działania aplikacji,
  • minor: ten numer zmienia się już trochę częściej i dzieje się to przede wszystkim, gdy nasza aplikacja nie zmienia swojego działania, a dodajemy do niej jakąś nową funkcjonalność,
  • release: fragment ten zmienia się najczęściej, ponieważ następuje to podczas każdego wypuszczenia nowej wersji aplikacji i zmienia się, kiedy tylko w ramach jednej koncepcji działania aplikacji i jej funkcjonalności wprowadzamy poprawki błędów czy jakieś łatki.

Jak już wyżej wspomniałem, jest to ciąg znaków, więc jeśli tylko wypuszczamy wersję alpha lub beta naszej aplikacji, możemy taką informację bez obaw tutaj zapisać:

versionName "2.1.0-beta"

Kod wersji aplikacji

Również w pliku build.gradle możemy znaleźć atrybut versionCode, który jest już przeznaczony dla developerów, jak również jest interpretowany przez Sklep Play, kiedy publikujemy nową wersję aplikacji. Tym razem mamy już do czynienia z liczbą, a nie z dowolnym ciągiem znaków. Początkowo, po utworzeniu nowego projektu w Android Studio, wygląda on następująco:

versionCode 1

Podczas publikacji nowej wersji aplikacji w Sklepie Play należy pamiętać, aby powiększyć wartość tego numerka. Jednak w tym miejscu należałoby również przyjąć pewne założenie, zamiast po prostu zwiększyć wartość o jeden i kolejną wersję aplikacji wypuścić z versionCode o wartości 2. Należy tutaj jeszcze zaznaczyć, że maksymalna wartość dla versionCode to 2100000000.

Bardzo dobrą i rozsądną zasadą jest jednak powiązanie wartości versionCode z atrybutem versionName, jak również z atrybutem minSdkVersion, który służy do określenia minimalnej wersji SDK Androida, na której będzie działała nasza aplikacja. Dlaczego? Postaram się to wytłumaczyć.

Atrybut versionCode a versionName

Bardzo dobrą praktyką jest przeniesienie wartości atrybutu versionName do versionCode pod postacią:

versionCode XXYYZZ

gdzie:

  • XX: major w postaci dwóch cyfr (jeśli nasz numer wersji major jest liczbą jednocyfrową, wówczas zapisujemy go pod postacią jednej cyfry, ponieważ niestety zero na przodzie nie zadziała),
  • YY: minor w postaci dwóch cyfr,
  • ZZ: release w postaci dwóch cyfr.

Przyjmijmy teraz, że nasza wersja aplikacji to 2.1.3, a oto przykład jak będzie dla niej wyglądał versionCode:

versionCode 20103

Dzięki temu zabiegowi mamy możliwość tworzenia bardzo dużej ilości wersji aplikacji począwszy od wersji 0.0.1 aż do 99.99.99.

Teraz odpowiedzmy na pytanie: jakie z tego mam korzyści? Otóż łatwiej jest wówczas orientować się w wersji aplikacji, ponieważ oba atrybuty są sobie równe. Drugi bardzo ważny powód to możliwość łatwego rozdzielenia aplikacji na poszczególne ścieżki wydań.

Przyjmijmy następujący scenariusz, który pokaże nam minus zwiększania wartości versionCode o 1:

  • wersja produkcyjna aplikacji posiada versionName "2.1.3" oraz versionCode 7,
  • chcemy wydać wersję beta aplikacji z nową funkcjonalnością, którą oznaczamy jako versionName "2.4.0" oraz versionCode 8 (wiadomo, wartość tę musimy podnieść),
  • w wersji 2.1.3 pojawił się jakiś błąd, który chcemy naprawić, zmieniamy więc wartość versionName "2.1.4" oraz ustawiamy versionCode 9?

No i właśnie tutaj pojawia się konflikt, ponieważ kod wersji nie może się powtórzyć, jak również jest on wówczas wyższy niż w wersji beta, a przykładowo poprawiliśmy tylko literówkę. Co więcej, jeśli nasza aplikacja znajduje się w Sklepie Play, po wydaniu poprawki dla wersji produkcyjnej, naszym beta testerom aplikacja zaktualizuje się (zdowngrade’uje) do tej wersji, ponieważ wartość atrybutu versionCode będzie wyższa niż ta w obecnie zainstalowanej wersji beta.

Sprawdźmy teraz, jak to wygląda w przypadku powiązania ze sobą versionName oraz versionCode:

  • wersja produkcyjna posiada versionName "2.1.3" oraz versionCode 20103,
  • wydajemy wersję beta z nową funkcjonalnością i oznaczamy jako versionName "2.4.0" oraz versionCode 20400,
  • poprawiamy błąd w wersji produkcyjnej oraz aktualizujemy atrybuty versionName "2.1.4" oraz versionCode 20304,
  • otrzymujemy wartości atrybutów versionCode, które nie wchodzą sobie w paradę, a nasi beta testerzy pozostaną przy zainstalowanej wersji beta aplikacji, ponieważ jej versionCode jest już wyższy niż zaktualizowanej wersji produkcyjnej.

Atrybut minSdkVersion a versionCode

Do całości brakuje nam jeszcze określenia docelowych wersji Androida obsługiwanych przez naszą aplikację. W pewnym momencie możemy dojść do wniosku, że rozwijanie aplikacji dla bardzo starej wersji systemu nie jest już dla nas opłacalne, ale jednak nie chcemy całkowicie z niej rezygnować, ponieważ posiada ona dużą ilość aktywnych użytkowników. W takim przypadku w atrybucie versionCode warto również zawrzeć informację o minimalnej wspieranej wersji systemu pod postacią:

versionCode MMXXYYZZ

gdzie:

  • MM: wartość atrybutu minSdkVersion w postaci dwóch cyfr (jeśli jest to jedna cyfra to zapisujemy tylko jedną bez zera na przedzie),
  • XX: poznany już major,
  • YY: poznany już minor,
  • ZZ: poznany już release.

Uznajmy więc, że mamy wersję produkcyjną aplikacji o versionName "2.1.4" (już po poprawce literówki), która wspiera system Android od wersji 14 SDK oraz wydajemy wersję 3.0.0 aplikacji, ale tylko dla urządzeń z Androidem w wersji minimum 6.0 (wersja 23 SDK). Oto jak całość będzie wyglądała, kiedy dodamy do Sklepu Play dwie wersje aplikacji:

  • 2.1.4: minSdkVersion 14, versionName "2.1.4", versionCode 14020104,
  • 3.0.0: minSdkVersion 23, versionName "3.0.0", versionCode 23030000.

W takim przypadku użytkownik instalujący aplikację ze Sklepu Play posiadający system starszy niż Android 6.0 pobierze wersję 2.1.4, a nowszą wersję systemu już aplikację o numerze 3.0.0 (zadba o to atrybut minSdkVersion). Dodatkowo jakaś aktualizacja aplikacji z wersji 2.x będzie ciągle posiadała versionCode niższy niż aplikacja z wersji 3.x, co nie spowoduje sytuacji, w której kod wersji z aplikacji 2.x będzie wyższy niż 3.x.

Dodatkowym plusem dodania wartości z minSdkVersion do versionCode jest również sytuacja, w której posiadamy taką samą wersję aplikacji, ale z innymi funkcjami dla starszych i nowszych wersji systemu Android:

  • Android od wersji API 14: minSdkVersion 14, versionName "2.1.4", versionCode 14020104,
  • Android od wersji API 23: minSdkVersion 23, versionName "2.1.4", versionCode 23020104.

Aktualizacja takich aplikacji w różnych wersjach nie powoduje konfliktów atrybutu versionCode.

Podsumowanie

Już na samym początku tworzenia aplikacji na Androida jest w versionCode zawrzeć wartości atrybutów minSdkVersion, jak również versionName na podstawie wyżej przedstawionych zasad. Nigdy nie wiadomo jakie będą dalsze losy naszej aplikacji ze względu na to, że zmiany w SDK Androida z każdą wersją mogą być coraz większe oraz może się również w przyszłości okazać, że potrzebujemy wypuścić aplikację w wersji alpha czy beta do testów przed wdrożeniem jakichś przełomowych zmian do wersji produkcyjnej. Dzięki tym prostym zabiegom zabezpieczamy się przed komplikacjami, które mogą pojawić się prędzej czy później.