Configurando deep linking no React Native

React Native 27 de Set de 2017

O Deep Linking possibilita que o usuário acesse seu aplicativo através de aplicações terceiras ou por links em websites acessados pelo smartphone. Vemos muito essa funcionalidade em aplicativos de GPS por exemplo.

NLW Expert | Evento gratuito de programação na prática | Rocketseat
Desafie-se em uma nova tecnologia criando um projeto completo em 3 aulas no maior evento online e gratuito de programação na prática para todos os níveis da Rocketseat.

Essa funcionalidade também permite a comunicação entre outros apps, ou seja, você pode abrir o WhatsApp, Facebook, ou qualquer outro app, diretamente da sua aplicação.

Vamos supor que você tenha criado um app de receitas e no site do seu aplicativo você possua um botão “Visualizar no app” que deve abrir a aplicação, se o usuário estiver no smartphone, já na página da receita.

Dessa forma seu app teria um endereço, uma URL, só dele, assim como um website. Vamos admitir que o aplicativo se chama “Receita Fácil”, teríamos uma URL receitafacil:// e tudo que vier depois das duas barras indica a página e parâmetros que o usuário está acessando.

Uma grande utilidade para o Deep Linking é enviar notificações push com uma URL personalizada, dessa forma, ao clicar na notificação, o usuário é destinado à página desejada e até com parâmetros personalizados.

NLW Expert | Evento gratuito de programação na prática | Rocketseat
Desafie-se em uma nova tecnologia criando um projeto completo em 3 aulas no maior evento online e gratuito de programação na prática para todos os níveis da Rocketseat.

Configurando ambiente iOS

Se você estiver utilizando um sistema OSx, pode configurar o Deep Linking no iOS. Primeiramente, abra o arquivo ios/receitafacil/AppDelegate.m e adicione o seguinte import junto aos demais:

#import <React/RCTLinkingManager.h>

Agora, no fim do arquivo, adicione o seguinte trecho de código:

- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
{
  return [RCTLinkingManager application:application openURL:url
                      sourceApplication:sourceApplication annotation:annotation];
}

Seu arquivo deve ficar muito parecido com esse.

A partir disso, nosso app está preparado pra receber deep linking, mas ainda precisamos informar qual a URL que nosso aplicativo reconhecerá (no nosso caso vai ser receitafacil://).

Agora no XCode, abra seu projeto, na barra lateral esquerda clique sobre o projeto e nas abas superiores selecione a aba Info. No fim da aba, na opção URL Types, adicione a URL da seguinte forma:

Configurando ambiente Android

Vamos começar configurando o Android para permitir Deep Linking abrindo o arquivo android/app/src/main/AndroidManifest.xml e adicionando um novo intent-filter ao XML:

<intent-filter>
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="receitafacil"
        android:host="receitafacil" />
</intent-filter>

Seu arquivo deve ficar parecido com esse.

Veja que no Android temos um host que será o prefixo antes do :// e temos também um scheme, que virá logo após as duas barras, para só depois disso vir o resto da nossa URL, então vamos acessar algo parecido com a seguinte URL no Android: receitafacil://receitafacil/pagina/parametro

Utilizando react-navigation (recomendado)

NLW Expert | Evento gratuito de programação na prática | Rocketseat
Desafie-se em uma nova tecnologia criando um projeto completo em 3 aulas no maior evento online e gratuito de programação na prática para todos os níveis da Rocketseat.

Durante esse exemplo, vou utilizar a biblioteca React Navigation para identificar a página correta recebida pelo link, mas a funcionalidade de Deep Linking é do React Native, então você pode utilizar a lib que preferir (explico isso no próximo tópico). O código desse exemplo está disponível no Github.

Vamos começar criando nossa aplicação e instalando o React Navigation:

react-native init receitafacil

yarn add react-navigation

Agora, crie uma pasta src ao seu projeto com um arquivo index.jsdentro. Vamos utilizar esse arquivo index.js como ponto de entrada para aplicação (assim não precisamos de um index para cada plataforma).

Nos seus arquivos index.android.js e index.ios.js, substitua o conteúdo por esse:

import { AppRegistry } from 'react-native';
import App from './src';

AppRegistry.registerComponent('receitafacil', () => App);

Dentro da pasta src crie uma nova pasta chamada pages com dois arquivos dentro, list.js e recipe.js:

/* Core */
import React, { Component } from 'react';

/* Presentational */
import { View, Platform, Linking } from 'react-native';

export default class List extends Component {
  static navigationOptions = {
    title: 'Lista de receitas',
  };

  render() {
    return <View />
  }
}
/* Core */
import React, { Component } from 'react';

/* Presentational */
import { View, Text } from 'react-native';

export default class Recipe extends Component {
  static navigationOptions = {
    title: 'Detalhe da receita'
  };

  render() {
    const { params } = this.props.navigation.state;

    return (
      <View>
        <Text>Você acessou a receita: {params.recipe}</Text>
      </View>
    );
  }
}

Note que no segundo arquivo, estamos buscando o parâmetro “recipe” da rota e exibindo-o em tela. Agora no seu arquivo index.js na pasta src, utilize o seguinte código:

import React from 'react';
import { Platform } from 'react-native';
import { createStackNavigator } from 'react-navigation';

import List from './pages/list';
import Recipe from './pages/recipe';

const Router = createStackNavigator({
  List,
  Recipe: {
    screen: Recipe,
    path: 'recipe/:recipe',
  },
});

const prefix = (Platform.OS === 'ios')
  ? 'receitafacil://'
  : 'receitafacil://receitafacil/';

export default () => <Router uriPrefix={prefix} />;

Aqui definimos um navigator com duas rotas (list e recipe). Como a página recipe é a que queremos acessar via URL, definimos um path para ela. Logo abaixo definimos o prefixo de URL utilizado no iOS e no Android (lembre que o Android possui o scheme além do host, então o nome repete mesmo).

Estamos dizendo para a página recipe ouvir a URL recipe/nome-da-receitae nomear o parâmetro após a barra como “recipe”.

Agora com o emulador aberto podemos fazer os testes utilizando a linha de comando.

NLW Expert | Evento gratuito de programação na prática | Rocketseat
Desafie-se em uma nova tecnologia criando um projeto completo em 3 aulas no maior evento online e gratuito de programação na prática para todos os níveis da Rocketseat.

Testando no Android

No Android podemos utilizar o adb para testar a URL:

adb shell am start -W -a android.intent.action.VIEW -d "receitafacil://receitafacil/recipe/teste" com.receitafacil

Testando no iOS

No iOS podemos tanto utilizar a linha de comando:

xcrun simctl openurl booted receitafacil://recipe/teste

Ou podemos acessar diretamente pelo Safari do emulador:

Sem react-navigation

Caso você não esteja usando react-navigation, os passos de configuração para Android e iOS são os mesmos, porém no código você terá que ouvir a URL inicial acessada no app e redirecionar o usuário conforme o conteúdo dela, inclusive passar os parâmetros enviados.

Para isso, sua página inicial (no nosso caso list) ficará mais ou menos assim:

/* Core */
import React, { Component } from 'react';

/* Presentational */
import { View, Platform, Linking } from 'react-native';

export default class List extends Component {
  async componentDidMount() {
    if (Platform.OS === 'android') {
      const url = await Linking.getInitialURL();
      this.navigate(url);
    } else {
      Linking.addEventListener('url', this.handleOpenURL);
    }
  }

  componentWillUnmount() {
    Linking.removeEventListener('url', this.handleOpenURL);
  }

  handleOpenURL = (event) => {
    this.navigate(event.url);
  };

  navigate = (url) => {
    const { navigate } = this.props.navigation;
    const route = url.replace(/.*?:\/\//g, '');
    const recipe = route.match(/\/([^\/]+)\/?$/)[1];
    const routeName = route.split('/')[0];
  
    // routeName: recipe
    // recipe: teste (parâmetro)
  };

  render() {
    return <View />
  }
}

No método componentDidMount eu acesso a URL inicial e no Android posso chamar diretamente a função navigate, já no iOS precisamos assinar ao evento url da classe Linking para receber a string com a URL.

Abaixo na função navigate, nós quebramos a URL recebida utilizando Javascript para identificar as partes em forma de variável, dessa forma, temos uma variável para o nome da rota (routeName) e o nome da receita acessada (recipe). Caso tiver mais parâmetros, você pode utilizar as próximas posições no array que a variável recipe utiliza.

E por hoje é só

Nesse post aprendemos a configurar o Deep Linking no React Native utilizando, ou não, o react-navigation. Lembrando que essa técnica é muito interessante para notificações push ou interações com outras aplicações (como login no Facebook).

Código do projeto: https://github.com/Rocketseat/blog-react-native-deep-linking

NLW Expert | Evento gratuito de programação na prática | Rocketseat
Desafie-se em uma nova tecnologia criando um projeto completo em 3 aulas no maior evento online e gratuito de programação na prática para todos os níveis da Rocketseat.

Marcadores

Diego Fernandes

Programador full-stack, apaixonado pelas melhores tecnologias de desenvolvimento back-end, front-end e mobile, é co-fundador e CTO na Rocketseat.