Flutter mobile, web e desktop — The stars race — ptBr

Neste artigo vamos explorar a real capacidade do Flutter de com um mesmo código gerar aplicações para diferentes plataformas mobile, web e desktop.

Esse post foi originalmente escrito em blog.juliobitencourt.com.

A aplicação

As famosas estrelinhas ⭐️ nos projetos open source do GitHub são consideradas por muitos um medidor de popularidade, e embora um projeto possuir mais estrelas que o outro não signifique muita coisa, ao menos significa que a comunidade tem gostado e está acompanhando / incentivando uma determinada tecnologia.

Através de uma aplicação simples então, vamos medir essa corrida das estrelas nos projetos open source das principais tecnologias que são capazes de construir aplicações mobile multiplataforma. O layout e as funcionalidades não contém nada de extraordinário que uma aplicação em Flutter normal não tenha. Por isso não irei explicar o funcionamento do código ou recursos utilizados (apenas pontos específicos).

Mas o app contém:

  • Slivers
  • Animação com Flare
  • Requisições HTTP
  • Json parsing com json_serialazable
  • Layout simples adaptável
  • Hiperlinks (urls externas)

Abaixo uma imagem da versão web pronta, e em jhbitencourt.github.io/stars-race você pode acessar ela rodando no GithubPages para dar uma olhada. Agora vamos explorar as diferentes versões.

Mobile

Criar um projeto mobile em Flutter é fácil e todo mundo que já trabalhou com ele sabe de cor o caminho, independente da versão ou channel que você se encontra, os recursos desse app rodarão tranquilamente em Android ou iOS.

A ideia se baseia em fazer requests na API do Github para os projetos públicos e recuperar as informações e total de estrelas. As tecnologias atualmente disponíveis estão abaixo, sinta-se livre para mandar um PR com alguma outra tecnologia multiplataforma mobile que você conheça.

https://api.github.com/repos/{orgName}/{projectName}

Você pode testar acessando https://api.github.com/repos/flutter/flutter por exemplo. A API trás vários dados sobre o projeto, porém só serão usados alguns deles, conforme RepoInfo abaixo:

Para fazer o parse dos requests, é usado json_serializable. Já o estado da aplicação é gerenciado com bloc e rxdart. Então, baseado no estado atual da stream, mostramos um loading, uma mensagem de erro, ou os dados da API.

Para o loading, é mostrado a animação abaixo com algumas estrelas, construída com Flare e disponível neste link.

Já em caso de erro você verá essa mensagem:

Isso porque existe um limite de 60 requests por hora na API do GitHub para um determinado IP, então caso ultrapasse o erro é tratado. Mais sobre esse limite. Alguns locais do app existem hiperlinks que levam para páginas externas, essa é uma tarefa comum e facilmente feita com a ajuda do plugin url_launcher da própria equipe da Google, que permite acessar urls externas tanto no Android quanto iOS.

Com tudo isso pronto, ao rodar para mobile (smartphone e tablet), tudo funciona perfeitamente conforme o esperado:

  • flutter run
App rodando no smartphone
App rodando no tablet

Web

Flutter para Web ou também, Hummingbird, está atualmente em tech preview (ainda nem chegou na alpha), então definitivamente não deve ser utilizado em produção para aplicações reais. Mas isso não impede de utilizarmos para testes e já achar incrível.

Inicialmente o projeto estava separado no repositório flutter_web, o que resultava em um maior setup para funcionamento, além de problemas com nomenclatura de pacotes. Mas a partir de 10 de setembro, todo o código foi unificado no repositório original do SDK, presente no channel master, uma vez que não está estável.

Para utilização então é necessário alterar para o channel master e preferencialmente sempre manter a última release disponível.

  • flutter channel master && upgrade

Após atualização flutter config --enable-web irá habilitar a configuração para a versão web. Então basta acessar a pasta do projeto e rodarflutter create . para configurar a versão web no projeto existente.

Isso irá criar uma pasta web dentro do projeto, com um index.html, responsável por linkar o main.dart com o js.

Ao rodar flutter devices dois novos devices serão listados:

Ao utilizar o web-server será criado um servidor local em uma porta listada pelo Flutter, essa mesma porta pode ser acessada por qualquer navegador para testar a aplicação.

  • flutter run -d web-server

Já o device chrome utiliza obviamente o navegador Chrome e permite que a aplicação seja debugada.

  • flutter run -d chrome

Isso já é o suficiente para vermos a mesma aplicação rodando na web! Até mesmo a animação em Flare funcionou sem problemas (embora algumas animações aparentam não funcionar corretamente). Obviamente, muita coisa ainda tem uma aparência de mobile-like, mesmo estando na web, e há muito trabalho a ser feito. Um exemplo é o próprio pointer do mouse, que ao passar acima de um objeto clicável é esperado que ele mude visualmente.

Atualmente não temos esse tipo de comportamento out-of-the-box, e para isso é necessário utilizar uma espécie de hack. Para isso, dentro do index.html definimos um id para o body da página:

Agora é possível referenciar o body em um Widget HoverAware:

O Listener já disponibiliza vários callbacks para ações do mouse, note que atualmente onPointerHover e onPointerExit estão listados como deprecated, o que mudará brevemente, acompanhe a issue. Bastaria utilizar esse widget, e agora ao colocar e tirar o mouse de cima de área do mesmo, o tipo do cursor será alterado através da referência para o elemento do body.

Isso funciona perfeitamente ao compilar para a web, mas irá quebrar o nosso código para mobile, uma vez que ao compilar para mobile não é permitido utilizar o pacote dart:html. A solução atual é então utiliza o pacote universal_html, que funcionará como um embed de dart:html.

Criamos então um novo widget InkWellPlatformAware que estende de InkWell e insere o HoverAware caso estivermos rodando na web, validade através da constante kIsWeb.

Utilizando ele, obtemos o comportamento desejado:

Ao clicar entretanto, o link externo não irá funcionar, pois o plugin url_launcher atualmente não funciona para web. E para que funcione, é necessário utilizar novamente o universal_html:

Agora sim, tudo perfeito para rodar na web:

GitHub Pages

O GitHub Pages é uma boa opção para hospedar a nossa página com flutter web. Para isso basta gerar o build para web com:

  • flutter build web

Os arquivos serão gerados em <project_folder>\build\web:

Eu já possuo o repositório jhbitencourt.github.io no GitHub e a ideia é que o app rode em jhbitencourt.github.io/stars-race. Você pode ver aqui mais informações sobre o GHPages.

Então bastou criar uma pasta /stars-race dentro do repositório, e jogar os arquivos do build para lá, conforme aqui. E é só isso, só acessar em https://jhbitencourt.github.io/stars-race, muito simples, não?

Desktop

A missão agora é a mesma aplicação rodando no Desktop. E se o flutter web ainda está em tech preview, o embed de desktop está ainda mais imaturo. Muita coisa ainda está sendo mantida em um repositório separado flutter-desktop-embedding.

Para integrar com o nosso projeto então, também é necessário estar com o último release do channel master. Os passos que irei seguir abaixo usarão o Windows como exemplo, mas facilmente as coisas podem ser adaptadas para linux/mac, para maiores informações basta visualizar o readme do repositório oficial ou a página desktop.

Para evitar problemas, rode o prompt do windows em modo administrador. E estando na master é possível habilitar o desktop com flutter config --enable-windows-desktop. Agora ao rodar flutter doctor -v irão aparecer warnings solicitando a instalação do Visual Studio e alguns componentes que vem com ele para compilar aplicações em C++ para o windows.

É necessário fazer o download no website e instalar o que foi solicitado pelo flutter doctor. Note, Visual Studio != VS Code.

Com tudo instalado, os warnings devem sumir do flutter doctor. Talvez seja necessário reiniciar máquina para ter efeito. Agora é preciso clonar o repositório flutter-desktop-embedding para a máquina local, pois vamos precisar copiar os scripts e runners da plataforma, disponíveis nele.

Acessando o diretório \flutter-desktop-embedding\example\windows basta copiar as pastas resources, scripts e todos os arquivos. Colando os mesmos no nosso projeto, deverá ficar conforme aqui.

Para que a aplicação rode, é preciso definir o TargetPlatform antes da função runApp(), isso porque atualmente a plataforma desktop não é reconhecida automaticamente, e com o TargetPlatform nulo irão ocorrer erros.

Aqui existe um detalhe para que a aplicação continue compilando para as 3 opções. A documentação do flutter desktop diz para definir o TargetPlatform de acordo com o método a seguir:

Porém, o flutter web não possui acesso ao dart:io, assim como o mobile não possui acesso ao dart:html. E como Platform está definido em dart:io, o código acima quebra a versão para web. Por isso o primeiro código é a versão correta que garante o funcionamento em todas as compilações. Com isso já é possível rodar o app, flutter devices listará windows como um device.

Então, flutter run -d windows resulta na aplicação rodando, o quão maravilhoso isso é?

Até mesmo a animação com o Flare, as chamadas para a API, o parsing do Json, nada disso foi necessário alterar. Falta apenas um último detalhe. Os hiperlinks não estão funcionando, pois no desktop não é possível abrir um link através do universal_html e nem com o url_launcher padrão.

Atualmente o suporte a plugins no desktop não está muito bem definido como serão tratados, por conta disso os plugins existentes não são publicados no pub.dev. E sim publicados em flutter-desktop-embedding/plugins. Esses plugins estão em early-stage e provavelmente serão integrados aos existentes, ou mudados de lugar.

Para abrir uma url será usado o url_launcher_fde, um embed para o plugin original url_launcher, veja mais. Então adicionamos no pubspec:

É possível ler mais sobre os plugins aqui. Mas isso ainda não é suficiente, ainda é necessário adicionar o plugin manualmente ao Runner do windows.

Para isso abrimos o /windows/Runner.sln com o Visual Studio. Em Arquivo > Adicionar > Projeto existente.. adicione o arquivo .vcxproj do plugin. O arquivo é baixado para a máquina local no diretório <flutter_home>.pub-cache\\git\\flutter-desktop-embedding-..\\plugins\\flutter_plugins\\url_launcher_fde.

Agora em Projeto > Dependências do Projeto é necessário definir o projeto Runner como dependente de url_launcher_fde, e o projeto url_launcher_fde dependente de Flutter Build. A ordem de compilação ficará assim:

Já é possível salvar o arquivo e fechar o Visual Studio. Agora o plugin está devidamente configurado e ao rodar novamente o projeto a chamada a urls externas estará funcionando perfeitamente. o/

Observações finais:

  • Devo utilizar flutter web ou desktop em produção? Ainda não.
  • Devo utilizar flutter web ou desktop? Definitivamente sim.

Claro que precisamos realizar alguns ajustes um pouco chatos, principalmente para o desktop. Mas com essa simples aplicação é possível sentir um gostinho do que o verdadeiro flutter multiplataforma é capaz. E afinal, responde aí, em quanto tempo você acha que Flutter alcançará o primeiro lugar dessa corrida? :D

Todo o código está no GitHub, acessa lá e se curtiu deixa uma ⭐️ ;)

Flutter — Comunidade BR

Artigos escritos e voltados para a comunidade brasileira de Flutter

Julio Henrique Bitencourt

Written by

juliobitencourt.com

Flutter — Comunidade BR

Artigos escritos e voltados para a comunidade brasileira de Flutter

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade