Como um script fez o deploy do nosso app ficar até 400% mais rápido

André Zagatti
ReZÉnha
Published in
4 min readApr 8, 2022
Reactjs codes
Photo by Juanjo Jaramillo on Unsplash

Para quem já conhece o React Native, deve conhecer o conceito de deploy over the air ou até mesmo pelo serviço mais conhecido desse conceito que é o CodePush da Microsoft.

Quando temos um aplicativo em React Native existem duas partes de código, o código nativo escrito em Java/Kotlin e Swift/Objective-C, que geralmente são pouco alterados e a segunda parte é o código JavaScript que contém a lógica de componentes, bibliotecas e tudo que é utilizado nessa camada JavaScript. Como comentei, as alterações no código nativo são raras, com isso o conceito de over the air é o aplicativo conferir se existe uma nova versão desse código JavaScript e, caso tenha, baixar para o aplicativo local da pessoa, ou seja, conseguimos criar novas features que alteram só o JavaScript, enviar essa atualização com algum serviço como o CodePush, e então a pessoa terá o aplicativo atualizado sem precisar atualizar na loja de aplicativo do seu celular.

Pipeline e a lentidão

Utilizamos Github Actions em nossa pipeline, com isso geramos uma versão do aplicativo com as alterações da branch na pull request, e em seguida com essa versão conseguimos rodar nossos testes e2e para validar se as alterações não afetam nossos fluxos principais.

O tempo de build do Android é relativamente rápido, chegando a no máximo 20 minutos. Comparado a gerar um ambiente de testes da web é lento, mas geralmente fazemos esse build após as aprovações na pull request e testes de QA então se torna aceitável.

Já o build do iOS demorava de 40 minutos até 1 hora, algo totalmente fora do aceitável, e verificando a etapa que mais demora é criar um novo arquivo .app (um formato da Apple), o arquivo nesse formato se assemelha a uma pasta então podemos mover arquivos para dentro dele, isso já nos dá um ideia de otimização.

Github Actions e o bom e velho script

Para quem não conhece o Github Actions, é uma ferramenta de CI/CD em que os usuários podem criar actions e publicar na loja da ferramenta.

A action que mais facilitou meu trabalho com certeza foi a action de cache, com ela podemos armazenar um artefato qualquer e recuperar escolhendo uma chave única para vários caches específicos.

Na pipeline temos a informação se um cache foi recuperado, então se torna simples gerar o .app ou não, caso exista um cache.

No pipeline do Github Actions também podemos criar scripts em shell, e foi o que fiz para gerar um novo bundle com as informações do JavaScript e mover para dentro do .app com as mudanças, também podemos adicionar novas imagens para utilizar no JavaScript então também adicionei no script para mover as imagens para a pasta assets dentro do .app.

Um exemplo genérico do script:

#!/bin/bashset -e# use version as cache key, for this command to work keep the package key version at the top of the file (usually second after the name)
pkgVersion=$(cat package.json | grep version | head -1 | awk -F: ‘{ print $2 }’ | sed ‘s/[“,]//g’ | tr -d ‘[[:space:]]’)\
# directory when your CI generate and read .app file
releaseDir=”ios/build/Build/Products/Release-iphonesimulator”
appDir=$(pwd)# generate new JS bundle, change index.js if your initial file have another name
yarn react-native bundle \
— entry-file index.js \
— platform ios \
— dev false \
— bundle-output ${releaseDir}/main.jsbundle
echo “## Unzip cached ios ##”
cd ${releaseDir}
unzip ios-${pkgVersion}.zip
echo “## Remove cached zip ##”
rm -rf ios-${pkgVersion}.zip
echo “## Update main.jsbundle and assets on YouApp.app ##”
mkdir assets
cp -R ${appDir}/src/assets/png assets
cp -R ${appDir}/src/assets/json assets
cp -R ${appDir}/src/assets/gif assets
mv main.jsbundle YourApp.app
cp -R assets/* YourApp.app/assets/src/assets/
rm -rf assets
# the directories should change depending on your folder structure, check the assets folder inside your .app and you will know how to replace
echo “### Zip .app with new bundle ##”
zip -rm ios-${pkgVersion}.zip YourApp.app
cd ${appDir}

E agora um exemplo simples de como ficou o nosso fluxo da pipeline de release do iOS.

Novo workflow pro build, primeiro pega o .app no cache, então gera o novo bundle JavaScript e é criado um novo .app com esse bundle, com isso os testes e2e são rodados

Criei um gráfico simples para exemplificar e ficar mais visual a melhoria no tempo de build do iOS. Podemos ver que antes do cache a média de build ultrapassava os 50 minutos, diminuindo com a implementação do cache para uma média de 15 minutos.

Gráfico com o tempo de build, melhorando a média de 55min para 15min

Tentei fazer algo parecido com o Android, mas infelizmente quando descompactamos o arquivo .apk perdemos a assinatura do build gerado e não conseguimos instalar nos celulares/emuladores.

Finalização e comemoração

Após essa implementação o tempo do build no iOS ficou entre 10–18min, uma melhora absurda comparado ao tempo anterior. E não devemos parar por aí, pois para gerar o bundle JS localmente é muito rápido não chegando a 2 minutos, enquanto no CI acaba demorando 5–8 minutos, então melhorar as máquinas com certeza é um próximo passo para evoluir esse tempo tanto no Android, quanto no iOS.

Agora é só comemorar e rodar o build completo somente quando planejarmos uma nova release com alterações nativas.

--

--