Desenvolvendo um plugin para flutter

Wes Guirra
Flutter — Comunidade BR

--

Fala Galera! Espero que esteja tudo bem com vocês e suas famílias durante este período que estamos passando.

Estou há algum tempo sem passar insights por aqui, mas estou de volta! E dessa vez não vou falar de React mas de Flutter.

Recentemente estou trabalhando bastante com Flutter dentro do contexto de aplicações mobile e me deparei com o desafio de desenvolver uma camada de comunicação entre o app Flutter e uma biblioteca nativa, decidi por fazer essa comunicação através do desenvolvimento de um plugin Flutter, na ocasião eu precisei utilizar bibliotecas Java nativas, uma vez que ainda não existia uma solução para Flutter ou Dart.

O primeiro passo não foi em si o desenvolvimento, mas sim entender de cabo a rabo o funcionamento, os métodos, os parâmetros necessários e os possíveis retornos da biblioteca Java, a minha ideia era desenvolver um plugin com o mesmo padrão, para que assim qualquer pessoa que já tivesse utilizado a biblioteca Java pudesse entender com facilidade como utilizar o plugin flutter.

O projeto em questão se tratava do desenvolvimento de um app para máquinas de débito/crédito que rodam android como sistema operacional, Esse app deve se integrar com o sistema de pagamentos da máquina de débito e isso é feito através dessa biblioteca:

Após entender a documentação da biblioteca, precisei buscar por alguns recursos um guia inicial de como construir essa biblioteca, o qual você pode encontrar aqui:

Basicamente utilizei a cli do flutter para criar o código inicial do plugin com o comando abaixo:

flutter create --org <id-do-pacote> --template=plugin -a java <nome-do-pacote>

Na ocasião o nome do meu pacote era flutter_paystore_client, e a org br.com.enjoyin.

então meu comando ficou assim:

flutter create --org br.com.enjoyin --template=plugin -a java flutter_paystore_client

Isso cria um projeto de plug-in em uma nova pasta no diretório atual com o nome que você escolheu para o pacote com o seguinte conteúdo:

lib/<nome-do-pacote>.dart 
A API do Dart para o plug-in.
android/src/main/java/<org>/<nomedopacote>/<NomeDoPacoteEmPascalCase>Plugin.kt
A implementação específica da plataforma Android da API do plug-in no Kotlin.
ios/Classes/<NomeDoPacoteEmPascalCase>Plugin.m
A implementação específica da plataforma iOS da API do plug-in no Objective-C.
example/
Um aplicativo Flutter que depende do plug-in e ilustra como usá-lo.

Por padrão, o projeto do plug-in usa o código Swift para iOS e o código Kotlin para Android. Se você preferir Objective-C ou Java, poderá especificar a linguagem do iOS usando -i e a linguagem do Android usando -a. Por exemplo:

flutter create --template=plugin -i objc helloflutter create --template=plugin -a java hello

Após criar o código inicial para o Plugin será necessário implementar os métodos para que esse plugin suporta, será necessário conhecimento especifíco da linguagem nativa em questão, no meu caso era Java que é tranquilo pra mim.

O primeiro passo do desenvolvimento foi recriar as models Java no Dart.

da uma olhada aqui nesse repo onde tem todas as classes recriadas com base na biblioteca original:

Com as models necessárias implementadas o passo seguinte foi desenvolver os métodos disponíveis no plugin no caso desse plugin foram uns 5 métodos.

vamos implementar uma classe dart com os métodos dentro do arquivo .dart criado no início, abaixo você pode checar como ficou a implementação da classe com os métodos.

Na linha 8 criamos o channel para fazer a comunicação com os métodos nativos que estão na implementação Java do nosso plugin.

O suporte à API específico da plataforma integrada do Flutter não depende da geração de código, mas de um estilo flexível de transmissão de mensagens.

Como alternativa, o pacote Pigeon pode ser usado para enviar mensagens tipadas seguras estruturadas por meio da geração de código:

  • A parte Flutter do aplicativo envia mensagens para seu host, a parte iOS ou Android do aplicativo, através do Platform Channel.
  • O host possui um listener no através do Platform Channel e recebe a mensagem. Em seguida, ele invoca as APIs específicas da plataforma usando a linguagem de programação nativa e envia uma resposta de volta ao cliente, a parte Flutter do aplicativo.
Mensagens e respostas são transmitidas de forma assíncrona, para garantir que a interface do usuário permaneça responsiva

na linha 20 da classe dart estou invocando um método nativo através da api do Channel: invokeMethod.

Esta API invoca um método no channel nativo com os argumentos especificados.

O tipo estático dos argumentos é dynamic, mas apenas valores suportados pelo [codec] deste canal pode ser usado. O mesmo se aplica aos valores retornados.

você pode checar os tipos suportados no link abaixo:

O nosso metodo deve Retornar uma Future que pode possuir o seguinte resultado:

* um resultado (possivelmente nulo), na chamada bem-sucedida;
* a [PlatformException], se a chamada falhar no código especifico da plataforma (iOS ou Android);
* a [MissingPluginException], se o método não tiver sido implementado no código especifico da plataforma (iOS ou Android).

O Próximo passo é trabalhar na implementação nativa no meu caso Java, vamos utilizar a classe nativa para identificar e executar o código nativo solicitado pela API Flutter.

Após realizar essa chamada utilizando invokeMethod o método nativo será chamado, abaixo temos a nossa classe com o código nativo em Java:

A nossa classe nativa implementa a classe MethodCallHandler essa classe possui um método onMethodCall esse método recebe dois parâmetros a chamada que é uma instância de MethodCall e uma instância da classe Result que será responsável por enviar os valores de volta para o flutter.

Dentro da nossa instância de MethodCall temos a propriedade method que é uma String com o nome do método que estamos chamando.

Tudo que eu preciso fazer agora é validar os nomes dos métodos que estão sendo chamados e executar o código nativo correspondente.

O meu começa na linha 49, da classe Java, da uma olhada lá.

Você pode fazer isso de várias formas pois ai já se trata da implementação nativa do plugin, no meu caso eu fiz algumas validações condicionais direto no nome do método e mantive tudo dentro do mesmo arquivo, importei as classes necessárias e executei o código ali mesmo, você pode como no meu caso utilizar alguma biblioteca de terceiros ou mesmo utilizar alguma biblioteca nativa Android ou iOS.

Por fim você irá utilizar a instância do Result para retornar o valor para o flutter, lembra que nosso método flutter é uma Future? pois é, esse result vai voltar para o flutter dentro daquela Future como resultado.

É isso! vou deixar abaixo a biblioteca que criei para a Paystore caso você esteja implementando alguma solução mobile com Flutter para a máquina PAX A920 vai te ajudar bastante.

Espero que tenha ajudado e que o conteúdo seja de bom uso, Agradeço muito pela sua leitura, e peço que apoie essa iniciativa clicando algumas vezes no botão de aplausos, isso me ajuda bastante a entender que meu conteúdo está sendo lido e me incentiva a continuar escrevendo sobre React e Flutter aqui no Medium.

Obrigado e até a próxima.

--

--

Wes Guirra
Flutter — Comunidade BR

Desde que me entendo por gente, procuro maneiras de inovar para melhorar o mundo em que vivemos.