x

Enviando e/ou recebendo eventos do JS para o Nativo e do Nativo para o JS

Jose Urbano Duarte Junior
5 min readJun 2, 2017

No meu último post, eu demonstrei como rodar duas aplicações React-Native dentro de um único aplicativo Android. Nesse post, eu irei um pouco além e apresentarei como trocar mensagens entre essas aplicações.

Veremos como enviar uma mensagem da camada JavaScript para a camada Java e como enviar uma mensagem da camada Java para a camada JavaScript.

Esse post servirá para você que quer continuar brincando com o exemplo do post anterior, para você que tem uma aplicação React-Native integrada a uma aplicação nativa e para você que tem uma aplicação desenvolvida totalmente dentro do mundo JS.

Mão na massa

Lado Nativo

Para começar, clone o repositório que fiz para vocês. Vamos analisar juntos o que está sendo feito. Depois, vocês mesmos poderão criar e enviar suas mensagens. Aqui recomendo que você leia o post anterior para entender um pouco melhor algumas ideias e funcionalidades desse projeto.

O primeiro passo para enviar uma mensagem é criar uma classe que estenda a classe ReactPackage. Nesse projeto criei a classe MyPackage. Ela basicamente permite que você crie uma interface para módulos JavaScript, controladores de Views e módulos nativo. Entretanto, nest post vamos focar no módulo nativo, pois é o que precisamos para enviar mensagens de um lado para outro.

Aqui é importante entender que um único ReactPackage pode conter milhares de módulos. O que normalmente irá restringir a quantidade de módulos expostos em um único pacote é a arquitetura desejada. Suponha que um dos seus pacotes exponha as fotos do usuário para o lado JavaScript. Você gostaria, mesmo, que qualquer aplicação JavaScript tenha acesso a esses dados? Nos meus projetos, eu acabo criando meus pacotes baseado em funcionalidades, privilégios e acessos.

Observe no exemplo abaixo, como adicionar um pacote ao gerenciador de instâncias React-Native. Nesse projeto, eu adicionei dois pacotes: o pacote MainReactPackage que contém todos os componentes básicos do React-Native e meu próprio pacote, o Mypackage. Assim, para restringir o acesso de uma instância há um pacote, basta não adicionar o pacote à instância.

Tudo bem, até aqui acredito que você já esteja entendendo um pouco sobre o conceito de ReactPackage e como adicioná-los à uma instancia React, mas precisamos ainda explorar como criar os módulos que compõem um pacote.

Para isso é preciso estender a classe ReactContextBaseJavaModule e sobrescrever o método getName() dando um nome ao meu módulo nativo. Abaixo segue um trecho do código da minha classe.

Observe que o nome do meu módulo é MyNativeModule e que ele está expondo uma função para a camada JavaScript. Essa função é chamada setMessageToApp1 e está marcada com a annotation @ReactMethod.

Nela temos três parâmetros: o primeiro que seria a mensagem enviado pelo lado JS, o segundo seria um callback retornado ao JS em caso de sucesso no envio da mensagem e o terceiro seria um callback em caso de erro.

Dentro dessa classe, é usado também um Objeto WritableMap. Ele funciona com JSON a ser devolvido para o lado JS. Nesse caso meu objeto devolvido será: {message: 'qualquer texto'}. Segue um link que mapeia objetos trocados entre o JS e o Java.

Finalmente para enviar a mensagem para o lado JS, é preciso definir um tópico para publicarmos nossa mensagem. O primeiro passo para isso é recuperaremos o contexto React da aplicação que receberá a mensagem. Basicamente estamos fazendo um broadcast para todos os listeners que estiverem escutando esse tópico dentro da aplicação alvo.

Nesse exemplo, utilizei um método acessório simplório da minha Activity para recuperar o gerenciador de instâncias React e a partir dele chegar no ReactContext. Lembre-se, aqui que cada aplicação React-Native tem seu próprio contexto, então emita o sinal no contexto certo.

Lado JS

Com a parte nativa pronta, podemos começar a implementar o lado JS. Para isso é preciso importar alguns módulos React-Native no seu projeto. Importe, então, o módulo NativeModules e o DeviceEventEmitter.

Feito isso, utilize o NativeModules para importar o seu módulo nativo e, posteriormente, cadastrar um listener para o tópico desejado.

O exemplo acima, ilustra como isso funciona. Veja que eu cadastrei um listener para o mesmo tópico em que estou emitindo meus sinais (Ps: isso já deveria estar claro… (ಠ益ಠ) )

Agora que já temos alguém ouvindo, precisamos efetivamente emitir o sinal (chamar o método Java). A imagem abaixo mostra como emitir um sinal quando um botão for clicado.

Observe que utilizei o MyNativeModule chamando uma função criada e exposta no Nativo. Para essa função foram passados três parâmetros conforme interface definida previamente. Uma message e dois callbacks.

Resultado Final

Nesse projeto demonstrei como enviar e receber eventos tanto na camada JS quanto na camada nativa. Observe que a comunicação funcionou da seguinte maneira:

O resultado final foi:

O resultado é simples, mas começamos a ver cenários ainda mais empolgantes para React-Native.

Considerações

As técnicas de troca de mensagens desse post podem ser muito melhor exploradas. Crie seus próprios métodos, brinque com diferentes interfaces e retorne diferente tipos de objetos para o JavaScript.

--

--

Jose Urbano Duarte Junior

Mestre em "Computação — Mobility" na Carnegie Mellon University, especialista em Gestão Estratégica de TI pela FGV e entusiasta por empreendedorismo