Concrete Logo
Hamburger button

As diferentes abordagens para aplicativos multiplataforma

  • Blog
  • 13 de Abril de 2018
Share

Se você é um desenvolvedor Android ou iOS, provavelmente, já passou muito tempo conversando sobre quais frameworks multiplataforma valem a pena. Eles são considerados o “El Dorado” do desenvolvimento mobile. Isso me lembra as boas e velhas promessas como o WORA (Write Once Run Anywhere). Aaah bons tempos…

Em todo o caso, a realidade é dura. Sonhos não se tornam realidade com tanta frequência e nós temos um instinto natural de duvidar de qualquer propaganda. Então vamos conversar sobre a história desse esforço e sobre três tentativas de resolver a questão. Mas, antes, vamos entender melhor o problema.

Desenvolvimento Front-end

Toda a discussão surge do problema de apresentar ideias aos usuários finais. Pense na sua mãe usando um serviço digital. Não importa qual é o serviço, qualquer pessoa que não é um cara de tecnologia que gosta de interfaces UNIX  – algo como

– provavelmente vai precisar de algum front-end para o serviço (a propósito, eu gosto das interfaces UNIX).

É por isso que a Xerox inventou a interface gráfica do usuário (Graphical User Interface), e enquanto eles eram os únicos com uma “GUI” não havia disputa nenhuma entre plataformas. Mas, à medida em que o princípio do caos humano evolui (acabei de inventar isso), muitos ambientes gráficos competitivos são “inventados”.

De qualquer forma, a questão é que um sistema operacional (seja Linux, Android, Windows, MacOS, RedoxOS ou qualquer outro) oferece os meios para a interface com gráficos, áudio e pipeline de entrada, e cabe aos desenvolvedores criarem o que chamamos de widget toolkits, que vão saber como mostrar a interface, reproduzir os sons e receber as entradas.

Até no desktop isso é um problema. Algumas aplicações funcionam no Windows, Linux e no MacOS usando ferramentas de widget que funcionam em todos eles. Alguns são bem conhecidos (pelo menos pelos usuários Linux), como:

  • GTK (Gnome Toolkit)
  • QT
  • WxWidgets

Eles fornecem os “tijolos” para as aplicações, como botões, visualizações de textos, etc. e trabalham bem, mas têm algumas desvantagens, como:

  • Aparência e comportamento nativos: como não surpreender o usuário sobre como parece seus controles gráficos;
  • Algumas APIs são antigas e associadas a gráficos, áudios e sistemas de entrada;
  • Eles não renderizam interfaces remotas.

Então, para dar suporte a uma nova plataforma você tem que criar a infraestrutura desses toolkits nos drivers do novo SO (sistema operacional). Se for open source, isso pode envolver algum tempo e esforço para convencer o time a dar suporte à nova plataforma.

Entretanto, com a “World Wide Web” surge uma nova necessidade: mostrar interfaces remotas. Isso é, quando você quer acessar um serviço digital em um servidor que está muito longe você precisa enviar a interface para o computador daquela pessoa. Isso tudo começou com documentos simples ligados uns aos outros (cada link faria download da próxima página) e evoluiu para interações assíncronas por meio de AJAX, WebSocket, long polling e assim por diante.

O negócio é: hoje nós usamos mais interfaces remotas do que locais. Ok, eu não fiz uma pesquisa gigante sobre isso, então deixe-me reformular:

A maior parte dos serviços possui uma interface remota ou um back-end remoto para atender à interface local.

Para participar da internet os desenvolvedores precisaram desenvolver navegadores que pudessem primeiro renderizar esses documentos estáticos e só depois todas as especificações do ECMAScript.

Primeira onda do cross mobile

Inicialmente a ideia de rodar o mesmo código em plataformas diferentes só foi possível com JavaScript, HTML e CSS e na tela mobile. É isso: um website em um aplicativo. Pense como se fosse uma fina camada em torno do navegador.

Por que alguém gostaria de fazer isso? Bom, como já falamos na seção de front-end, toda plataforma tem um componente chamado de WebView: uma view que renderiza JavaScript, HTML e CSS. Então, com uma base de código nós poderíamos ter uma aplicação rodando em cada webview da plataforma. Nice and dandy 🙂

Acontece que há alguns problemas nessa abordagem:

  • Qual versão do JavaScript é boa o suficiente para todas as plataformas?
  • Como interfacear com features nativas que não são expostas por meio de uma API JS?
  • Performance desta abordagem apps nativos de verdade?
  • Novas features de cada plataforma assim que elas forem lançadas?

Existem inúmeros artigos com as armadilhas deste tipo de esforço multiplataforma. Mesmo assim, eles evoluíram muito e algumas grandes empresas apostaram neles. Aqui tem uma pequena lista de possibilidades:

A principal ideia aqui é que um navegador já tem seu toolkit de apresentação. Eles já precisam se conectar ao pipeline de gráficos, áudio, entradas e tudo o mais. Desenvolvedores só precisariam falar a linguagem web e então começariam construindo aplicações mobile da mesma forma.

A palavra chave “NATIVO”

A experiência web, porém, é difrente de uma interface nativa. Para renderizar tudo com 60 frames por segundo não é fácil e não são todos os smartphones que podem fazer isso embaixo do componente WebView. Animações começam a se tornar um gargalo e outras particularidades começam a aparecer, o que pode fazer com que a abordagem da webview seja um problema para muitas pessoas.

A alternativa é um transpiler. Sim, isso mesmo, não é um typo. TRANSPILER (origem para o compilador de origem). Nós compilamos um código fonte para rapidamente criar um novo código fonte =)

O quê? Por que alguém iria querer fazer isso? Bom, isso é mais comum do que a maioria das pessoas pensa.

Typescript é uma linguagem que compila para JavaScript, por exemplo. Mas de novo, por quê? Porque você pode adicionar features ou traduzir de uma fonte para a outra.

Essa abordagem era especial porque você poderia desenvolver um site usando alguma coisa como React e depois usar react-native para transpilar para fontes nativas. Então, sua aplicação em JavaScript teria todos os benefícios da renderização nativa.

Na prática, quando você codifica um texto em um componente HTML react-native ele será transformado em um TextView em Android. Ooops… Parece que o problema foi resolvido, certo?

Bem, mais ou menos. Você ainda precisa saber sobre as necessidades de cada plataforma se você quiser interfacear com um serviço, sistema ou se você precisa debugar as coisas mais profundamente.

Outra questão é que algumas coisas não são bem traduzidas. Eu sou brasileiro e sempre ouvi a história de que “saudade” não tem tradução para o inglês. O que nós fazemos quando queremos expressar “saudade”? Traduzimos a palavra em toda uma sentença que praticamente explica o significado de “saudade” (algo como “I miss you”), mas que não é exatamente a mesma coisa.

Exemplos de frameworks que usam essa abordagem:

A nova onda do desenvolvimento mobile

(Iron Flutter! Brincadeira… piada heavy metal interna “New Wave of British Heavy Metal”)

Algumas pessoas já solucionaram o problema do desenvolvimento multiplataforma há algum tempo. Eles não estavam desenvolvendo documentos de ligações estáticas, mas estavam resolvendo renderização em tempo real de milhares de polígonos. Quem são eles? Os desenvolvedores de jogos!

Pense: você realmente acha que pessoas que desenvolvem jogos para Playstation, XBox, Nintendo Switch e etc. têm um repositório diferente com uma base de código diferente para cada plataforma? Você acha que eles desenvolvem com foco em apenas uma delas e depois reescrevem tudo em diferentes linguagens para o Steam OS, por exemplo?

A resposta é não. Mais ou menos não 😉

É claro que eles devem levar em conta features específicas de plataformas específicas, mas a maior parte do código é focada em um “motor de jogo” (game engine). Vou deixar alguns exemplos de game engines aqui. Se você tiver a chance de buscar rapidamente suas páginas de “features” você vai ver que a resposta estava aqui desde o princípio.

Todos eles seguem uma arquitetura parecida:

  • Sempre têm uma linguagem de programação e seu ambiente de execução (Java, C#, C++, etc.)
  • Se conectam profundamente a plataformas específicas de gráficos, áudio e de APIs de entrada;
  • Têm ferramentas para gerar um binário otimizado para cada plataforma;
  • NÃO usam o widget toolkit da plataforma. Antes de começar eles perguntam ao sistema: “dê uma janela e um canvas no qual eu possa ter o controle, o resto é comigo!” Eles têm seu PRÓPRIO pipeline de gráficos, renderização de texto, manuseio de entrada e etc. É como um ambiente FULL, que roda acima da plataforma de hospedagem.

Calma, calma, calma… qual é a diferença entre os transpiladores? Bom, essa abordagem evita a necessidade de traduzir para uma LINGUAGEM ou toolkit específico. Tudo isso está no nível mais baixo das coisas (debaixo do toolkit) e por isso não precisa funcionar com nenhuma impedância de plataforma.

Ou seja, não é um compilador de um código fonte em outro código fonte. É um compilador para binário. Roda na ABI (Abstract Binary Interface) ao invés do que na API (Abstract Public Interface).

É por isso que motores de jogos são tão performáticos, eles podem implementar suas próprias otimizações.

Pois bem, agora é o momento da verdade: e se, ao invés de fazer um motor de JOGOS nós fizéssemos um motor de APLICAÇÕES?

Com isso, quero dizer: incorporamos uma pilha inteira de gráficos (Skia, por exemplo), um mecanismo de renderização de texto inteiro (HarfBuzz, por exemplo) e assim por diante. Com isso, poderíamos desenvolver um ambiente de execução com uma única linguagem para diferentes plataformas. Enquanto Skia e Harfbuzz puderem ser executados na plataforma, nosso ambiente de execução estará seguro.

Essa é a abordagem do Flutter. E eu espero que agora você entenda porque é uma abordagem diferente da react-native atual, por exemplo.

É claro que nada é perfeito. Qual é o tamanho da minha aplicação se eu embarcar tudo isso? Bem, com certeza será maior do que se nós fizermos tudo na mão em cada plataforma.  Além disso, nem todos os serviços de sistemas têm uma API comum para todas as plataformas. Essas questões sempre vão existir em soluções multiplataforma.

O que nós deveríamos olhar são as vantagens. Com o Flutter nós conseguimos:

  • Hot-code deploy, sem necessidade de esperar que o Gradle construa algo, ou de se preocupar com o Instant Run e se isso funciona com processadores do anotações Java;
  • Uma abordagem nova para lidar com eventos mobile: rotação de tela, persistência do estado, ciclo de vida da aplicação e etc.;
  • Um novo mecanismo de layout, mais fácil e mais moderno de trabalhar;
  • Não se preocupar com compatibilidade de versões antigas;
  • Não se preocupar com limite de Dex no Android;
  • e assim por diante…

Bons tempos para se viver… Certo?

Engine toolkit

Se você leu tudo até agora você deve estar se perguntando: este negócio de Flutter não é como os toolkits da seção de front-end? Bom, sim e não. É uma extensão do mesmo conceito: vamos plugar no sistema baixo nível para providenciar widgets. É uma extensão de como isso pluga no sistema e como roda até o fim, mas o conceito é similar.

Então por que nós não usamos GTK ou QT para isso? Bom, na verdade, algumas pessoas já fazem exatamente isso.

Nós temos outras plataformas sendo construídas todos os dias (lembre-se do princípio do caos humano) e algumas delas estão usando esses toolkits plugados em drivers ou especificações gráficas como OpenGL, OpenGL ES, Vulkan e outras.

Nós tentamos com tecnologias web porque todo mundo precisa de uma webpage. Agora o browser vai começar a falar WASM (Web Assembly), e talvez nós possamos ter esses toolkits e tempos de execução para a web também.

Para concluir: o princípio do caos humano diz que nós sempre estaremos inventando novas coisas que não são de todo novas. A maior parte do tempo nós estamos reinventando coisas do passado com uma cabeça mais fresca. É como se nós soubéssemos que este momento chegaria e então teríamos completado o ciclo =)

Discorda, concorda ou tem algo a dizer? Aproveite os campos abaixo.
Até a próxima!

Nós somos a Concrete, empresa parte da Accenture, e estamos em constante movimento. Trabalhamos junto às maiores empresas do Brasil para garantir os melhores produtos digitais do mercado. Para isso, usamos design, desenvolvimento ágil e nossa cultura de inovação. Trabalhe com os melhores: concrete.com.br/vagas