Automatize o Deploy de Aplicativos React Native App

Rakesh Arunachalam
Traduzido por Diego Oliveira
Este artigo também está disponível em: English

Introdução

A implantação de aplicativos é uma parte fundamental do fluxo de trabalho de desenvolvimento nativo, e automatizá-la pode tornar o processo mais eficiente e controlável. Este artigo visa educar sobre as várias opções de implantação disponíveis para um aplicativo React Native, a estratégia apropriada e as maneiras de automatizá-las. A combinação dessas estratégias nos permitiu fornecer atualizações de aplicativos tão rapidamente quanto as de back-end.

Antes de mergulhar na implantação, é útil entender que existem duas partes principais de qualquer aplicativo React Native:

  • O contêiner do aplicativo nativo (diferente para iOS e Android)
  • A base de código JavaScript que se comunica com o contêiner nativo usando uma ponte

A documentação React Native explica isso bem.

Passos manuais para implantar um aplicativo React Native

Para iOS, estes são os passos para arquivar e enviar uma nova build no TestFlight por meio da App Store Connect:

  1. Abra o XCode e selecione seu projeto no Project Navigator.
  2. Atualize o número da Versão ou Build
  3. Na barra superior, clique em Product > Archive (depois que o aplicativo for arquivado, a janela Archive Manager será aberta).
  4. Selecione o novo Arquivo e clique no botão Distribute App.
  5. Selecione o método de distribuição: App Store Conect e escolha Destino: Upload
  6. Nas opções de distribuição da App Store Connect, verifique se todas as opções estão marcadas.
  7. Selecione o perfil Automatic, revise o conteúdo e clique no botão Upload.
  8. Depois que o upload terminar, vá para App Store Connect > My Apps, selecione seu aplicativo e a build deve estar disponível no painel.
  9. Depois que a build é processada, ela está pronta para ser enviada para testadores internos que fazem parte de sua Equipe de Desenvolvimento Apple ou usuários externos convidados diretamente por meio de um link público.

O processo de implantação no Android envolve uma série de etapas, como gerar uma chave de upload usando keytool, executar comandos para gerar compilações de lançamento e fazer upload do aplicativo na Play Store.

Com base nisso, temos várias etapas para ambas as plataformas e algumas delas são propensas a erros do desenvolvedor.

Métricas para estratégia de implantação

Para um aplicativo React Native, aqui estão algumas métricas valiosas que podem ser usadas para decidir se uma estratégia de implantação será bem-sucedida:

  1. Tempo de implantação - O tempo decorrido desde o início do processo de implantação até que uma atualização do aplicativo esteja disponível nas lojas. Isso também inclui o tempo gasto no imprevisível processo de revisão do aplicativo.
  2. Tempo de atualização - Não implantamos para 100% dos usuários se eles não atualizarem imediatamente. Nem todos os usuários atualizam seus aplicativos quando há uma atualização de aplicativo e pode levar algumas semanas ou até um mês para garantir que uma grande porcentagem dos usuários tenha atualizado. Às vezes, vale a pena medir se uma porcentagem maior de usuários ativos fez upgrade.
  3. Frequência de implantações - O número de atualizações de aplicativos enviadas em um determinado momento. Se esse número for pequeno, os dois fatores acima podem não importar. Mas se nossa equipe enviar muitas atualizações e os fatores acima começarem a afetar a entrega, pode valer a pena mudar a estratégia ou adicionar uma nova abordagem para complementar a existente.
  4. Automático/Manual - Ao implantar atualizações de aplicativos, desenvolvedores não têm um botão “Desfazer” e as atualizações são permanentes após o envio. Imagine enviar uma atualização de aplicativo para milhares de usuários e perceber que um desenvolvedor usou erroneamente o ambiente de preparação em vez de produção durante o processo de implantação. Isso piora quando uma correção que aborda isso leva dois dias para ser disponibilizada devido a estar presta na revisão do aplicativo. Qualquer estratégia de implantação deve ser automática de forma que pelo menos elimine os erros do desenvolvedor.
  5. Complexidade de implementação - É ótimo ter uma implementação com um clique, mas não é ideal se levar algumas semanas para ser implementada. Esperamos com otimismo que desenvolvedores configurem o aplicativo, as ferramentas de CI (TypeScript, Linter, Testes) e as implantações de aplicativos (Android e iOS) em uma semana. Pode ser aceitável se o processo não for totalmente automático, desde que o restante das métricas seja tratado por nossa estratégia.

Implantação aplicativo Expo x React Native CLI

É relativamente fácil implantar um aplicativo usando Expo em comparação à React Native CLI.

A diferença entre Expo e RN CLI é que o Expo fornece ótimas predefinições e ajuda no desenvolvimento de diferentes aspectos (permissões de aplicativos, notificações push, modo escuro etc.) da experiências do usuário em vez de lidar com conflitos de bibliotecas de terceiros, problemas de integração, atualizações e manutenção. Com a CLI, os desenvolvedores têm maior flexibilidade para decidir as bibliotecas corretas que resolvem o problema e, às vezes, isso pode ser bom, pois o Expo pode limitar desenvolvedores com o que pode ser alcançado em um aplicativo móvel. No entanto, essa escolha tem um custo na forma de horas gastas pelo desenvolvedor na integração da biblioteca com as plataformas nativas. Portanto, o contêiner nativo de uma aplicação Expo é limitado por um motivo ainda estável para cada versão.

A base de código JavaScript pode mudar dinamicamente com base no aplicativo que queremos construir. Além disso, Expo utiliza Expo Application Services, o que facilita a atualização do pacote JavaScript over-the-air. A execução de um comando em seu terminal ou CI pode fornecer atualizações instantâneas para todos os usuários do aplicativo sem submeter uma atualização para a iOS App Store ou Google Playstore, o que é fantástico de uma perspectiva de implantação contínua.

No entanto existem alguns contras em usar o Expo, como

  • Native Modules, que está disponível apenas no React Native CLI, permite que o código React Native JavaScript converse com o código da plataforma Native.
  • As atualizações mais recentes da plataforma (iOS/Android) não estão disponíveis imediatamente e precisamos esperar que a equipe da Expo as implemente em uma versão futura.

Os aplicativos criados com o RN CLI têm recursos quase ilimitados. Portanto, vamos nos concentrar apenas nas estratégias de implantação de aplicativos baseados em RN CLI neste post.

FastLane

Ao iniciar um novo projeto, há uma possibilidade maior de adicionar bibliotecas de terceiros e dependências associadas ao projeto, o que significa que o contêiner do aplicativo nativo e a base de código JavaScript mudam continuamente. Isso significa também que as equipes devem enviar atualizações com frequência para as lojas de aplicativos iOS/Android. Automatizar as compilações de aplicativos mantém a equipe produtiva e focada no desenvolvimento do aplicativo em vez de implantá-lo.

Fastlane é uma ferramenta comumente usada para gerenciar implantações de aplicativos. Ela é construída usando Ruby, já existe há algum tempo e está bem documentado. Também facilita a implantação de aplicativos em vários ambientes (desenvolvimento, preparação, produção), pois podemos criar lanes separadas para cada ambiente e plataforma.

Fastfile contém todos esses comandos de lanes, e o README.md é gerado automaticamente para que cada membro da equipe tenha o poder de implantar os aplicativos em múltiplos ambientes e plataformas. Há também um ecossistema de plugins com muitas integrações para serviços como Microsoft AppCenter, incremento de número de versão, símbolos de upload para Sentry, Bugsnag, etc.

Implantação de aplicativo na máquina local

A documentação da Fastlane contêm todas as informações necessárias para configurar um fluxo de trabalho de implantação individual. Esta seção mostra como um fluxo de trabalho de implantação se parece, destacando aqueles que provaram ser bem-sucedidos em nossos projetos.

iOS

Para iOS, estes são os passos típicos do fluxo de trabalho de implantação do aplicativo que a Fastlane gerencia para nós:

  • Certifique-se de que o repositório git esteja limpo, pois não queremos criar e enviar aplicativos com código não commitado.
  • Incremente automaticamente os números da build do iOS, pois todos os aplicativos iOS enviados ao TestFlight precisam de um número da build maior.
  • Commite essas alterações, crie uma tag git e envie as alterações para o repositório. Essas tags git servem como pontos de verificação para identificar rapidamente o commit que causou o lançamento de um determinado aplicativo.
  • Compile o aplicativo usando o esquema correto com base na lane selecionada. Exemplo: para a lane desenvolvimento, compile a versão de desenvolvimento do aplicativo.
  • Envie a build do aplicativo gerada para o TestFlight iOS.

lane :development do
  ensure_git_status_clean
  increment_build_number(xcodeproj: 'ios/MyApp.xcodeproj')
  commit_version_bump(xcodeproj: 'ios/MyApp.xcodeproj')
  add_git_tag
  push_to_git_remote
  scheme = options.fetch(:scheme, 'Development')
  gym(
    scheme: scheme,
    include_bitcode: false,
    export_xcargs: '-allowProvisioningUpdates',
  )
  testflight(skip_waiting_for_build_processing: false)
end

Android

Para Android, estes são passos gerenciados pela Fastlane:

  • Verifique que o repositório git está limpo.
  • Compile o aplicativo para o ambiente correto e a lane do Google Play.
  • Submeta a build do aplicativo gerada para a Google Playstore.
lane :build do |options|
  type = options.fetch(:type, 'Release')
  env = options.fetch(:env, 'development')
  track = options.fetch(:track, 'beta')
  ENV['ENVFILE'] = '.env.#{env}'
  Dir.chdir('..') do
    sh 'bin/bundle-android'
  end
  gradle(task: 'clean')
  gradle(
    task: 'assemble',
    flavor: track,
    build_type: type,
  )
end

lane :development do
  ensure_git_status_clean
  build(type: 'Release', env: 'development', track: 'development')
  supply(
    track: 'internal',
    apk: 'development',
    package_name: 'com.myapp.development'
  )
end

Não temos incrementos de número de versão automatizados porque, no Android, usamos variações de produto que a FastLane não suporta para serem incrementados automaticamente. Infelizmente, isso deve ser feito manualmente antes de implantar um aplicativo Android.

Fluxo de trabalho de Implantação Contínua no CI

Todo o processo de implantação é difícil de automatizar totalmente no CI, por isso realizamos implantações semiautomáticas. O processo de compilação é totalmente automatizado no [Circle CI], enquanto a implantação nas lojas é feita manualmente na máquina local. Isso garante que não haja erros do desenvolvedor em relação às variáveis de ambiente e outras configurações específicas do ambiente (Firebase, configuração da Play Store, etc.) durante as implantações do aplicativo, pois esses dados são armazenados como segredos do Circle CI.

Um fluxo de trabalho Circle CI é mostrado abaixo, que ajuda desenvolvedores a criar aplicativos iOS e Android no CI em três etapas:

  • build - Verificações básicas de qualidade de código (lint, tipos, testes, etc.)
  • hold_build - Um processo de aprovação para conservar recursos do CI e não compilar aplicativos para cada commit.
  • build_ios ou build_android - Processo de compilação real que gera as compilações do aplicativo como artefatos.

Circle CI

Processo de compilação iOS

Às vezes, a sessão de conexão da Apple AppStore requer uma senha única, que pode ser inserida na máquina local, mas não no CI. As soluções alternativas disponíveis não eram confiáveis, o que nos fez dividir o fluxo de trabalho em três como:

  1. Na máquina local, execute bundle exec fastlane ios adhoc_pre_build. Independentemente do ambiente “Development”, “Staging”, or “Production”, isso deve ser executado para cada implantação no Testflight, pois incrementa o número da build do aplicativo iOS.
  2. bundle exec fastlane ios adhoc_build será executado no CI, baseado no ambiente selecionado, eventualmente gerando uma build do aplicativo (arquivo IPA).
  3. bundle exec fastlane ios adhoc_deploy scheme:{SCHEME_NAME} deve ser executado pelo desenvolvedor após o download do artefato (IPA) produzido pelo CI. SCHEME_NAME deve ser fornecido dependendo do ambiente escolhido no processo de compilação acima.
lane :adhoc_pre_build do
  increment_build_number(xcodeproj: 'ios/MyApp.xcodeproj')
  commit_version_bump(xcodeproj: 'ios/MyApp.xcodeproj')
  add_git_tag
  push_to_git_remote
end

lane :adhoc_build do |options|
  scheme = options.fetch(:scheme, "Development")
  match(type: "appstore", readonly: true)
  gym(
    scheme: scheme,
    include_bitcode: false,
    export_xcargs: "-allowProvisioningUpdates",
  )
end

lane :adhoc_deploy do |options|
  scheme = options.fetch(:scheme, "Development")
  match(type: "appstore", readonly: true)
  testflight(
    ipa: "MyApp.ipa",
    skip_waiting_for_build_processing: false
  )
end

Processo de compilação Android

Os variações de produto Android não permitem automatizar o incremento dos números de versão por variação. Para contornar isso e também manter um processo de três etapas semelhante ao iOS, o fluxo de trabalho do Android é o seguinte:

  1. Certifique-se de que o número da build do aplicativo Android seja incrementado em arquivo build.gradle para o productFlavors correspondente - “Development”, “Staging”, or “Production”.
  2. bundle exec fastlane build será executado no CI, gerando uma build do aplicativo (arquivo APK).
  3. bundle exec fastlane android adhoc_deploy env:{ENV_NAME} deve ser executado pelo desenvolvedor após o download do artefato (APK) produzido acima. ENV_NAME deve ser especificado com base no artefato baixado.
lane :build
# Same as described previously
end

lane :adhoc_deploy do |options|
  env = options.fetch(:env, "development")
  package_name = "com.myapp.development"
  apk = "myapp-development-release.apk"

  case env
    when "development"
      package_name = "com.myapp.development"
      apk = "myapp-development-release.apk"
    when "staging"
      package_name = "com.myapp.staging"
      apk = "myapp-staging-release.apk"
    when "production"
      package_name = "com.myapp"
      apk = "myapp-production-release.apk"
  end

  supply(
    track: "internal",
    apk: apk,
    package_name: package_name
  )
end

Conclusão

Cobrimos as estratégias de implantação de aplicativos móveis baseados em React Native CLI neste post. Lembre-se de como existem duas partes principais de um aplicativo React Native. O processo descrito nesta postagem se aplica principalmente à automação da implantação do contêiner do aplicativo nativo no qual o código JavaScript é empacotado durante o processo de compilação. React Native Code Push é um módulo que permite que o código JavaScript seja atualizado separadamente over-the-air, semelhante ao Expo Application Services, e automatizar implantações usando essa tecnologia pode ser uma postagem de blog separada.