Aplicativos de construção é uma paixão compartilhada por desenvolvedores de software em todo o mundo. Mas a sobrecarga administrativa de gerenciar a assinatura de código é monótona. Como podemos acertar isso da primeira vez? Lewis Cianci olha para ele.
Deixe-me só dizer isto com antecedência.
Assinatura de código é tão chato que me faz doer os dentes. É um conceito que existe com uma boa razão. Você quer que as pessoas tenham certeza que o seu pacote de software é realmente de você, certo?! E ainda assim, é algo que tantos desenvolvedores lutam para acertar diariamente. É como fazer seus impostos depois de um ano inteiro de trabalho e ter tantos formulários para preencher. Yippee.
Scroll down se você só quer ver o guia passo-a-passo sobre assinatura de código Android e não estão interessados em porque fazemos this😉
Por que nós codificamos o sinal
Assinamos nossos pacotes para que as pessoas que baixam o nosso pacote na Play Store realmente sabem que somos nós. Nós fazemos isso assinando nosso pacote com uma chave que nós geramos. Quando enviamos nosso pacote assinado para o Google Play, ele se lembra da chave que foi usada para enviar o pacote inicial e garante que os pacotes subsequentes sejam assinados com a mesma chave.
Para atingir esse objetivo, a assinatura do pacote Android realmente tira vantagem de uma ferramenta que vem do framework de desenvolvimento Java chamado keytool. O keytool já existe há tanto tempo quanto o próprio JDK, por isso é bastante antigo. Isso se presta provavelmente a algumas das razões pelas quais assinar um APK ou AAB (android app bundle) é tão confuso quanto é.
Por que a Play Store não pode apenas lidar com a assinatura de código para nós?
Seríamos tentados a pedir por um nirvana onde poderíamos simplesmente dar todos os nossos pacotes de apps não assinados para a Play Store e apenas tê-los para resolver isso e apenas assiná-lo para nós. Mas a lógica disso rapidamente se quebra. Se você escrevesse um livro, conseguiria que alguém o assinasse? Não. Você assinaria porque você é o autor.
Hoje em dia assinar código é muito mais fácil do que costumava ser. Desde que assinemos sempre os nossos pacotes com a mesma chave (a “chave de upload”), o Google Play irá realmente gerar e gerir as nossas chaves de assinatura de código para nós.
Se você é particularmente empreendedor, pode tentar ler e compreender tudo aqui, mas eu tenho vindo a desenvolver para o Android há mais de três anos e estou triste em dizer que mesmo eu não o compreendo completamente. Tudo o que sei é que quando ele quebra, é uma dor enorme para consertar.
Deixemos um tempo para entender não só como codificar o sinal, mas também porque codificamos o sinal. Quando compreendermos a necessidade deste processo, será mais fácil de completar.
O que precisamos para assinar o código?
A versão curta está aqui. Para assinatura de código precisamos:
- criar o arquivo Java Development Kit (JDK);
- assinar nosso pacote de aplicativos ou APK com nossa chave privada;
- modificar o build.gradle;
- enviar pacote para o distribuidor (Google Play).
No final deste artigo você também encontrará como fazer a assinatura de código funcionar com o Codemagic.
Agora uma versão um pouco mais longa com guia passo-a-passo sobre o que precisamos para assinatura de código Android e como fazê-lo.
Guia passo-a-passo para assinatura de código Android
STEP 1: O Java Development Kit (JDK)
Se você está desenvolvendo para Android, provavelmente já tem estes já instalados.
Precisamos criar um arquivo Java Key Store (JKS) que contém nossas informações de assinatura. Ao gerar um JKS para a nossa aplicação, estamos na verdade a criar uma chave privada no nosso computador. Essa chave privada é protegida por uma senha que definimos.
De um prompt de comando, podemos digitar o seguinte para obter um JKS.
keytool -genkey -v -keystore %DESKTOP%/key.jks -storetype JKS -keyalg RSA -keysize 2048 -validity 10000 -alias DEVELOPERNAME
Estamos dizendo a keytool
para gerar um Java Key Store e colocá-lo em nosso desktop. Esta chave será válida por 10.000 dias ou cerca de 27 anos, permitindo-nos empurrar atualizações para a vida útil do nosso aplicativo. Também somos obrigados a definir um alias. Eu apenas faço este meu nome de desenvolvedor ou algo que eu vou lembrar.
keytool
irá solicitar várias informações ao longo do caminho. É importante especificá-las correctamente pois estamos essencialmente a definir os detalhes para a nossa chave privada.
Ser-lhe-á pedido:
- Keystore password – precisará disto para desbloquear esta keystore novamente no futuro. Se você perder esta senha, é praticamente impossível recuperá-la.
- Digite novamente a senha do keystore
- Detalhes pessoais sobre o que colocar no certificado pessoal
Ser-lhe-á pedido que preencha alguns detalhes sobre nós. Estes são os detalhes que estão associados à nossa chave privada, por isso devem ser um pouco relevantes. Depende de você o que você colocar nestes campos, mas como regra geral, eu não deixaria isso muito louco.
Esta é a saída de 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?:
Pague a atenção! Se você apenas enviar spam Entre através deste processo, a criação irá apenas fazer um loop repetidamente enquanto você responde ‘não’ à última pergunta.
Ao fazer isso, nós criamos um JKS e colocamos a nossa própria chave privada gerada nele. Porque nós o geramos e definimos a senha, podemos ter certeza de que qualquer um que tenha esse arquivo JKS é nós ou está especificamente autorizado a usá-lo.
Se alguém tiver o seu JKS e as credenciais corretas, ele pode assinar pacotes como você ou sua empresa. Mantenha-o seguro, não o coloque no controle de código fonte.
Agora temos a nossa Java Key Store, por isso estamos a meio caminho! Alegre-se de acordo.
STEP 2: Assinando nosso pacote de maçãs ou APK com nossa chave privada
Agora, queremos assinar nosso pacote de maçãs com aquele JKS que acabamos de fazer. É possível assinar manualmente o nosso APK ou release build cada vez, mas na realidade, seria melhor configurá-lo para que quando executarmos flutter build apk --release
ele apenas assine automaticamente o nosso pacote com a chave de upload certa. A documentação do Flutter fala sobre como atualizar os arquivos Gradle aqui, mas nós vamos analisá-lo lentamente e explicá-lo pelo caminho.
Para começar, vamos abrir nosso arquivo flutter_app/android/app/build.gradle
. Na linha 49 podemos ver isto:
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 }}
O principal que está acontecendo aqui é que nossos builds estão sendo assinados com a debug
keystore, então nosso build de lançamento ainda funciona. Nós queremos mudar isso para que nossos lançamentos sejam assinados com nossa própria keystore. Assim eles podem ser enviados para a loja do Google Play.
A primeira coisa que fazemos é criar um key.properties
em nosso diretório de aplicativos. Criamos isto em flutter_app/android/key.properties
.
key.properties
incluirá todos os detalhes que precisamos para assinar com sucesso nosso pacote.
storePassword=The JKS store passwordkeyPassword=The key passwordkeyAlias=The alias for your keystoreFile=Where to look for your keystore file
Uma nota rápida sobre o controle do código fonte
Você deve pensar antes de verificar este código no controle do código fonte. Se atores ruins tivessem acesso à loja de chaves e essas credenciais, e eles tivessem controle sobre suas contas, eles poderiam empurrar uma nova atualização para sua aplicação com malware ou outras coisas ruins. A maioria das soluções CI/CD permitem-lhe fornecer estes detalhes como “segredos”, mas a implementação difere por plataforma.
STEP 3: Recapitulação & Modificando o build.gradle
Fizemos um ficheiro de keystore, e especificámos um alias, assim como uma palavra-passe para proteger o keystore. Se estamos usando a assinatura da aplicação Google Play (que você usa por padrão), então a chave que nós geramos atua como nossa chave de upload. O primeiro pacote que enviarmos através do console do Google Play será assinado com essa chave. Isto prova ao Google que somos quem dizemos ser.
Make sense? Legal, vamos fazer isso assinar como parte do nosso processo de construção Flutter.
Modificar o build.gradle
Abrir flutter_app/android/app/build.gradle
. Na linha 31 mais ou menos assim você deve ver um texto como este:
android { compileSdkVersion 29` lintOptions { disable 'InvalidPackage' }...
Queremos dizer ao Gradle onde encontrar a loja de chaves. Fazemos isso colocando estes detalhes na linha 28, acima da declaração android {
def keystoreProperties = new Properties()def keystorePropertiesFile = rootProject.file('key.properties')if (keystorePropertiesFile.exists()) { keystoreProperties.load(new FileInputStream(keystorePropertiesFile))}
Vamos quebrar o acima para baixo…
Definimos uma variável keystoreProperties
. Depois, verificamos se key.properties
existe relativamente à raiz do nosso projecto androide (não o projecto Flutter).
Quando a nossa construção corre, carrega key.properties
. key.properties
identifica a localização da keystore, mais as credenciais necessárias para desbloquear a Java Key Store para assinar o pacote. Com todos os detalhes necessários em mãos, Gradle agora assina o app bundle ou APK como parte do nosso build de lançamento.
Vamos apenas verificar se todos os nossos arquivos estão no local certo.
>
O nosso modificado build.gradle
está em flutter_app/android/app/build.gradle
.
Nosso key.jks
arquivo está em flutter_app/android/app/key.jks
.
Nosso key.properties
arquivo está em flutter_app/android/key.properties
.
Após termos certeza do acima, devemos ser capazes de executar flutter build apk --release
agora e assinar deve funcionar bem.
STEP 4: Enviando para a Loja Play do Google
Agora podemos enviar nosso APK ou pacote de maçã para a Loja Play. Quando fizermos isso com nosso pacote assinado, e com o Google Play Signing on (que é por padrão), o Google reconhecerá a chave que usamos para assinar o pacote e o lembrará como nossa chave de envio. O Google assinará então nosso APK ou pacote de aplicativos com sua própria chave. É importante que quaisquer atualizações subsequentes que fornecemos para este aplicativo, nós assinamos com esta mesma chave. O Google Play reconhece esta chave como nossa chave de upload e não podemos lançar atualizações sem ela.
Não entendo nada do acima e eu apreciaria uma ilustração incrivelmente visual do que exatamente está acontecendo.
Posso fazer! Isto é o que está acontecendo.
- Geramos uma maneira super secreta de nos identificarmos, quase como se fizéssemos um passaporte para nós mesmos.
- Porque qualquer pessoa com este ‘passaporte’ será capaz de se identificar positivamente como nós (ou seja: imitar-nos sem muita resistência), nós trancamos atrás de uma senha em nosso cofre (o JKS, ou Java Key Store).
- Criamos o pacote de maçã ou APK, e então assinamos o pacote com a mesma assinatura que usamos no passaporte. Para acessar esse passaporte, temos que destravar o cofre em que o passaporte está (fornecendo a senha e o apelido para o processo de construção do Gradle).
- Enviamos o pacote para o distribuidor (Google Play). O distribuidor, vendo o pacote pela primeira vez, toma nota da nossa assinatura que usamos neste pacote e leva uma cópia do mesmo.
- Quando enviamos pacotes para o nosso distribuidor (Google Play) no futuro, assinamos estes pacotes com os mesmos detalhes que usamos inicialmente. Nosso distribuidor, lembrando os detalhes que usamos inicialmente para enviar o pacote, ou aceita ou rejeita o pacote. Se corresponder (se a chave de upload for a mesma que utilizámos inicialmente), então o pacote é aceite e distribuído. Caso contrário, não é aceite.
- O nosso distribuidor, sabendo que o pacote inicial e potenciais pacotes futuros são definitivamente de nós, distribui o pacote.
Fazer a assinatura do código funcionar com o Codemagic
Queremos finalmente assinar isto como parte do nosso fluxo de trabalho CI/CD mas, ao mesmo tempo, não queremos verificar na nossa loja de chaves e ficheiro de propriedades o controlo do código fonte. Em vez disso, queremos que nosso provedor de CI/CD construa o pacote e depois assine-o mais tarde no processo de compilação com um keystore que fornecemos.
Configurando-o com Git
Se tivermos um aplicativo Flutter totalmente novo, então podemos mudar para a pasta e digitar git init
para começar a usar o controle do código-fonte com o aplicativo.
Por padrão, nós apenas verificaremos com prazer em nosso arquivo de propriedades de keystore e keystore, o que é uma má idéia do ponto de vista de segurança.
Você deve acertar desde o início
Se você acidentalmente verificar em seu arquivo de propriedades de keystore e keystore e empurrar essas mudanças, as pessoas serão capazes de arrancar esses arquivos a qualquer momento no futuro, olhando através de seu histórico de Git. Você pode remover manualmente arquivos do Git no futuro, ou você pode reinicializar seu repositório sem esses arquivos, mas é melhor simplesmente não verificá-los em primeiro lugar.
Queremos adicionar essas linhas ao final do nosso .gitignore
file:
# Don't check in the keystore files or equivalent*.jkskey*.properties
No Java KeyStore (JKS) ou propriedades para assinatura de código será verificado no controle do código fonte. How lovely.
Making build.gradle not sign when running on CI/CD
While seu projeto está construindo, o keystore e as configurações não estão disponíveis. Queremos que o build ainda produza um build de lançamento mesmo que não esteja assinado.
Esta é a parte do meu build.gradle
que permite isso:
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 }}
Configurando o Codemagic para assinar nossos builds
Em seu processo de build, encontre a seção de assinatura do código do Android (está na seção Publish). Parece assim:
Agora, nós carregamos nossa keystore e definimos nossa senha, alias de chave, e senha de chave (que são as mesmas que definimos inicialmente em nosso arquivo keystore.properties).
>
Agora, clicamos em “Salvar”. Quando o Codmagic executa nosso processo de construção, ele irá automaticamente produzir um APK ou App Bundle assinado para nós.
E é isso mesmo! Com esse APK ou App Bundle assinado, você pode implementar sua aplicação na Play Store.
Você pode conferir meu repo Git para um exemplo aqui (obviamente, sem a loja de chaves ou propriedades).
É isso.
Se você ainda estiver perdido, sinta-se livre para me avisar em @azimuthapps e eu tentarei ajudar. Pode ser frustrante acertar, mas uma vez que o faça, deve funcionar num futuro próximo.
Lewis Cianci é um desenvolvedor de software em Brisbane, Austrália. Seu primeiro computador tinha um drive de fita. Ele tem desenvolvido software por pelo menos dez anos, e tem usado vários frameworks de desenvolvimento móvel (como Ionic e Xamarin Forms) em seu tempo. Depois de converter para Flutter, porém, ele nunca mais vai voltar. Você pode contatá-lo em seu blog, ler sobre outras coisas que não são de flutter no Medium, ou talvez vislumbrá-lo em sua cafeteria mais próxima e mais chique com ele e sua querida esposa.
Mais artigos de Lewis: