Budowanie aplikacji to pasja dzielona przez programistów na całym świecie. Jednak koszty administracyjne związane z zarządzaniem podpisywaniem kodu są przygnębiające. Jak możemy zrobić to dobrze za pierwszym razem? Lewis Cianci przygląda się temu zagadnieniu.
Pozwólcie mi to powiedzieć z góry.
Podpisywanie kodu jest tak nudne, że aż bolą mnie zęby. Jest to koncepcja, która istnieje z dobrego powodu. To znaczy, chcesz, aby ludzie byli pewni, że twój pakiet oprogramowania jest rzeczywiście od ciebie, prawda?! A jednak, jest to coś, z czym tak wielu programistów zmaga się na co dzień. To jak robienie swoich podatków po całym roku pracy i posiadanie tak wielu formularzy do wypełnienia. Yippee.
Przewiń w dół, jeśli chcesz tylko zobaczyć przewodnik krok po kroku na temat podpisywania kodu na Androida i nie jesteś zainteresowany tym, dlaczego to robimy😉
Dlaczego podpisujemy kod
Podpisujemy nasze pakiety, więc ludzie, którzy pobierają nasz pakiet ze Sklepu Play faktycznie wiedzą, że to my. Robimy to podpisując nasz pakiet kluczem, który sami generujemy. Kiedy przesyłamy nasz podpisany pakiet do Google Play, pamięta on klucz, który został użyty do przesłania pierwszego pakietu i upewnia się, że kolejne pakiety są podpisane tym samym kluczem.
Aby osiągnąć ten cel, Android podpisywanie pakietów faktycznie korzysta z narzędzia, które pochodzi z Java Development Framework o nazwie keytool. Keytool istnieje prawdopodobnie tak długo, jak sam JDK, więc jest dość stary. To nadaje się do prawdopodobnie niektóre z powodów, dlaczego podpisywanie APK lub AAB (android app bundle) jest tak mylące, jak to jest.
Dlaczego Sklep Play nie może po prostu obsługiwać podpisywanie kodu dla nas?
Możemy być kuszeni, aby poprosić o nirwanę, gdzie możemy po prostu dać wszystkie nasze niepodpisane pakiety aplikacji do Sklepu Play i po prostu mieć je wypracować i po prostu podpisać go dla nas. Logika tego szybko załamuje się jednak. Jeśli napisałeś książkę, czy dostać kogoś innego, aby go podpisać? Nie. Podpisałbyś ją, ponieważ jesteś autorem.
W dzisiejszych czasach podpisywanie kodu jest o wiele łatwiejsze niż kiedyś. Tak długo, jak będziemy zawsze podpisywać nasze pakiety tym samym kluczem („klucz przesyłania”), Google Play faktycznie wygeneruje i będzie zarządzać naszymi kluczami podpisywania kodu dla nas.
Jeśli jesteś szczególnie przedsiębiorczy, możesz spróbować przeczytać i zrozumieć wszystko tutaj, ale rozwijałem się dla Androida przez lepszą część trzech lat teraz i przykro mi powiedzieć, że nawet ja nie rozumiem tego całkowicie. Wszystko, co wiem, to to, że kiedy to się psuje, to jest ogromny ból, aby to naprawić.
Poświęćmy trochę czasu, aby zrozumieć nie tylko jak kodować znak, ale także dlaczego kodujemy znak. Kiedy zrozumiemy konieczność tego procesu, będzie on łatwiejszy do wykonania.
Co jest potrzebne do podpisywania kodu?
Krótka wersja jest tutaj. Do podpisywania kodu potrzebujemy:
- utworzyć plik Java Development Kit (JDK);
- podpisać nasz pakiet aplikacji lub APK naszym kluczem prywatnym;
- zmodyfikować build.gradle;
- wysłać pakiet do dystrybutora (Google Play).
Na końcu tego artykułu znajdziesz również jak sprawić, aby podpisywanie kodu działało z Codemagic.
Teraz nieco dłuższa wersja z przewodnikiem krok po kroku na temat tego, czego potrzebujemy do podpisywania kodu Android i jak to zrobić.
Przewodnik krok po kroku do podpisywania kodu Android
KROK 1: The Java Development Kit (JDK)
Jeśli tworzysz dla Androida, prawdopodobnie masz już je zainstalowane.
Musimy utworzyć plik Java Key Store (JKS), który zawiera nasze informacje o podpisywaniu. Generując JKS dla naszej aplikacji, w rzeczywistości tworzymy klucz prywatny na naszym komputerze. Ten klucz prywatny jest chroniony przez hasło, które ustawiamy.
Z wiersza poleceń możemy wpisać następujące polecenie, aby uzyskać JKS.
keytool -genkey -v -keystore %DESKTOP%/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias DEVELOPERNAME
Powiadamiamy keytool
, aby wygenerował Java Key Store i umieścił go na naszym pulpicie. Ten klucz będzie ważny przez 10,000 dni lub około 27 lat, co pozwoli nam na aktualizacje przez cały czas życia naszej aplikacji. Jesteśmy również zobowiązani do ustawienia aliasu. Ja po prostu robię to moje imię dewelopera lub coś, co zapamiętam.
keytool
będzie monitować o różne informacje po drodze. Ważne jest, aby określić je poprawnie, ponieważ zasadniczo definiujemy szczegóły dla naszego klucza prywatnego.
Zostaniesz poproszony o:
- Hasło magazynu kluczy – będziesz potrzebował tego, aby odblokować ten magazyn kluczy ponownie w przyszłości. Jeśli zgubisz to hasło, odzyskanie go jest praktycznie niemożliwe.
- Re-enter keystore password
- Personal details about what to put in the personal certificate
Wtedy zostaniemy poproszeni o wypełnienie kilku informacji o nas. Są to dane związane z naszym kluczem prywatnym, więc powinny być w miarę istotne. Od ciebie zależy, co umieścisz w tych polach, ale z reguły nie byłoby w nich zbyt wiele szaleństwa.
To jest wyjście keytool
.
C:\code\signingtest\android\app>keytool -genkey -v -keystore key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias androidappsEnter keystore password:Re-enter new password:What is your first and last name?: Codemagic Article DudeWhat is the name of your organizational unit?: Fantastic Apps And Where To Find ThemWhat is the name of your organization?: GreatappsWhat is the name of your City or Locality?: EstoniaWhat is the name of your State or Province?: TartuWhat is the two-letter country code for this unit?: EEIs CN=Codemagic Article Dude, OU=Fantastic Apps And Where To Find Them, O=Greatapps, L=Estonia, ST=Tartu, C=ES correct?:
Uwaga! Jeśli po prostu spamujesz Enter w tym procesie, tworzenie będzie się zapętlać w kółko, ponieważ odpowiadasz „nie” na ostatnie pytanie.
W ten sposób stworzyliśmy JKS i umieściliśmy w nim nasz własny wygenerowany klucz prywatny. Ponieważ wygenerowaliśmy go i ustawiliśmy hasło, możemy być pewni, że każdy, kto ma ten plik JKS, jest albo nami, albo jest specjalnie upoważniony do korzystania z niego.
Jeśli ktoś ma twój JKS i prawidłowe dane uwierzytelniające, może podpisać pakiety jako ty lub twoja firma. Trzymaj go bezpiecznie, nie umieszczaj go w kontroli źródła.
Teraz mamy nasz Java Key Store, więc jesteśmy w połowie drogi! Raduj się odpowiednio.
KROK 2: Podpisywanie naszego pakietu aplikacji lub APK naszym kluczem prywatnym
Teraz chcemy podpisać nasz pakiet aplikacji za pomocą JKS, który właśnie stworzyliśmy. Możliwe jest ręczne podpisywanie kodu naszego APK lub release build za każdym razem, ale w rzeczywistości, lepiej będzie skonfigurować go tak, aby po uruchomieniu flutter build apk --release
automatycznie podpisywał nasz pakiet z odpowiednim kluczem uploadu. Dokumentacja Fluttera mówi o tym, jak zaktualizować pliki Gradle w tym miejscu, ale my przejdziemy przez to powoli i wyjaśnimy to po drodze.
Aby zacząć, otwórzmy nasz plik flutter_app/android/app/build.gradle
. Na około linii 49 możemy zobaczyć to:
buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so flutter run --release works. signingConfig signingConfigs.debug }}
Główną rzeczą, która się tutaj dzieje jest to, że nasze kompilacje są podpisywane za pomocą debug
keystore, więc nasz release build nadal działa. Chcemy to zmienić tak, aby nasze wydania były podpisywane naszym własnym keystore. W ten sposób będą mogły zostać przesłane do sklepu Google Play.
Pierwszą rzeczą, jaką zrobimy, jest utworzenie key.properties
w naszym katalogu z aplikacjami. Tworzymy go w flutter_app/android/key.properties
.
key.properties
będzie zawierał wszystkie szczegóły, których potrzebujemy, aby pomyślnie podpisać nasz pakiet.
storePassword=The JKS store passwordkeyPassword=The key passwordkeyAlias=The alias for your keystoreFile=Where to look for your keystore file
Szybka uwaga na temat kontroli źródła
Powinieneś pomyśleć, zanim sprawdzisz ten kod w kontroli źródła. Jeśli źli aktorzy uzyskaliby dostęp do magazynu kluczy i tych danych uwierzytelniających, i mieliby kontrolę nad waszymi kontami, mogliby potencjalnie wypchnąć nową aktualizację do waszej aplikacji ze złośliwym oprogramowaniem lub innymi złymi rzeczami. Większość rozwiązań CI/CD pozwala na dostarczenie tych szczegółów jako „sekretów”, ale implementacja różni się w zależności od platformy.
KROK 3: Podsumowanie & Modyfikacja build.gradle
Utworzyliśmy plik keystore, i określiliśmy alias, jak również hasło do ochrony keystore. Jeśli używamy podpisywania aplikacji w Google Play (czego używasz domyślnie), to wygenerowany przez nas klucz będzie działał jako nasz klucz wysyłania. Pierwsza paczka, którą wgrywamy przez konsolę Google Play będzie podpisana tym kluczem. Jest to dowód dla Google, że jesteśmy tym, za kogo się podajemy.
Ma to sens? Fajnie, sprawmy, żeby podpisywał się jako część naszego procesu budowania Fluttera.
Modyfikuj build.gradle
Otwórz flutter_app/android/app/build.gradle
. W około linii 31 lub tak powinieneś zobaczyć tekst taki jak ten:
android { compileSdkVersion 29` lintOptions { disable 'InvalidPackage' }...
Chcemy powiedzieć Gradle, gdzie znaleźć sklep z kluczami. Zrobimy to, umieszczając te informacje w około linii 28, powyżej instrukcji android {
.
def keystoreProperties = new Properties()def keystorePropertiesFile = rootProject.file('key.properties')if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile))}
Zróbmy to, co powyżej…
Zdefiniujemy zmienną keystoreProperties
. Następnie sprawdzamy, czy key.properties
istnieje względem korzenia naszego projektu android (nie projektu Flutter).
Kiedy nasz build się uruchamia, ładuje key.properties
. key.properties
identyfikuje lokalizację magazynu kluczy, plus poświadczenia potrzebne do odblokowania Java Key Store w celu podpisania pakietu. Mając wszystkie wymagane szczegóły w ręku, Gradle podpisuje teraz pakiet aplikacji lub APK jako część naszej kompilacji wydania.
Po prostu podwójnie sprawdźmy, że wszystkie nasze pliki są we właściwym miejscu.
Nasz zmodyfikowany build.gradle
znajduje się w flutter_app/android/app/build.gradle
.
Nasz key.jks
plik jest w flutter_app/android/app/key.jks
.
Nasz key.properties
plik jest w flutter_app/android/key.properties
.
Gdy jesteśmy pewni powyższego, powinniśmy być w stanie uruchomić flutter build apk --release
teraz i podpisywanie powinno działać dobrze.
KROK 4: Wysyłanie go do Google Play Store
Teraz możemy przesłać nasz APK lub pakiet aplikacji do Sklepu Play. Kiedy zrobimy to z naszym podpisanym pakietem i z włączonym podpisywaniem Google Play (co jest domyślnie), Google potwierdzi klucz, którego użyliśmy do podpisania pakietu i zapamięta go jako nasz klucz wysyłania. Google następnie podpisze nasz APK lub pakiet aplikacji swoim własnym kluczem. Ważne jest, że wszelkie kolejne aktualizacje, które dostarczymy dla tej aplikacji, podpiszemy tym samym kluczem. Google Play rozpoznaje ten klucz jako nasz klucz przesyłania i nie możemy wydawać aktualizacji bez niego.
Nie rozumiem żadnego z powyższych i byłbym wdzięczny za niesamowicie wizualną ilustrację tego, co dokładnie się dzieje.
Można zrobić! To jest to, co się dzieje.
- Generujemy super tajny sposób identyfikacji siebie, prawie tak, jakbyśmy robili sobie paszport.
- Ponieważ każdy, kto ma ten „paszport”, będzie w stanie zidentyfikować się jako my (tj. podszyć się pod nas bez większego oporu), zamykamy go za hasłem w naszym sejfie (JKS, czyli Java Key Store).
- Tworzymy pakiet aplikacji lub APK, a następnie podpisujemy pakiet tym samym podpisem, którego użyliśmy na paszporcie. Aby uzyskać dostęp do tego paszportu, musimy odblokować sejf, w którym znajduje się paszport (podając hasło i alias do procesu budowania Gradle).
- Wysyłamy pakiet do dystrybutora (Google Play). Dystrybutor, widząc pakiet po raz pierwszy, zwraca uwagę na nasz podpis, którego użyliśmy na tym pakiecie i robi jego kopię.
- Kiedy wysyłamy pakiety do naszego dystrybutora (Google Play) w przyszłości, podpisujemy te pakiety tymi samymi danymi, których użyliśmy na początku. Nasz dystrybutor, pamiętając dane, których użyliśmy początkowo do przesłania pakietu, albo akceptuje, albo odrzuca pakiet. Jeśli się zgadza (jeśli klucz przesyłania jest taki sam jak ten, którego użyliśmy początkowo), wtedy pakiet jest akceptowany i dystrybuowany. W przeciwnym razie, nie jest akceptowany.
- Nasz dystrybutor, wiedząc, że początkowy pakiet i potencjalne przyszłe pakiety są na pewno od nas, rozprowadza pakiet.
Powodowanie, aby podpisywanie kodu działało z Codemagic
Chcemy ostatecznie podpisać to jako część naszego przepływu pracy CI/CD, ale jednocześnie nie chcemy sprawdzać naszego keystore i pliku właściwości do kontroli źródła. Zamiast tego chcemy, aby nasz dostawca CI/CD zbudował pakiet, a następnie podpisał go później w procesie budowania za pomocą keystore, który dostarczymy.
Ustawianie go z Git
Jeśli mamy zupełnie nową aplikację Flutter, możemy przełączyć się do folderu i wpisać git init
, aby rozpocząć korzystanie z kontroli źródła z aplikacją.
Domyślnie, będziemy po prostu szczęśliwie sprawdzać w naszym keystore i pliku właściwości keystore, co jest złym pomysłem z punktu widzenia bezpieczeństwa.
Powinieneś to mieć od samego początku
Jeśli przypadkowo sprawdzisz w swoim pliku właściwości keystore i keystore i popchniesz te zmiany, ludzie będą mogli wyrwać te pliki w dowolnym momencie w przyszłości, przeglądając historię Git. Możesz ręcznie usunąć pliki z Git w przyszłości, lub możesz ponownie zainicjować swoje repozytorium bez tych plików, ale lepiej po prostu nie sprawdzać ich w pierwszej kolejności.
Chcemy dodać te linie do końca naszego pliku .gitignore
:
# Don't check in the keystore files or equivalent*.jkskey*.properties
Żaden Java KeyStore (JKS) lub właściwości do podpisywania kodu nie zostanie sprawdzony w kontroli źródła. Jak pięknie.
Making build.gradle not sign when running on CI/CD
Podczas budowania projektu, keystore i ustawienia nie są dostępne. Chcemy, aby build nadal produkował kompilację wydania, nawet jeśli nie jest podpisany.
To jest część mojego build.gradle
, która na to pozwala:
signingConfigs { file(rootProject.file('key.properties')).with { propFile -> if (propFile.canRead()) { release { keyAlias keystoreProperties keyPassword keystoreProperties storeFile file(keystoreProperties) storePassword keystoreProperties } } else { print('not signed') } }}buildTypes { release { file(rootProject.file('key.properties')).with { propFile -> if (propFile.canRead()) { // because we can read the keystore // we are building locally // so sign locally // otherwise build an unsigned apk for later signing by the CI/CD provider signingConfig signingConfigs.release } } applicationVariants.all { variant -> variant.outputs.all { output -> output.outputFileName = "app-release.apk" } } // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. // signingConfig signingConfigs.release }}
Ustawianie Codemagic do podpisywania naszych buildów
W swoim procesie budowania, znajdź sekcję podpisywania kodu Android (jest w sekcji Publish). Wygląda to tak:
Teraz wgrywamy nasz keystore i ustawiamy hasło, alias klucza i hasło klucza (czyli to samo, co ustawiliśmy na początku w pliku keystore.properties).
Następnie klikamy „Zapisz”. Gdy Codmagic uruchomi nasz proces budowania, automatycznie wygeneruje dla nas podpisany APK lub App Bundle.
I to by było na tyle! Mając podpisany APK lub App Bundle, możemy wysłać naszą aplikację do Play Store.
Przykład można znaleźć w moim repo Git (oczywiście bez keystore i właściwości).
To wszystko.
Jeśli nadal jesteś zagubiony, daj mi znać na @azimuthapps, a ja postaram się pomóc. To może być frustrujące, aby uzyskać to prawo, ale kiedy już to zrobisz, to powinno działać w przewidywalnej przyszłości.
Lewis Cianci jest programistą w Brisbane, Australia. Jego pierwszy komputer miał napęd taśmowy. Zajmuje się tworzeniem oprogramowania od co najmniej dziesięciu lat i w tym czasie korzystał z wielu mobilnych frameworków (takich jak Ionic i Xamarin Forms). Jednak po przejściu na Fluttera, już nigdy nie wróci. Możesz go spotkać na jego blogu, poczytać o innych nieflutterowych rzeczach na Medium, a może wpadnie Ci w oko w Twojej najbliższej i najbardziej luksusowej kawiarni z nim i jego drogą żoną.
Więcej artykułów Lewisa: