Guida passo dopo passo alla firma del codice Android e alla firma del codice con Codemagic

Connettiti con oltre 3.000 sviluppatori di app mobili su Slack Unisciti alla Codemagic Community

Costruire applicazioni è una passione condivisa dagli sviluppatori di software di tutto il mondo. Ma il carico amministrativo della gestione della firma del codice è noioso. Come possiamo farlo bene la prima volta? Lewis Cianci lo esamina.

Lasciatemi dire questo in anticipo.

La firma del codice è così noiosa che mi fa male ai denti. È un concetto che esiste per una buona ragione. Voglio dire, vuoi che la gente sia sicura che il tuo pacchetto software sia effettivamente tuo, giusto? Eppure, è qualcosa che così tanti sviluppatori lottano quotidianamente per fare bene. È come fare le tasse dopo un anno intero di lavoro e avere così tanti moduli da compilare. Yippee.

La firma del codice è come fare le tasse dopo un anno intero di lavoro e avere così tanti moduli da compilare. Codemagic ha una grande guida passo-passo per semplificarti la vita
Clicca per twittare

Scorri in basso se vuoi solo vedere la guida passo-passo sulla firma del codice Android e non sei interessato al perché lo facciamo😉

Perché firmiamo il codice

Firmiamo i nostri pacchetti così le persone che scaricano il nostro pacchetto dal Play Store sanno effettivamente che siamo noi. Lo facciamo firmando il nostro pacchetto con una chiave che generiamo noi. Quando carichiamo il nostro pacchetto firmato su Google Play, esso ricorda la chiave che è stata usata per caricare il pacchetto iniziale e si assicura che i pacchetti successivi siano firmati con la stessa chiave.

Per raggiungere questo obiettivo, la firma dei pacchetti Android sfrutta uno strumento che viene dal Java Development Framework chiamato keytool. Keytool è in giro probabilmente da tanto tempo quanto il JDK stesso, quindi è abbastanza vecchio. Questo si presta probabilmente ad alcune delle ragioni per cui la firma di un APK o AAB (bundle di app per Android) è così confusa come lo è.

Perché il Play Store non può semplicemente gestire la firma del codice per noi?

Saremmo tentati di chiedere un nirvana in cui potremmo semplicemente dare tutti i nostri bundle di app non firmati al Play Store e semplicemente farli lavorare e firmare per noi. La logica di questo si rompe rapidamente però. Se tu scrivessi un libro, lo faresti firmare da qualcun altro? No. Lo firmereste voi perché siete l’autore.

Oggi la firma del codice è molto più facile di quanto non fosse in passato. Finché firmiamo sempre i nostri pacchetti con la stessa chiave (la “chiave di caricamento”), Google Play genererà e gestirà le nostre chiavi di firma del codice per noi.

Se siete particolarmente intraprendenti, potete tentare di leggere e capire tutto qui, ma io sviluppo per Android da quasi tre anni e sono triste di dire che nemmeno io lo capisco completamente. Tutto quello che so è che quando si rompe, è un dolore enorme da riparare.

Prendiamoci il tempo per capire non solo come codificare il segno ma anche perché codifichiamo il segno. Quando capiremo la necessità di questo processo, sarà più facile da completare.

Di cosa abbiamo bisogno per la firma del codice?

La versione breve è qui. Per la firma del codice abbiamo bisogno di:

  • creare il file Java Development Kit (JDK);
  • firmare il bundle della nostra app o APK con la nostra chiave privata;
  • modificare il build.gradle;
  • inviare il pacchetto al distributore (Google Play).

In fondo a questo articolo troverete anche come far funzionare la firma del codice con Codemagic.

Ora una versione un po’ più lunga con una guida passo-passo su cosa ci serve per la firma del codice Android e come farlo.

Guida passo-passo per la firma del codice Android

Passo 1: Il Java Development Kit (JDK)

Se stai sviluppando per Android, probabilmente li hai già installati.

Abbiamo bisogno di creare un file Java Key Store (JKS) che contiene le nostre informazioni di firma. Nel generare un JKS per la nostra applicazione, stiamo effettivamente creando una chiave privata sul nostro computer. Questa chiave privata è protetta da una password che abbiamo impostato.

Dal prompt dei comandi, possiamo digitare quanto segue per ottenere un JKS.

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

Stiamo dicendo a keytool di generare un Java Key Store e metterlo nel nostro desktop. Questa chiave sarà valida per 10.000 giorni o circa 27 anni, permettendoci di spingere gli aggiornamenti per tutta la durata della nostra app. Ci viene anche richiesto di impostare un alias. Io faccio solo il mio nome da sviluppatore o qualcosa che ricorderò.

keytool richiederà varie informazioni lungo il percorso. È importante specificarle correttamente perché stiamo essenzialmente definendo i dettagli della nostra chiave privata.

Vi verrà richiesto:

  • Password del keystore – ne avrete bisogno per sbloccare questo keystore in futuro. Se perdi questa password, è praticamente impossibile recuperarla.
  • Reinserisci la password del keystore
  • Dettagli personali su cosa mettere nel certificato personale

Ci verrà richiesto di compilare alcuni dettagli su di noi. Questi sono i dettagli che sono associati alla nostra chiave privata, quindi dovrebbero essere in qualche modo rilevanti. Sta a te decidere cosa mettere in questi campi, ma come regola generale, non li renderei troppo folli.

Questo è l’output di 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?:

Fai attenzione! Se spammate Enter attraverso questo processo, la creazione andrà in loop ancora e ancora mentre rispondete ‘no’ all’ultima domanda.

In questo modo abbiamo creato un JKS e ci abbiamo messo la nostra chiave privata generata. Poiché l’abbiamo generata e abbiamo impostato la password, possiamo essere sicuri che chiunque abbia questo file JKS siamo noi o è specificamente autorizzato ad usarlo.

Se qualcuno ha il vostro JKS e le credenziali corrette, può firmare i pacchetti come voi o la vostra azienda. Tienilo al sicuro, non metterlo sul controllo dei sorgenti.

Ora abbiamo il nostro Java Key Store, quindi siamo a metà strada! Rallegratevi di conseguenza.

STEP 2: Firmare il nostro app bundle o APK con la nostra chiave privata

Ora, vogliamo firmare il nostro app bundle con la JKS che abbiamo appena fatto. E’ possibile firmare manualmente il nostro APK o release build ogni singola volta, ma in realtà, sarebbe meglio configurarlo in modo che quando eseguiamo flutter build apk --release firmi automaticamente il nostro pacchetto con la giusta chiave di caricamento. La documentazione di Flutter parla di come aggiornare i file Gradle qui, ma lo faremo lentamente e lo spiegheremo lungo la strada.

Per iniziare, apriamo il nostro file flutter_app/android/app/build.gradle. Sulla linea 49 possiamo vedere questo:

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

La cosa principale che sta succedendo qui è che le nostre build sono firmate con il keystore debug, quindi la nostra build di rilascio funziona ancora. Vogliamo cambiare questo in modo che le nostre release siano firmate con il nostro keystore. In questo modo possono essere caricate sul Google Play store.

La prima cosa che facciamo è creare un key.properties nella nostra directory delle app. Lo creiamo in flutter_app/android/key.properties.

key.properties includerà tutti i dettagli di cui abbiamo bisogno per firmare con successo il nostro pacchetto.

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

Una nota veloce sul controllo dei sorgenti

Si dovrebbe pensare prima di controllare questo codice nel controllo dei sorgenti. Se i cattivi attori dovessero avere accesso al keystore e a queste credenziali, e avessero il controllo sui vostri account, potrebbero potenzialmente spingere un nuovo aggiornamento alla vostra applicazione con malware o altre cose brutte. La maggior parte delle soluzioni CI/CD ti permette di fornire questi dettagli come “segreti”, ma l’implementazione differisce per piattaforma.

STEP 3: Recap &Modificare il build.gradle

Abbiamo creato un file keystore, e specificato un alias, così come una password per proteggere il keystore. Se stiamo usando la firma delle app di Google Play (che si usa di default), allora la chiave che abbiamo generato funge da chiave di caricamento. Il primo pacchetto che carichiamo tramite la console di Google Play sarà firmato con questa chiave. Questo dimostra a Google che siamo chi diciamo di essere.

Ha senso? Bene, facciamolo firmare come parte del nostro processo di compilazione di Flutter.

Modifica il build.gradle

Apri flutter_app/android/app/build.gradle. Sulla linea 31 circa dovresti vedere un testo come questo:

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

Vogliamo dire a Gradle dove trovare il negozio di chiavi. Lo facciamo mettendo questi dettagli sulla linea 28 circa, sopra la dichiarazione android {.

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

Facciamo un break down di quanto sopra…

Definiremo una variabile keystoreProperties. Poi, controlliamo se key.properties esiste relativamente alla radice del nostro progetto Android (non il progetto Flutter).

Quando la nostra build viene eseguita, carica key.properties. key.properties identifica la posizione del keystore, più le credenziali necessarie per sbloccare il Java Key Store per firmare il pacchetto. Con tutti i dettagli richiesti in mano, Gradle ora firma il bundle dell’app o APK come parte della nostra build di rilascio.

Controlliamo che tutti i nostri file siano nel posto giusto.

Il nostro layout del progetto android
Il nostro layout del progetto android

Il nostro build.gradle modificato è in flutter_app/android/app/build.gradle.

Il nostro file key.jks è in flutter_app/android/app/key.jks.

Il nostro file key.properties è in flutter_app/android/key.properties.

Una volta che siamo sicuri di quanto sopra, dovremmo essere in grado di eseguire flutter build apk --release e la firma dovrebbe funzionare bene.

Passo 4: Inviarlo a Google Play Store

Ora possiamo caricare il nostro APK o bundle di app sul Play Store. Quando lo facciamo con il nostro pacchetto firmato, e con Google Play Signing attivo (che è di default), Google riconoscerà la chiave che abbiamo usato per firmare il pacchetto e la ricorderà come nostra chiave di caricamento. Google firmerà quindi il nostro APK o bundle di app con la propria chiave. È importante che ogni successivo aggiornamento che forniamo per questa app, lo firmiamo con questa stessa chiave. Google Play riconosce questa chiave come la nostra chiave di caricamento e non possiamo rilasciare aggiornamenti senza di essa.

Non capisco nulla di quanto sopra e apprezzerei un’illustrazione incredibilmente visiva di ciò che sta accadendo esattamente.

Si può fare! Questo è quello che sta succedendo.

  1. Generiamo un modo super segreto per identificarci, quasi come se facessimo un passaporto per noi stessi.
  2. Perché chiunque abbia questo “passaporto” sarà in grado di identificarsi positivamente come noi (cioè: impersonarci senza molta resistenza), lo chiudiamo dietro una password nella nostra cassaforte (il JKS, o Java Key Store).
  3. Creiamo il bundle dell’app o APK, e poi firmiamo il pacchetto con la stessa firma che abbiamo usato sul passaporto. Per accedere a questo passaporto, dobbiamo sbloccare la cassaforte in cui si trova il passaporto (fornendo la password e l’alias al processo di build di Gradle).
  4. Inviamo il pacchetto al distributore (Google Play). Il distributore, vedendo il pacchetto per la prima volta, prende nota della nostra firma che abbiamo usato su questo pacchetto e ne prende una copia.
  5. Quando mandiamo pacchetti al nostro distributore (Google Play) in futuro, firmiamo questi pacchetti con gli stessi dettagli che abbiamo usato inizialmente. Il nostro distributore, ricordando i dettagli che abbiamo usato inizialmente per caricare il pacchetto, accetta o rifiuta il pacchetto. Se corrisponde (se la chiave di caricamento è la stessa che abbiamo usato inizialmente), allora il pacchetto viene accettato e distribuito. Altrimenti, non viene accettato.
  6. Il nostro distributore, sapendo che il pacchetto iniziale e i potenziali pacchetti futuri provengono sicuramente da noi, distribuisce il pacchetto.

Far funzionare la firma del codice con Codemagic

In definitiva vogliamo firmare questo come parte del nostro flusso di lavoro CI/CD, ma allo stesso tempo, non vogliamo controllare il nostro keystore e il file delle proprietà nel controllo delle fonti. Invece, vogliamo che il nostro provider CI/CD costruisca il pacchetto e poi lo firmi più tardi nel processo di costruzione con un keystore che forniamo noi.

Impostazione con Git

Se abbiamo un’app Flutter completamente nuova, allora possiamo passare alla cartella e digitare git init per iniziare a usare il controllo dei sorgenti con l’app.

Per impostazione predefinita, controlleremo felicemente il nostro keystore e il file delle proprietà del keystore, che è una cattiva idea dal punto di vista della sicurezza.

Dovresti farlo fin dall’inizio

Se accidentalmente controlli le proprietà del keystore e il file del keystore e fai il push di quei cambiamenti, la gente sarà in grado di strappare quei file in qualsiasi momento in futuro guardando nella tua cronologia Git. Puoi rimuovere manualmente i file da Git in futuro, o puoi reinizializzare il tuo repository senza quei file, ma è meglio non controllarli in primo luogo.

Vogliamo aggiungere queste righe alla fine del nostro file .gitignore:

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

Nessun Java KeyStore (JKS) o proprietà per la firma del codice sarà controllato nel controllo sorgente. Che bello.

Fare in modo che build.gradle non firmi quando viene eseguito su CI/CD

Mentre il progetto è in costruzione, il keystore e le impostazioni non sono disponibili. Vogliamo che la build produca comunque una build di rilascio anche se non è firmata.

Questa è la parte del mio build.gradle che lo permette:

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

Impostare Codemagic per firmare le nostre build

Nel tuo processo di build, trova la sezione di firma del codice Android (è nella sezione Publish). Assomiglia a questo:Android code signing

Ora, carichiamo il nostro keystore e impostiamo la nostra password, alias chiave e password chiave (che sono gli stessi che abbiamo impostato inizialmente nel nostro file keystore.properties).

Dettagli compilati
Dettagli compilati

Quindi premiamo “Save”. Quando Codmagic esegue il nostro processo di compilazione, produrrà automaticamente un APK o App Bundle firmato per noi.

E questo è praticamente tutto! Con questo APK o App Bundle firmato, puoi distribuire la tua app sul Play Store.

Puoi controllare il mio repo Git per un esempio qui (ovviamente, senza il keystore o le proprietà).

Ecco tutto.

Se sei ancora perso, fammi sapere a @azimuthapps e proverò ad aiutarti. Può essere frustrante ottenere il risultato giusto, ma una volta fatto, dovrebbe funzionare per il prossimo futuro.

Lewis Cianci è uno sviluppatore di software a Brisbane, Australia. Il suo primo computer aveva un’unità a nastro. Sviluppa software da almeno dieci anni e ha usato diversi framework di sviluppo mobile (come Ionic e Xamarin Forms) nel suo tempo. Dopo la conversione a Flutter, però, non tornerà più indietro. Potete raggiungerlo sul suo blog, leggere di altre cose non-fluttery su Medium, o forse intravederlo nella caffetteria più vicina e più elegante con lui e la sua cara moglie.

Altri articoli di Lewis:

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.