Alguns meses atrás, por causa de uma necessidade aqui na Red Ventures (onde trabalho atualmente), me deparei com essa pergunta:
Como transformar uma aplicação React em um aplicativo (iOS e Android) de uma maneira rápida, que aproveite o codebase atual e seja escalável?
Logo de cara, notamos que seria necessário usar um browser para renderizar a aplicação já existente e alguma ferramenta para gerar tanto o aplicativo Android como o iOS com a mesma codebase, mas ainda existiam algumas dúvidas:
A aplicação está em constante mudança. Desse modo, faz sentido uma soluçao como Cordova/Phonegap, que para qualquer alteração seria necessário soltar uma atualização na loja?
Caso a aplicação tenha engajamento, como faremos para escalar para um aplicativo nativo sem precisar matar tudo de uma vez e começar do zero? Como faremos essa transição gradual caso for preciso?
A partir daí, comecei a realizar algumas pesquisas e fazer algumas POC’s.
Por não facilitar a atualização do aplicativo e não ser escalável para uma experiência nativa, concluímos em não seguir com Cordova/Phonegap, mas ir para um caminho que tivesse esses benefícios. Porém, nossa aplicação web, apesar de já estar preparada para uso mobile, ainda precisava de alguns ajustes para o uso em aplicativo, como por exemplo uma tela inicial específica.
Então resolvemos gerar duas aplicações com o mesmo processo de build existente da aplicação web, por exemplo:
Aplicação já existente: https://meusite.com.br/
Nova aplicação: https://meusite.com.br/app/
As duas aplicações seguiram exatamente com o mesmo codebase, a única diferença foi a necessidade de disponibilizar uma variável global dentro da aplicação em tempo de build informando o valor “App” ou “Web”, o que na prática foi só adicionar mais um passo no processo de build/deploy. Com isso foi possível criar condições como qual tela inicial mostrar.
Com a parte web resolvida e depois de alguns outros testes, decidi fazer uma POC com React Native (uma ferramenta do Facebook que muita gente conhece ou já ouviu falar), pois resolveria o problema da geração do app para Android e iOS e eu já tinha um conhecimento básico prévio. Em menos de uma hora, a POC já tinha atendido quase todas as necessidades, mas ainda faltava uma coisa para fechar a solução: a comunicação entre o nativo e o browser.
Olhando a documentação da ferramenta, descobri que quando o React Native monta um componente WebView, ele sempre injeta um método chamado ReactNativeWebView.postMessageno window da página que foi carregada, dessa maneira eu consegui fazer minha aplicação web passar informações para o nativo e vice-versa.
Olha só essa lista de coisas que foram possíveis fazer por causa dessa comunicação:
Escalabilidade. Posso agora ter em paralelo tanto telas nativas feitas diretamente no React Native como telas da aplicação web
Escutar o evento de backPressque é disparado quando o botão de voltar do celular é acionado
Usar o push notification
Usar as features de biometria, como o faceId
Executar qualquer outra função nativa
Essa solução resolveu muito bem o problema e espero que ajude na criação de novas soluções para quem está lendo!
Vou deixar abaixo o link para o próximo post, onde irei mostrar como construir do zero, passo a passo, toda a estrutura que eu descrevi ao longo desse artigo, com uma aplicação web que utilizará React, mas que pode ter como base qualquer outra biblioteca ou até mesmo vanilla.
]]>Para essa primeira parte vamos precisar criar dois projetos, um para a aplicação web que será feita em React e outro para a aplicação nativa que será feita com React Native.
Não será abordado o setup inicial para rodar as aplicações React e React Native, mas você pode ler sobre isso aqui.
Para este artigo, eu criarei somente um repositório no Github, mas em um caso real onde terá outras pessoas codando, eu prefiro quebrar em dois repositórios para ficar mais organizado.
No fim deste artigo há a URL para o repositório, caso queira pular o passo a passo.
Para facilitar a criação desse artigo e não misturar com outros assuntos e conceitos, irei usar o CRA (create-react-app) para iniciarmos um projeto React.
Vamos lá!
npx create-react-app web
Com o projeto criado, iremos colocar variáveis de ambiente no script de start e build para diferenciarmos nossa aplicação web e nativa quando precisarmos e adicionar um arquivo de estilos já pronto que vou deixar disponível aqui. Basta copiar e salvar no arquivo index.css.
Agora precisamos criar um útil para recebermos essa informação, então irei criar uma pasta utils, e um arquivo chamado isApp.js com o seguinte código:
Com isso pronto, irei adicionar o react-router-dom para criarmos nossas rotas. Caso queira se aprofundar na biblioteca, você pode encontrar mais informações aqui.
yarn add react-router-dom ou npm install react-router-dom
Arquivo: App.js
Como mostrado nó código acima, separei em outros arquivos o Root, Home e About para deixar mais organizado.
> Arquivo: ./pages/Home/index.js
> Arquivo: ./pages/About/index.js
> Arquivo: Root.js
No código acima, importei um módulo que eu criei chamado postMessage. Esse módulo tem a responsabilidade de se comunicar diretamente com o lado nativo via o método ReactNativeWebView.postMessage, que é inserido no window, assim usamos ele para sempre avisar o aplicativo nativo quando uma rota foi alterada e qual é a nova rota atual. Mais para baixo irei mostrar um caso real de onde podemos usar essa informação.
> Arquivo: utils/postMessage.js
Com essa comunicação podemos fazer várias outras coisas, como alternar entre uma página nativa e uma página web por exemplo.
Agora com a parte web já preparada, podemos criar o nosso projeto React Native!
O comando abaixo vai iniciar o projeto, ele pode demorar um pouco dependendo da sua conexão.
npx react-native init app --template react-native-web-to-native-template
Reparem no parâmetro –template, onde eu passo o nome do boilerplate que deixei preparado com algumas coisas que iremos precisar.
Com o projeto criado, iremos abrir o arquvio webview.js que se encontrará no caminho src > constants > webview.js para atualizarmos a URL inicial do aplicativo o rootUrl. Como estamos trabalhando localmente, iremos colocar localhost com a porta default que o CRA criou para nossa aplicação web que foi a 3000, ficando dessa maneira abaixo:
export const rootUrl = 'http://localhost:3000/'
Agora iremos rodar o projeto e ver como está!
yarn ios ou yarn android
Com o nosso aplicativo rodando, agora podemos perceber no topo da tela que a barra superior do sistema não bate com a cor da aplicação. De acordo com o estilo já adicionado no começo do artigo, as cores são:
Com isso, iremos usar a informação que mandamos via postMessage para conseguir manipular a cor do sistema conforme a página atual. Mas antes, iremos ver como a comunicação via postMessage funciona do lado do aplicativo e, para ficar claro, terei que passar por alguns arquivos.
> Trecho do arquivo: src/pages/Main/index.js (A página que renderiza o WebView)
No trecho acima, podemos perceber o uso do onMessage, o callback que o componente WebView irá chamar quando o método ReactNativeWebView.postMessage for executado. No nosso caso estamos passando o handleOnMessage como callback, então vamos ver o que ele está fazendo.
> Trecho do arquivo: src/pages/Main/hooks/useWebview.js (Um custom hook que estamos chamando no src/pages/Main/index.js)
No nosso callback, recebemos o evento e conseguimos extrair a informação que foi passada da nossa aplicação web acessando o event.nativeEvent.data. Como enviamos um json formatado como string, pois o postMessage só aceita string, agora podemos transformar nossa string para json de volta.
O messageEvents faz um papel bem importante de roteamento. Como o método que estamos usando para comunicação não nos fornece nenhuma estrutura (ele apenas transmite texto de um lado para o outro), foi preciso criar essa estrutura de roteamento para facilitar a nossa vida e deixar mais organizado. Na nomenclatura vou usar o termo event para facilitar o entendimento.
> Arquivo: src/utils/messageEvents/index.js
Como mostrado acima, usei RamdaJS para criar essa estrutura (também poderia ser feita com switch case), que pega a propriedade eventName passada da aplicação web e endereça a função que vai receber e lidar com os dados. No caso atual estamos lidando somente com o routeChange que criamos, então vamos entender o que ele está fazendo.
> Arquivo: src/utils/messageEvents/routeChange.js
O routeChange verifica se o href existe e, caso exista, ele atualiza o estado que informa a url atual e também atualiza o status do canGoBack, que é quem controla se o app pode ou não fechar em uma ação de voltar.
Com tudo isso pronto e explicado, agora temos a informação da url atual no lado do React Native e podemos manipular a cor do sistema para que sempre fique igual ao topo da aplicação web.
> Arquivo: src/pages/Main/hooks/propsMapper.js
No custom hooks acima, pegamos a url atual que é passada para ele, extraimos a url limpa de query strings e passamos para a função getUrlToStatusBarColor, que está mapeando as urls e as respectivas cores e então retornamos isso diretamente para o componente Main que vai passar para o componente StatusBar.
> Trecho do arquivo: src/constants/webview.js
Estamos adicionando no código acima as cores no mapa por url.
> Trecho do arquivo: pages/Main/index.js
No código acima, passamos a propriedade da cor para o StatusBar e para o SafeAreaView para de fato fazer as cores alterarem, vamos ver como ficou! Se você já estiver com o projeto rodando é só atualizar, se não tiver é só rodar o yarn ios ou yarn android ou olhar o gif abaixo:
Repositório com o código que desenvolvemos aqui nesse artigo.
Encerro por aqui esse artigo, mas se quiser saber mais sobre essa implementação, leia a primeira parte desse post, onde mostro como chegamos nessa solução, o motivo e os ganhos que você pode ter caso esteja em um cenário parecido.
Espero que consigam adaptar no cenário de vocês e qualquer dúvida ou sugestão estarei respondendo os campos de comentários, obrigado!
Método postMessage que o React Native injeta no window
Parâmetro onMessage do componente WebView
Repositório com o código do artigo
Método postMessage do componente WebView
Parte um desse artigo
Fiz um vídeo explicando o básico das duas ferramentas, mas para quem preferir ler, continue lendo que farei um resumo em texto também!
Figma
Design.io / Gravit.io
Acredito que essas ferramentas, mesmo sendo ótimas e MUITO intuitivas elas não tomaram o espaço de ferramentas já conhecidas no mercado, como Sketch e as ferramentas da adobe em geral, mas para usuário mais “casuais”, que não nescessariamente são designers, mas que também precisam prototipar alguma coisa antes de sair fazendo, com certeza essas ferramentas terão seu espaço para essas pessoas.
Pontos positivos
Pontos negativos
Esse blog é opensource!! Então caso veja algo errado ou queira acrescentar algo é so criar uma issue ou mandar um PR lá no github!
]]>Projeto open source, feito com foco em espalhar o conhecimento, e para o uso do dia-a-dia!
gulp watch
Esse projeto está disponível no Github e com o coração aberto para pull request :D