Strin-for-trin-guide til Android-kodesignering og kodesignering med Codemagic

Før sammen med 3.000+ udviklere af mobilapps på Slack Deltag i Codemagic-fællesskabet

Bygning af applikationer er en passion, som deles af softwareudviklere over hele verden. Men det administrative overhead ved at administrere kodesignering er trist. Hvordan kan vi få det rigtigt første gang? Lewis Cianci ser nærmere på det.

Lad mig lige sige dette på forhånd.

Kodeunderskrift er så kedeligt, at det giver mig ondt i tænderne. Det er et koncept, der eksisterer med en god grund. Jeg mener, du vil jo gerne have folk til at være sikre på, at din softwarepakke rent faktisk er fra dig, ikke sandt?! Og alligevel er det noget, som så mange udviklere dagligt kæmper for at få styr på. Det er som at lave sin skat efter et helt års arbejde og have så mange formularer, der skal udfyldes. Yippee.

Kodeunderskrivelse er som at lave sin skat efter et helt års arbejde og have så mange formularer at udfylde. Codemagic har en fantastisk trin-for-trin-guide til at forenkle dit liv
Klik for at tweete

Rul ned, hvis du bare vil se trin-for-trin-guiden om kodesignering af Android og ikke er interesseret i, hvorfor vi gør det😉

Hvorfor vi kodesignerer

Vi signerer vores pakker, så folk, der downloader vores pakke fra Play Store, faktisk ved, at det er os. Det gør vi ved at signere vores pakke med en nøgle, som vi genererer. Når vi uploader vores signerede pakke til Google Play, husker Google Play den nøgle, der blev brugt til at uploade den første pakke, og sørger for, at efterfølgende pakker signeres med den samme nøgle.

For at nå dette mål udnytter Android-pakkesignering faktisk et værktøj, der kommer fra Java Development Framework og hedder keytool. Keytool har eksisteret i formentlig lige så lang tid som selve JDK’et, så det er ret gammelt. Det giver nok nogle af grundene til, at signering af en APK eller AAB (android app bundle) er så forvirrende, som det er.

Hvorfor kan Play Store ikke bare håndtere kodesignering for os?

Vi ville være fristet til at bede om et nirvana, hvor vi bare kunne give alle vores usignerede app-bundles til Play Store og bare få dem til at ordne det og bare signere det for os. Logikken i det bryder dog hurtigt sammen. Hvis du skrev en bog, ville du så få en anden til at signere den? Nej. Du ville underskrive den, fordi du er forfatteren.

Der er i dag meget nemmere at underskrive kode, end det var førhen. Så længe vi altid signerer vores pakker med den samme nøgle (uploadnøglen), vil Google Play faktisk generere og administrere vores nøgler til kodesignering for os.

Hvis du er særligt initiativrig, kan du forsøge at læse og forstå alt her, men jeg har udviklet til Android i det meste af tre år nu, og jeg må desværre sige, at selv jeg ikke forstår det helt. Det eneste jeg ved er, at når det går i stykker, er det en enorm smerte at reparere.

Lad os tage os tid til at forstå ikke kun hvordan vi koder tegn, men også hvorfor vi koder tegn. Når vi forstår nødvendigheden af denne proces, vil det gøre den lettere at gennemføre.

Hvad har vi brug for til kodesignering?

Den korte version er her. Til kodesignering skal vi:

  • skabe Java Development Kit (JDK)-filen;
  • underskrive vores app-pakke eller APK med vores private nøgle;
  • modificere build.gradle;
  • sende pakke til distributøren (Google Play).

I slutningen af denne artikel finder du også, hvordan du får kodesignering til at fungere med Codemagic.

Nu en lidt længere version med en trin-for-trin-guide om, hvad vi skal bruge til Android-kodesignering, og hvordan vi gør det.

Strin-for-trin-guide til Android-kodesignering

Trin 1: Java Development Kit (JDK)

Hvis du udvikler til Android, har du sikkert allerede disse installeret.

Vi skal oprette en Java Key Store-fil (JKS), der indeholder vores signeringsoplysninger. Når vi genererer en JKS til vores app, opretter vi faktisk en privat nøgle på vores computer. Denne private nøgle er beskyttet af en adgangskode, som vi indstiller.

Fra en kommandoprompt kan vi skrive følgende for at få en JKS.

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

Vi beder keytool om at generere en Java Key Store og lægge den på vores skrivebord. Denne nøgle vil være gyldig i 10.000 dage eller ca. 27 år, hvilket giver os mulighed for at skubbe opdateringer i hele vores app’s levetid. Vi er også nødt til at indstille et alias. Jeg gør det bare til mit udviklernavn eller noget, jeg vil huske.

keytool vil bede om forskellige oplysninger undervejs. Det er vigtigt at angive disse korrekt, da vi i det væsentlige definerer detaljerne for vores private nøgle.

Du vil blive bedt om:

  • Keystore password – du skal bruge dette for at låse op for denne keystore igen i fremtiden. Hvis du mister denne adgangskode, er det stort set umuligt at gendanne den.
  • Indtast keystore-adgangskode igen
  • Personlige oplysninger om, hvad der skal stå i det personlige certifikat

Vi vil blive bedt om at udfylde nogle oplysninger om os. Disse oplysninger er de oplysninger, der er knyttet til vores private nøgle, så de bør være nogenlunde relevante. Det er op til dig, hvad du skriver i disse felter, men som tommelfingerregel ville jeg ikke gøre det alt for vildt.

Dette er keytools output.

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

Påpasselig! Hvis du bare spammer Enter gennem denne proces, vil oprettelsen bare sløjfe igen og igen, mens du svarer “nej” til det sidste spørgsmål.

Derved har vi oprettet en JKS, og vi har lagt vores egen genererede private nøgle ind i den. Fordi vi har genereret den, og vi har indstillet adgangskoden, kan vi være sikre på, at alle, der har denne JKS-fil, enten er os eller har specifik tilladelse til at bruge den.

Hvis nogen har din JKS og de korrekte legitimationsoplysninger, kan de underskrive pakker som dig eller din virksomhed. Opbevar den sikkert, læg den ikke på kildekontrol.

Nu har vi vores Java Key Store, så vi er halvvejs igennem! Glæd dig i overensstemmelse hermed.

STEG 2: Signering af vores app-pakke eller APK med vores private nøgle

Nu vil vi signere vores app-pakke med den JKS, som vi lige har lavet. Det er muligt at kodeunderskrive vores APK eller release build manuelt hver eneste gang, men i virkeligheden vil det være bedre at konfigurere det, så når vi kører flutter build apk --release, underskriver den bare automatisk vores pakke med den rigtige uploadnøgle. Flutter-dokumentationen taler om, hvordan du opdaterer Gradle-filerne her, men vi vil gennemgå det langsomt og forklare det undervejs.

For at komme i gang, skal vi åbne vores flutter_app/android/app/build.gradle-fil. På omkring linje 49 kan vi se dette:

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 vigtigste, der sker her, er, at vores builds bliver signeret med debug keystore, så vores release build fungerer stadig. Vi ønsker at ændre dette, så vores udgivelser er signeret med vores egen keystore. På den måde kan de uploades til Google Play-butikken.

Den første ting vi gør er at oprette en key.properties i vores app-mappe. Vi opretter denne i flutter_app/android/key.properties.

key.properties vil indeholde alle de oplysninger, vi har brug for for at signere vores pakke med succes.

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

En hurtig note om kildekontrol

Du bør tænke dig om, før du tjekker denne kode ind i kildekontrollen. Hvis dårlige aktører fik adgang til keystore og disse legitimationsoplysninger, og de havde kontrol over dine konti, kunne de potentielt skubbe en ny opdatering til din app med malware eller andre dårlige ting. De fleste CI/CD-løsninger lader dig angive disse oplysninger som “secrets”, men implementeringen varierer fra platform til platform.

STEG 3: Opsummering & Ændring af build.gradle

Vi har lavet en keystore-fil og angivet et alias samt en adgangskode for at beskytte de keystore. Hvis vi bruger Google Play app-signering (som du bruger som standard), fungerer den nøgle, vi har genereret, som vores upload-nøgle. Den første pakke, som vi uploader via Google Play-konsollen, vil blive signeret med denne nøgle. Dette beviser over for Google, at vi er dem, vi siger, vi er.

Giver det mening? Cool, lad os få den til at underskrive som en del af vores Flutter-byggeproces.

Modificer build.gradle

Opnå flutter_app/android/app/build.gradle. På omkring linje 31 eller deromkring bør du se tekst som denne:

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

Vi ønsker at fortælle Gradle, hvor nøgleoplaget skal findes. Det gør vi ved at sætte disse oplysninger på omkring linje 28, over android {-erklæringen.

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

Lad os bryde ovenstående ned…

Vi definerer en keystoreProperties-variabel. Derefter kontrollerer vi, om key.properties findes relativt til roden af vores android-projekt (ikke Flutter-projektet).

Når vores build køres, indlæser den key.properties. key.properties identificerer placeringen af keystore, plus de nødvendige legitimationsoplysninger til at låse Java Key Store op for at signere pakken. Med alle de nødvendige oplysninger i hånden underskriver Gradle nu app-pakken eller APK’en som en del af vores release-build.

Lad os lige dobbelttjekke, at alle vores filer er på det rigtige sted.

Vores android-projektlayout
Vores android-projektlayout

Vores modificerede build.gradle er i flutter_app/android/app/build.gradle.

Vores key.jks fil er i flutter_app/android/app/key.jks.

Vores key.properties fil er i flutter_app/android/key.properties.

Når vi er sikre på ovenstående, bør vi kunne køre flutter build apk --release nu, og signeringen bør fungere fint.

STEP 4: Afsendelse til Google Play Store

Nu kan vi uploade vores APK eller app-bundle til Play Store. Når vi gør dette med vores signerede pakke og med Google Play Signing slået til (hvilket det er som standard), vil Google anerkende den nøgle, som vi har brugt til at signere pakken, og huske den som vores upload-nøgle. Google vil derefter signere vores APK- eller app-pakke med deres egen nøgle. Det er vigtigt, at alle efterfølgende opdateringer, som vi leverer til denne app, signerer vi med denne samme nøgle. Google Play genkender denne nøgle som vores upload-nøgle, og vi kan ikke frigive opdateringer uden den.

Jeg forstår ikke noget af ovenstående, og jeg ville sætte pris på en utrolig visuel illustration af, hvad der præcist sker.

Kan jeg gøre! Det er det, der sker.

  1. Vi genererer en superhemmelig måde at identificere os selv på, næsten som om vi laver et pas til os selv.
  2. Da enhver med dette “pas” vil kunne identificere sig positivt som os (dvs. efterligne os uden megen modstand), låser vi det bag et kodeord i vores pengeskab (JKS, eller Java Key Store).
  3. Vi opretter app-bundlen eller APK’en og underskriver pakken med den samme signatur, som vi brugte på passet. For at få adgang til dette pas skal vi låse det pengeskab op, som passet befinder sig i (ved at give adgangskoden og aliaset til Gradle-byggeprocessen).
  4. Vi sender pakken til distributøren (Google Play). Distributøren, der ser pakken for første gang, noterer sig vores underskrift, som vi har brugt på denne pakke, og tager en kopi af den.
  5. Når vi sender pakker til vores distributør (Google Play) i fremtiden, underskriver vi disse pakker med de samme oplysninger, som vi brugte i første omgang. Vores distributør, der husker de oplysninger, som vi oprindeligt brugte til at uploade pakken, enten accepterer eller afviser pakken. Hvis det stemmer overens (hvis uploadnøglen er den samme som den, vi brugte oprindeligt), accepteres pakken og distribueres. Ellers accepteres den ikke.
  6. Vores distributør, der ved, at den oprindelige pakke og potentielle fremtidige pakker helt sikkert er fra os, distribuerer pakken.

Få kodesignering til at fungere med Codemagic

Vi ønsker i sidste ende at signere dette som en del af vores CI/CD-arbejdsgang, men samtidig ønsker vi ikke at checke vores keystore- og egenskabsfil ind i kildekontrollen. I stedet ønsker vi, at vores CI/CD-udbyder skal bygge pakken og derefter signere den senere i byggeprocessen med en keystore, som vi leverer.

Sæt det op med Git

Hvis vi har en helt ny Flutter-app, kan vi skifte til mappen og skrive git init for at begynde at bruge kildekontrol med appen.

Som standard tjekker vi bare gladeligt vores keystore- og keystore-egenskabsfil ind, hvilket er en dårlig idé ud fra et sikkerhedsperspektiv.

Du bør få dette lige fra starten

Hvis du ved et uheld tjekker dine keystore-egenskaber og keystore-fil ind og skubber disse ændringer, vil folk til enhver tid i fremtiden kunne plukke disse filer ud ved at kigge i din Git-historik. Du kan manuelt fjerne filer fra Git i fremtiden, eller du kan geninitialisere dit repository uden disse filer, men det er bedre bare at lade være med at tjekke dem i første omgang.

Vi vil gerne tilføje disse linjer til slutningen af vores .gitignore-fil:

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

Ingen Java KeyStore (JKS) eller egenskaber til kodesignering vil blive tjekket ind i kildekontrollen. Hvor dejligt.

Måtte build.gradle ikke signere, når den kører på CI/CD

Mens dit projekt er ved at blive bygget, er keystore og indstillinger ikke tilgængelige. Vi ønsker, at buildet stadig skal producere et release-build, selvom det ikke er signeret.

Dette er den del af min build.gradle, der giver mulighed for dette:

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

Indstilling af Codemagic til at signere vores builds

I din buildproces skal du finde afsnittet om signering af Android-kode (det er i afsnittet Udgiv). Det ser således ud:Android code signing

Nu uploader vi vores keystore og indstiller vores adgangskode, nøglealias og nøgleadgangskode (som er de samme som dem, vi oprindeligt indstillede i vores keystore.properties-fil).

Udfyldte detaljer
Udfyldte detaljer

Så trykker vi på “Save” (Gem). Når Codmagic kører vores byggeproces, vil den automatisk producere en signeret APK eller App Bundle til os.

Og det er stort set det hele! Med denne signerede APK eller App Bundle kan du distribuere din app til Play Store.

Du kan tjekke min Git repo for et eksempel her (naturligvis uden keystore eller egenskaber).

Det er det.

Hvis du stadig er fortabt, er du velkommen til at lade mig vide det på @azimuthapps, så vil jeg forsøge at hjælpe dig. Det kan være frustrerende at få det rigtigt, men når du først har gjort det, bør det fungere i en overskuelig fremtid.

Lewis Cianci er softwareudvikler i Brisbane, Australien. Hans første computer havde et bånddrev. Han har udviklet software i mindst ti år, og han har brugt en hel del rammer for mobiludvikling (som Ionic og Xamarin Forms) i sin tid. Efter at have konverteret til Flutter vil han dog aldrig vende tilbage. Du kan nå ham på hans blog, læse om andre ting uden for Flutter på Medium eller måske få et glimt af ham på din nærmeste og mest fancy kaffebar sammen med ham og hans kære kone.

Mere artikler af Lewis:

Skriv et svar

Din e-mailadresse vil ikke blive publiceret.