Az alkalmazások építése a szoftverfejlesztők közös szenvedélye világszerte. De a kódaláírás kezelésének adminisztratív terhei unalmasak. Hogyan lehet elsőre jól csinálni? Lewis Cianci ennek jár utána.
Hadd mondjam el előre:
A kódaláírás annyira unalmas, hogy megfájdul a fogam. Ez egy olyan fogalom, ami jó okkal létezik. Úgy értem, azt akarod, hogy az emberek biztosak legyenek abban, hogy a szoftvercsomagod valóban tőled származik, igaz?! És mégis, ez olyasvalami, amivel sok fejlesztő küzd, hogy napi szinten jól csinálja. Olyan ez, mintha egy egész éves munka után adót kellene írni, és rengeteg kitöltendő űrlapot kellene kitölteni. Yippee.
Görgessen lejjebb, ha csak az Android kódaláírásra vonatkozó lépésről-lépésre útmutatót szeretné látni, és nem érdekli, hogy miért csináljuk ezt😉
Miért kódolunk
A csomagjainkat azért írjuk alá, hogy az emberek, akik letöltik a csomagunkat a Play Store-ból, valóban tudják, hogy mi vagyunk. Ezt úgy tesszük, hogy a csomagunkat egy általunk generált kulccsal írjuk alá. Amikor feltöltjük az aláírt csomagunkat a Google Play-be, a rendszer megjegyzi az eredeti csomag feltöltéséhez használt kulcsot, és gondoskodik arról, hogy a későbbi csomagok ugyanazzal a kulccsal legyenek aláírva.
Az Android csomagok aláírása ennek a célnak az eléréséhez valójában a Java Development Frameworkből származó keytool nevű eszközt használja ki. A keytool valószínűleg olyan régóta létezik, mint maga a JDK, tehát elég régi. Ez adódik valószínűleg néhány okból, amiért egy APK vagy AAB (androidos alkalmazáscsomag) aláírása olyan zavaros, amilyen zavaros.
Miért nem tudja a Play Store egyszerűen kezelni helyettünk a kód aláírását?
Kísértésbe esnénk, hogy egy olyan nirvánát kérjünk, ahol egyszerűen odaadhatjuk az összes alá nem írt alkalmazáscsomagunkat a Play Store-nak, hogy ők megoldják és aláírják helyettünk. Ennek a logikája azonban gyorsan összeomlik. Ha írnál egy könyvet, megkérnél valakit, hogy írja alá? Nem. Aláírnád, mert te vagy a szerző.
Manapság a kódok aláírása sokkal egyszerűbb, mint régen. Amíg mindig ugyanazzal a kulccsal (a “feltöltőkulccsal”) írjuk alá a csomagjainkat, addig a Google Play tulajdonképpen generálja és kezeli helyettünk a kódaláíró kulcsokat.
Ha különösen vállalkozó kedvű vagy, akkor megpróbálhatsz mindent elolvasni és megérteni itt, de én már jó három éve fejlesztek Androidra, és sajnos azt kell mondanom, hogy még én sem értem teljesen. Csak annyit tudok, hogy amikor elromlik, akkor hatalmas fájdalmat okoz a javítás.
Foglaljunk időt arra, hogy ne csak azt értsük meg, hogyan kódoljuk a jelet, hanem azt is, hogy miért kódoljuk a jelet. Ha megértjük ennek a folyamatnak a szükségességét, akkor könnyebb lesz elvégezni.
Mire van szükségünk a kódaláíráshoz?
A rövid változat itt van. A kódaláíráshoz szükségünk van:
- a Java Development Kit (JDK) fájl létrehozására;
- az alkalmazáscsomagunk vagy APK-nk aláírására a privát kulcsunkkal;
- a build.gradle módosítása;
- a csomag elküldése a forgalmazónak (Google Play).
A cikk végén azt is megtaláljuk, hogyan lehet a Codemagic segítségével a kódaláírást működésre bírni.
Most egy kicsit hosszabb változatban lépésről-lépésre leírjuk, hogy mire és hogyan van szükségünk az Android kódaláíráshoz.
Step-by-step guide for Android code signing
STEP 1: A Java Development Kit (JDK)
Ha Androidra fejlesztesz, valószínűleg már telepítetted ezeket.
El kell hoznunk egy Java Key Store (JKS) fájlt, amely tartalmazza az aláírási információinkat. A JKS létrehozásával az alkalmazásunkhoz tulajdonképpen egy privát kulcsot hozunk létre a számítógépünkön. Ezt a privát kulcsot egy általunk beállított jelszó védi.
A parancssorból a következőket írhatjuk be a JKS létrehozásához.
keytool -genkey -v -keystore %DESKTOP%/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias DEVELOPERNAME
Megmondjuk a keytool
-nak, hogy hozzon létre egy Java Key Store-t, és tegye az asztalunkra. Ez a kulcs 10 000 napig vagy nagyjából 27 évig lesz érvényes, lehetővé téve számunkra, hogy frissítéseket toljunk az alkalmazásunk élettartama alatt. Szükségünk van egy alias beállítására is. Én ezt egyszerűen a fejlesztői nevemre teszem, vagy valamire, amire emlékezni fogok.
keytool
különböző információkat fog kérni az út során. Fontos, hogy ezeket helyesen adjuk meg, mivel lényegében a privát kulcsunk részleteit határozzuk meg.
Az alábbiakat kéri:
- Keystore jelszó – ez kell ahhoz, hogy a jövőben újra feloldhassuk ezt a keystore-t. Ha elveszíti ezt a jelszót, akkor nagyjából lehetetlen visszaszerezni.
- Keystore jelszó újbóli megadása
- Személyes adatok arról, hogy mit tegyünk a személyes tanúsítványba
Elkérést kapunk, hogy töltsünk ki néhány adatot magunkról. Ezek azok az adatok, amelyek a privát kulcsunkhoz kapcsolódnak, tehát valamennyire relevánsnak kell lenniük. Rajtunk múlik, hogy mit írunk ezekbe a mezőkbe, de ökölszabályként én nem tenném túl őrültté.
Ezkeytool
kimenete.
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?:
Figyelem! Ha csak végigspammeled az Entert ezen a folyamaton, akkor a létrehozás újra és újra loopolni fog, mivel az utolsó kérdésre nemmel válaszolsz.
Ezzel létrehoztunk egy JKS-t, és beletöltöttük a saját generált privát kulcsunkat. Mivel mi generáltuk és mi állítottuk be a jelszót, biztosak lehetünk benne, hogy bárki, aki rendelkezik ezzel a JKS-fájllal, vagy mi vagyunk, vagy kifejezetten jogosult használni azt.
Ha valaki rendelkezik az Ön JKS-ével és a megfelelő hitelesítő adatokkal, akkor Önként vagy az Ön cégeként aláírhatja a csomagokat. Tartsuk biztonságban, ne tegyük fel a forráskontrolba.
Most megvan a Java Key Store, tehát félúton vagyunk! Ennek megfelelően örüljünk.
2. LÉPÉS: Alkalmazáscsomagunk vagy APK-nk aláírása a privát kulcsunkkal
Most, szeretnénk aláírni az alkalmazáscsomagunkat azzal a JKS-el, amit az imént készítettünk. Lehetséges, hogy minden egyes alkalommal manuálisan aláírjuk kóddal az APK-nkat vagy a kiadási buildünket, de a valóságban jobban járunk, ha úgy konfiguráljuk, hogy amikor a flutter build apk --release
futtatjuk, akkor automatikusan aláírja a csomagunkat a megfelelő feltöltési kulccsal. A Flutter dokumentáció itt beszél arról, hogyan frissítsük a Gradle fájlokat, de mi lassan végigmegyünk rajta, és útközben elmagyarázzuk.
Az induláshoz nyissuk meg a flutter_app/android/app/build.gradle
fájlunkat. Körülbelül a 49. sorban ezt láthatjuk:
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 }}
A legfontosabb dolog, ami itt történik, hogy a buildjeinket a debug
keystore-ral írják alá, így a release buildünk továbbra is működik. Ezt szeretnénk megváltoztatni, hogy a kiadásaink a saját keystore-unkkal legyenek aláírva. Így fel lehet őket tölteni a Google Play áruházba.
Az első dolog, amit csinálunk, hogy létrehozunk egy key.properties
-t az alkalmazáskönyvtárunkban. Ezt a flutter_app/android/key.properties
-ben hozzuk létre.
key.properties
tartalmazni fog minden adatot, amire szükségünk van a csomagunk sikeres aláírásához.
storePassword=The JKS store passwordkeyPassword=The key passwordkeyAlias=The alias for your keystoreFile=Where to look for your keystore file
Egy gyors megjegyzés a forráskezelésről
Meg kell gondolnunk, mielőtt ezt a kódot bejelöljük a forráskezelésbe. Ha a rossz szereplők hozzáférnének a keystore-hoz és ezekhez a hitelesítő adatokhoz, és ellenőrzésük lenne a fiókjaid felett, akkor potenciálisan egy új frissítést tolhatnának az alkalmazásodhoz rosszindulatú programokkal vagy más rossz dolgokkal. A legtöbb CI/CD megoldás lehetővé teszi, hogy ezeket az adatokat “titokként” megadjuk, de a megvalósítás platformonként eltérő.
3. LÉPÉS: Összegzés & A build.gradle módosítása
Elkészítettünk egy keystore fájlt, és megadtunk egy aliast, valamint egy jelszót a keystore védelmére. Ha a Google Play alkalmazás-aláírást használjuk (amit alapértelmezés szerint használunk), akkor az általunk generált kulcs működik a feltöltési kulcsunkként. Az első csomag, amelyet a Google Play konzolon keresztül feltöltünk, ezzel a kulccsal lesz aláírva. Ez bizonyítja a Google számára, hogy azok vagyunk, akiknek mondjuk magunkat.
Van értelme? Király, tegyük az aláírást a Flutter építési folyamatunk részévé.
Módosítsuk a build.gradle
Nyissuk meg a flutter_app/android/app/build.gradle
. Körülbelül a 31. sorban kell látnunk egy ilyen szöveget:
android { compileSdkVersion 29` lintOptions { disable 'InvalidPackage' }...
Meg akarjuk mondani a Gradle-nek, hogy hol találja a kulcstárolót. Ezt úgy tesszük meg, hogy körülbelül a 28. sorba, a android {
utasítás fölé írjuk ezeket az adatokat.
def keystoreProperties = new Properties()def keystorePropertiesFile = rootProject.file('key.properties')if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile))}
Bontjuk le a fentieket…
Meghatározunk egy keystoreProperties
változót. Ezután ellenőrizzük, hogy a key.properties
létezik-e az android projektünk (nem a Flutter projekt) gyökeréhez viszonyítva.
Mikor a buildünk fut, betölti a key.properties
-t. A key.properties
azonosítja a keystore helyét, valamint a csomag aláírásához szükséges hitelesítő adatokat a Java Key Store feloldásához. Az összes szükséges adat birtokában a Gradle most aláírja az alkalmazáscsomagot vagy APK-t a kiadási buildünk részeként.
Még egyszer ellenőrizzük, hogy minden fájlunk a megfelelő helyen van-e.
A módosított build.gradle
a flutter_app/android/app/build.gradle
-ben van.
A mi key.jks
fájlunk a flutter_app/android/app/key.jks
.
A mi key.properties
fájlunk a flutter_app/android/key.properties
.
Ha már biztosak vagyunk a fentiekben, akkor most már futtathatjuk a flutter build apk --release
-et, és az aláírásnak jól kell működnie.
4. LÉPÉS: Elküldés a Google Play Áruházba
Most már feltölthetjük az APK vagy alkalmazáscsomagunkat a Play Áruházba. Ha ezt az aláírt csomagunkkal tesszük, és a Google Play Aláírása be van kapcsolva (ami alapértelmezés szerint be van kapcsolva), a Google vissza fogja ismerni a kulcsot, amit a csomag aláírásához használtunk, és megjegyzi azt, mint a feltöltési kulcsunkat. A Google ezután a saját kulcsával fogja aláírni az APK-unkat vagy alkalmazáscsomagunkat. Fontos, hogy minden későbbi frissítést, amit ehhez az alkalmazáshoz biztosítunk, ugyanezzel a kulccsal írjuk alá. A Google Play ezt a kulcsot ismeri fel a feltöltési kulcsunkként, és e nélkül nem tudunk frissítéseket kiadni.
Nem értem a fentiekből semmit, és örülnék egy hihetetlenül szemléletes illusztrációnak, hogy pontosan mi is történik.
Megoldható! Ez történik.
- Generálunk egy szuper titkos módot arra, hogy azonosítsuk magunkat, majdnem olyan, mintha útlevelet készítenénk magunknak.
- Mert mivel bárki, aki rendelkezik ezzel az “útlevéllel”, képes lesz pozitívan azonosítani magát, mint mi (azaz: megszemélyesíthet minket különösebb ellenállás nélkül), elzárjuk egy jelszó mögé a széfünkben (a JKS, azaz a Java Key Store).
- Elkészítjük az alkalmazáscsomagot vagy APK-t, majd aláírjuk a csomagot ugyanazzal az aláírással, amit az útlevélen használtunk. Ahhoz, hogy hozzáférjünk ehhez az útlevélhez, fel kell oldanunk a széfet, amelyben az útlevél van (a jelszó és az alias megadásával a Gradle építési folyamatnak).
- Elküldjük a csomagot a forgalmazónak (Google Play). A forgalmazó, amikor először látja a csomagot, tudomásul veszi az aláírásunkat, amelyet ezen a csomagon használtunk, és készít róla egy másolatot.
- Amikor a jövőben csomagokat küldünk a forgalmazónak (Google Play), ezeket a csomagokat ugyanazokkal az adatokkal írjuk alá, amelyeket eredetileg használtunk. A forgalmazónk, mivel emlékszik azokra az adatokra, amelyeket eredetileg a csomag feltöltéséhez használtunk, vagy elfogadja, vagy elutasítja a csomagot. Ha egyezik (ha a feltöltési kulcs megegyezik azzal, amit eredetileg használtunk), akkor a csomagot elfogadja és terjeszti. Ellenkező esetben nem fogadja el.
- A forgalmazónk, tudván, hogy az eredeti csomag és a lehetséges jövőbeli csomagok biztosan tőlünk származnak, szétosztja a csomagot.
Kódaláírás működőképessé tétele a Codemagic segítségével
Végső soron a CI/CD munkafolyamat részeként szeretnénk aláírni, ugyanakkor nem szeretnénk a kulcstárunkat és a properties fájlunkat a forráskezelésbe bejelölni. Ehelyett azt akarjuk, hogy a CI/CD szolgáltatónk készítse el a csomagot, majd később, az építési folyamat során írja alá az általunk megadott keystore-ral.
Elhelyezés Git-tel
Ha teljesen új Flutter alkalmazásunk van, akkor átkapcsolhatunk a mappába és beírhatjuk a git init
, hogy elkezdjük használni a forrásvezérlést az alkalmazással.
Az alapértelmezés szerint csak boldogan bejelentkezünk a keystore és keystore properties fájlunkba, ami biztonsági szempontból rossz ötlet.
Ezt már a kezdetektől fogva meg kell tenned
Ha véletlenül bejelentkezel a keystore properties és keystore fájlodba, és ezeket a változtatásokat betolod, akkor az emberek a jövőben bármikor ki tudják majd tépni ezeket a fájlokat, ha átnézik a Git előzményeidet. A jövőben manuálisan eltávolíthatod a fájlokat a Gitből, vagy újraindíthatod a tárolódat ezen fájlok nélkül, de jobb, ha eleve nem csekkolod be őket.
Az alábbi sorokat szeretnénk hozzáadni a .gitignore
fájlunk végéhez:
# Don't check in the keystore files or equivalent*.jkskey*.properties
Nem lesz Java KeyStore (JKS) vagy a kód aláírásához szükséges tulajdonságok bejelentkezve a forráskezelésbe. Milyen szép.
A build.gradle nem írja alá, ha CI/CD-n fut
Míg a projektünk épül, a keystore és a beállítások nem állnak rendelkezésre. Azt akarjuk, hogy a build akkor is kiadási buildet hozzon létre, ha nincs aláírva.
Ez az én build.gradle
részem, ami ezt lehetővé teszi:
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 }}
A Codemagic beállítása a buildjeink aláírására
A build folyamatodban keresd meg az Android code signing részt (a Publish szakaszban van). Így néz ki:
Most feltöltjük a keystore-unkat, és beállítjuk a jelszavunkat, a kulcs aliasát és a kulcs jelszavát (amelyek megegyeznek azzal, amit eredetileg a keystore.properties fájlban állítottunk be).
Ezután nyomjuk meg a “Save” gombot. Amikor a Codmagic lefuttatja a build folyamatunkat, automatikusan létrehoz számunkra egy aláírt APK-t vagy App Bundle-t.
És nagyjából ennyi! Ezzel az aláírt APK-val vagy App Bundle-lel telepíthetjük az alkalmazásunkat a Play Store-ba.
Egy példát itt találsz a Git repómban (természetesen a keystore és a tulajdonságok nélkül).
Ez minden.
Ha még mindig nem érted, nyugodtan szólj nekem a @azimuthapps címen, és megpróbálok segíteni. Frusztráló lehet, amíg sikerül, de ha egyszer sikerül, akkor belátható időn belül működnie kell.
Lewis Cianci szoftverfejlesztő az ausztráliai Brisbane-ben. Az első számítógépében szalagos meghajtó volt. Legalább tíz éve fejleszt szoftvereket, és elég sok mobilfejlesztési keretrendszert (például Ionic és Xamarin Forms) használt már ez idő alatt. Miután azonban áttért a Flutterre, soha többé nem tér vissza. Elérheted őt a blogján, olvashatsz más, nem flutteres dolgokról a Mediumon, vagy talán megpillanthatod őt a legközelebbi és legmenőbb kávézóban vele és kedves feleségével.
Még több cikk Lewis-tól: