Steg-för-steg-guide till kodsignering för Android och kodsignering med Codemagic

Koppla upp dig mot 3 000+ utvecklare av mobilappar på Slack Gå med i Codemagic Community

Ansamling av applikationer är en passion som delas av mjukvaruutvecklare världen över. Men den administrativa bördan av att hantera kodsignering är tråkig. Hur kan vi få det rätt första gången? Lewis Cianci undersöker saken.

Låt mig bara säga detta på förhand.

Kodsignering är så tråkigt att jag får ont i tänderna. Det är ett koncept som finns av en god anledning. Jag menar, du vill ju att folk ska vara säkra på att ditt mjukvarupaket verkligen kommer från dig, eller hur! Ändå är det något som så många utvecklare kämpar för att göra rätt på daglig basis. Det är som att göra sin skatt efter ett helt år av arbete och ha så många blanketter att fylla i. Yippee.

Kodsignering är som att göra sin skatt efter ett helt års arbete och ha så många blanketter att fylla i. Codemagic har en bra steg-för-steg-guide för att förenkla ditt liv
Klicka för att twittra

Rulla ner om du bara vill se steg-för-steg-guiden om kodsignering för Android och inte är intresserad av varför vi gör det här😉

Varför vi kodsignerar

Vi signerar våra paket så att folk som laddar ner vårt paket från Play Store faktiskt vet att det är vi. Vi gör detta genom att signera vårt paket med en nyckel som vi genererar. När vi laddar upp vårt signerade paket till Google Play kommer Google Play ihåg nyckeln som användes för att ladda upp det första paketet och ser till att efterföljande paket signeras med samma nyckel.

För att uppnå det här målet drar Android-paketsignering faktiskt nytta av ett verktyg som kommer från Java Development Framework och som heter keytool. Keytool har funnits förmodligen lika länge som JDK självt, så det är ganska gammalt. Det här ger förmodligen några av anledningarna till varför det är så förvirrande att signera en APK eller AAB (android app bundle) som det är.

Varför kan inte Play Store bara sköta kodsigneringen åt oss?

Vi skulle vara frestade att be om ett nirvana där vi bara skulle kunna ge alla våra osignerade app-bundlar till Play Store och låta dem lösa det hela och bara signera det åt oss. Logiken i detta bryter dock snabbt samman. Om du skrev en bok, skulle du låta någon annan signera den? Nej, du skulle signera den eftersom du är författaren.

Det är mycket lättare att signera kod numera än tidigare. Så länge vi alltid signerar våra paket med samma nyckel (”uppladdningsnyckeln”) kommer Google Play faktiskt att generera och hantera våra kodsigneringsnycklar åt oss.

Om du är särskilt företagsam kan du försöka läsa och förstå allting här, men jag har utvecklat för Android i nästan tre år nu och måste tyvärr konstatera att inte ens jag förstår det helt och hållet. Allt jag vet är att när det går sönder är det en enorm plåga att fixa.

Låt oss ta oss tid att förstå inte bara hur vi kodar tecken utan också varför vi kodar tecken. När vi förstår nödvändigheten av denna process kommer den att bli lättare att genomföra.

Vad behöver vi för kodsignering?

Den korta versionen finns här. För kodsignering behöver vi:

  • skapa filen för Java Development Kit (JDK);
  • signa vårt app-paket eller APK med vår privata nyckel;
  • modifiera build.gradle;
  • sända paketet till distributören (Google Play).

I slutet av den här artikeln hittar du också hur du får kodsignering att fungera med Codemagic.

Nu finns en lite längre version med en steg-för-steg-guide om vad vi behöver för kodsignering för Android och hur vi gör det.

Steg-för-steg-guide för kodsignering för Android

STEG 1: Java Development Kit (JDK)

Om du utvecklar för Android har du antagligen redan installerat dessa.

Vi måste skapa en JKS-fil (Java Key Store) som innehåller vår signeringsinformation. När vi genererar en JKS för vår app skapar vi faktiskt en privat nyckel på vår dator. Denna privata nyckel skyddas av ett lösenord som vi ställer in.

Från en kommandotolk kan vi skriva följande för att få en JKS.

keytool -genkey -v -keystore %DESKTOP%/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias DEVELOPERNAME

Vi säger till keytool att generera en Java Key Store och lägga den i vårt skrivbord. Den här nyckeln kommer att vara giltig i 10 000 dagar eller ungefär 27 år, vilket gör att vi kan skicka uppdateringar under hela appens livstid. Vi måste också ställa in ett alias. Jag gör bara detta till mitt utvecklarnamn eller något som jag kommer ihåg.

keytool kommer att be om olika delar av informationen längs vägen. Det är viktigt att ange dessa korrekt eftersom vi i huvudsak definierar detaljerna för vår privata nyckel.

Du kommer att uppmanas till:

  • Keystore password – du behöver detta för att låsa upp denna keystore igen i framtiden. Om du förlorar detta lösenord är det i stort sett omöjligt att återskapa det.
  • Inför lösenordet till keystore igen
  • Personlig information om vad som ska stå i det personliga certifikatet

Vi kommer att bli ombedda att fylla i några uppgifter om oss. Dessa uppgifter är de uppgifter som är kopplade till vår privata nyckel, så de bör vara någorlunda relevanta. Det är upp till dig vad du skriver i dessa fält, men som en tumregel skulle jag inte göra det alltför galet.

Detta är keytools utdata.

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?:

Var uppmärksam! Om du bara spammar Enter genom den här processen kommer skapandet bara att gå i loop om och om igen när du svarar ”nej” på den sista frågan.

I samband med detta har vi skapat en JKS och vi har lagt in vår egen genererade privata nyckel i den. Eftersom vi har genererat den och fastställt lösenordet kan vi vara säkra på att alla som har denna JKS-fil antingen är vi eller har särskilt tillstånd att använda den.

Om någon har din JKS och rätt autentiseringsuppgifter kan de signera paket som du eller ditt företag. Förvara den säkert, lägg den inte på källhanteringen.

Nu har vi vår Java Key Store, så vi har kommit halvvägs! Glädj dig följaktligen.

STEG 2: Signera vårt app-paket eller APK med vår privata nyckel

Nu vill vi signera vårt app-paket med den JKS som vi just gjort. Det är möjligt att manuellt kodsignera vår APK eller release build varje gång, men i verkligheten är det bättre att konfigurera det så att när vi kör flutter build apk --release så signerar det bara automatiskt vårt paket med rätt uppladdningsnyckel. Flutter-dokumentationen talar om hur man uppdaterar Gradle-filerna här, men vi kommer att gå igenom det långsamt och förklara det på vägen.

För att komma igång öppnar vi vår flutter_app/android/app/build.gradle-fil. På ungefär rad 49 kan vi se detta:

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 }}

Det viktigaste som händer här är att våra builds signeras med debug keystore, så vår release build fungerar fortfarande. Vi vill ändra detta så att våra utgåvor signeras med vår egen keystore. På så sätt kan de laddas upp till Google Play store.

Det första vi gör är att skapa en key.properties i vår app-katalog. Vi skapar denna i flutter_app/android/key.properties.

key.properties kommer att innehålla alla uppgifter vi behöver för att framgångsrikt signera vårt paket.

storePassword=The JKS store passwordkeyPassword=The key passwordkeyAlias=The alias for your keystoreFile=Where to look for your keystore file

En snabb notering om källkontroll

Du bör tänka dig för innan du checkar in den här koden i källkontrollen. Om dåliga aktörer skulle få tillgång till keystore och dessa autentiseringsuppgifter, och de hade kontroll över dina konton, skulle de potentiellt kunna trycka en ny uppdatering till din app med skadlig kod eller andra dåliga saker. De flesta CI/CD-lösningar låter dig tillhandahålla dessa uppgifter som ”secrets”, men implementeringen skiljer sig åt per plattform.

STEG 3: Sammanfattning & Ändra build.gradle

Vi har gjort en keystore-fil och angett ett alias samt ett lösenord för att skydda de keystore. Om vi använder Google Play app-signering (vilket du använder som standard) fungerar nyckeln som vi har genererat som vår uppladdningsnyckel. Det första paketet som vi laddar upp via Google Play-konsolen kommer att signeras med den här nyckeln. Detta bevisar för Google att vi är de vi utger oss för att vara.

Säger du något vettigt? Coolt, låt oss få den att signera som en del av vår Flutter-byggprocess.

Modifiera build.gradle

Öppna upp flutter_app/android/app/build.gradle. På ungefär rad 31 eller så bör du se text som denna:

android { compileSdkVersion 29` lintOptions { disable 'InvalidPackage' }...

Vi vill tala om för Gradle var han ska hitta nyckelförrådet. Det gör vi genom att sätta dessa detaljer på ungefär rad 28, ovanför android {-anvisningen.

def keystoreProperties = new Properties()def keystorePropertiesFile = rootProject.file('key.properties')if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile))}

Låt oss bryta ner ovanstående…

Vi definierar en keystoreProperties-variabel. Sedan kontrollerar vi om key.properties finns relativt till roten av vårt androidprojekt (inte Flutterprojektet).

När vårt bygge körs laddas key.properties. key.properties identifierar platsen för keystore, plus de autentiseringsuppgifter som behövs för att låsa upp Java Key Store för att signera paketet. Med alla nödvändiga uppgifter i handen signerar Gradle nu app-paketet eller APK:n som en del av vårt release-bygge.

Vi ska bara dubbelkolla att alla våra filer finns på rätt plats.

Vår androidprojektlayout
Vår androidprojektlayout

Vår modifierade build.gradle finns i flutter_app/android/app/build.gradle.

Vår key.jks-fil finns i flutter_app/android/app/key.jks.

Vår key.properties-fil finns i flutter_app/android/key.properties.

När vi är säkra på ovanstående bör vi kunna köra flutter build apk --release nu och signeringen bör fungera bra.

STAP 4: Skicka den till Google Play Store

Nu kan vi ladda upp vår APK eller vårt apppaket till Play Store. När vi gör detta med vårt signerade paket och med Google Play Signing på (vilket det är som standard) kommer Google att bekräfta den nyckel som vi har använt för att signera paketet och komma ihåg den som vår uppladdningsnyckel. Google kommer sedan att signera vår APK eller vårt apppaket med sin egen nyckel. Det är viktigt att alla efterföljande uppdateringar som vi tillhandahåller för den här appen signerar vi med samma nyckel. Google Play känner igen den här nyckeln som vår uppladdningsnyckel och vi kan inte släppa uppdateringar utan den.

Jag förstår inget av ovanstående och skulle uppskatta en otroligt visuell illustration av vad exakt som händer.

Kan jag göra! Detta är vad som händer.

  1. Vi skapar ett superhemligt sätt att identifiera oss själva, nästan som om vi gör ett pass åt oss själva.
  2. Då vem som helst med detta ”pass” kommer att kunna identifiera sig som oss (dvs. utge sig för att vara oss utan större motstånd), låser vi det bakom ett lösenord i vårt kassaskåp (JKS, eller Java Key Store).
  3. Vi skapar app-paketet eller APK, och signerar paketet med samma signatur som vi använde på passet. För att få tillgång till detta pass måste vi låsa upp det kassaskåp som passet finns i (genom att ge lösenordet och aliaset till Gradle-byggprocessen).
  4. Vi skickar paketet till distributören (Google Play). Distributören, som ser paketet för första gången, noterar vår signatur som vi använde på paketet och tar en kopia av den.
  5. När vi skickar paket till vår distributör (Google Play) i framtiden signerar vi dessa paket med samma uppgifter som vi använde inledningsvis. Vår distributör, som kommer ihåg de uppgifter som vi använde ursprungligen för att ladda upp paketet, accepterar eller avvisar paketet. Om det stämmer (om uppladdningsnyckeln är densamma som den vi använde ursprungligen) accepteras paketet och distribueras. Annars accepteras den inte.
  6. Vår distributör, som vet att det första paketet och eventuella framtida paket definitivt kommer från oss, distribuerar paketet.

För att få kodsignering att fungera med Codemagic

Vi vill i slutändan signera detta som en del av vårt CI/CD-arbetsflöde, men samtidigt vill vi inte checka in vår keystore- och egenskapsfil i källhanteringen. Istället vill vi att vår CI/CD-leverantör ska bygga paketet och sedan signera det senare i byggprocessen med en keystore som vi tillhandahåller.

Sätta upp det med Git

Om vi har en helt ny Flutter-app kan vi växla till mappen och skriva in git init för att börja använda källkontroll med appen.

Som standard checkar vi bara glatt in vår keystore- och keystore properties-fil, vilket är en dålig idé ur ett säkerhetsperspektiv.

Du bör få det här rätt från början

Om du råkar checka in dina keystore properties- och keystore-filer och pushar dessa ändringar, kommer folk att kunna plocka fram dessa filer när som helst i framtiden genom att titta i din Git-historik. Du kan manuellt ta bort filer från Git i framtiden, eller så kan du återinitialisera ditt arkiv utan dessa filer, men det är bättre att bara låta bli att checka in dem från början.

Vi vill lägga till dessa rader i slutet av vår .gitignore-fil:

# Don't check in the keystore files or equivalent*.jkskey*.properties

Ingen Java KeyStore (JKS) eller egenskaper för kodsignering kommer att checkas in i källhanteringen. Hur härligt.

För att build.gradle inte ska signera när den körs på CI/CD

När ditt projekt byggs är keystore och inställningar inte tillgängliga. Vi vill att byggnaden fortfarande ska producera en release-build även om den inte är signerad.

Detta är den del av min build.gradle som möjliggör detta:

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 }}

Inställning av Codemagic för att signera våra builds

I din byggprocess hittar du avsnittet för signering av Android-kod (det finns i avsnittet Publish). Det ser ut så här:Android code signning

Nu laddar vi upp vår keystore och ställer in vårt lösenord, nyckelalias och nyckellösenord (som är desamma som vi ställde in initialt i vår fil keystore.properties).

Uppfyllda detaljer
Uppfyllda detaljer

Sedan trycker vi på ”Save”. När Codmagic kör vår byggprocess kommer den automatiskt att producera en signerad APK eller App Bundle åt oss.

Och det är i stort sett allt! Med denna signerade APK eller App Bundle kan du distribuera din app till Play Store.

Du kan kolla in min Git-repo för ett exempel här (givetvis utan keystore eller egenskaper).

Det var allt.

Om du fortfarande är vilse, hör gärna av dig till mig på @azimuthapps så ska jag försöka hjälpa dig. Det kan vara frustrerande att få det rätt, men när du väl gör det bör det fungera under överskådlig tid.

Lewis Cianci är mjukvaruutvecklare i Brisbane, Australien. Hans första dator hade en bandspelare. Han har utvecklat programvara i minst tio år och har använt en hel del ramverk för mobilutveckling (som Ionic och Xamarin Forms) under sin tid. Efter att ha konverterat till Flutter kommer han dock aldrig att gå tillbaka. Du kan nå honom på hans blogg, läsa om andra saker som inte har med Flutter att göra på Medium, eller kanske få en glimt av honom på ditt närmaste och finaste kafé tillsammans med honom och hans kära fru.

Mera artiklar av Lewis:

Lämna ett svar

Din e-postadress kommer inte publiceras.