🔗Deep Links

Neste guia, vamos explorar o que são deep links, como configurá-los no Flutter para iOS e Android, e como criar e utilizar uma classe helper para facilitar o gerenciamento de deep links no seu app

Deep links são URLs que direcionam os usuários para partes específicas de um aplicativo, em vez de simplesmente abrir a tela inicial. Eles são úteis para:

  • Integração com marketing: Direcionar usuários para promoções, produtos ou conteúdos específicos.

  • Compartilhamento de conteúdo: Permitir que usuários compartilhem links que abrem diretamente em uma tela específica do app.

  • Melhorar a experiência do usuário: Reduzir o número de passos necessários para acessar um recurso.

Exemplo de deep link: https://meuapp.com/produto/123 pode abrir diretamente a tela de detalhes do produto com ID 123.


2.1. Configuração no Android

Passo 1: Adicionar Intent Filters no AndroidManifest.xml

No arquivo android/app/src/main/AndroidManifest.xml, adicione o seguinte dentro da tag <activity> da sua atividade principal:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="http" android:host="@string/deep_link_host" />
	<data android:scheme="https" />
</intent-filter>
  • O que isso faz?

    • Define que a atividade pode ser aberta por um link (android.intent.action.VIEW).

    • Configura o domínio (meuapp.com) e o esquema (https) que serão usados para os deep links.

Passo 2: Configuração dos flavors

Para configurar o @string/deep_link_host, no diretório android/app/src/, crie pastas para cada flavor (se ainda não existirem). Por exemplo:

  • android/app/src/flavor1/

  • android/app/src/flavor2/

Dentro de cada pasta, crie um arquivo res/values/strings.xml para definir o valor de deep_link_host específico para cada flavor.

Exemplo para flavor1:

Arquivo: android/app/src/flavor1/res/values/strings.xml

<resources>
    <string name="deep_link_host">flavor1.meuapp.com</string>
</resources>

Exemplo para flavor2:

Arquivo: android/app/src/flavor2/res/values/strings.xml

<resources>
    <string name="deep_link_host">flavor2.meuapp.com</string>
</resources>
  • O que isso faz?

    • Define o valor de deep_link_host como flavor1.meuapp.com para flavor1.

    • Define o valor de deep_link_host como flavor2.meuapp.com para flavor2.


Passo 3: Configurar o assetlinks.json

Para que o Android valide automaticamente os deep links, você precisa hospedar um arquivo assetlinks.json no seu domínio. Ele deve estar acessível em https://meuapp.com/.well-known/assetlinks.json.

Exemplo de assetlinks.json:

[{
  "relation": ["delegate_permission/common.handle_all_urls"],
  "target": {
    "namespace": "android_app",
    "package_name": "com.seuapp",
    "sha256_cert_fingerprints": ["SEU_FINGERPRINT_AQUI"]
  }
}]
  • O que isso faz?

    • Associa o domínio meuapp.com ao seu aplicativo Android.

    • Substitua com.seuapp pelo pacote do seu app e SEU_FINGERPRINT_AQUI pelo fingerprint SHA-256 do seu certificado.


2.2. Configuração no iOS

Passo 1: Adicionar a Capacidade "Associated Domains"

  1. No Xcode:

    • Abra o projeto iOS no Xcode (ios/Runner.xcworkspace).

    • Selecione o target Runner e vá para a aba Signing & Capabilities.

    • Clique no botão + Capability e adicione Associated Domains.

  2. Configurar os Domínios:

    • Na seção Associated Domains, adicione os domínios que você deseja associar ao aplicativo.

    • O formato é applinks:<domínio>.

    Exemplo:

    • Para flavor1, adicione:

      applinks:flavor1.meuapp.com
    • Para flavor2, adicione:

      applinks:flavor2.meuapp.com
  3. No Apple Developer Portal:

    • Acesse o portal Apple Developer.

    • Vá para Certificates, Identifiers & Profiles > Identifiers.

    • Selecione o identificador do seu aplicativo.

    • Habilite a capacidade Associated Domains e adicione os mesmos domínios configurados no Xcode.

Passo 2: Hospedar o Arquivo apple-app-site-association

  1. Crie o Arquivo:

    • Crie um arquivo chamado apple-app-site-association (sem extensão).

    • O conteúdo do arquivo deve seguir o formato JSON e associar o domínio aos IDs dos aplicativos (um para cada flavor).

    Exemplo:

    {
      "applinks": {
        "apps": [],
        "details": [
          {
            "appID": "<team_id>.com.seuapp",
            "paths": ["*"]
          },
        ]
      }
    }
    • Substitua <team_id> pelo seu Team ID (encontrado no Apple Developer Portal).

    • Substitua com.seuapp.flavor1 e com.seuapp.flavor2 pelos bundle IDs dos seus flavors.

  2. Hospede o Arquivo:

    • O arquivo deve ser hospedado no diretório .well-known do seu domínio.

    • O caminho completo deve ser: https://<domínio>/.well-known/apple-app-site-association.

    Exemplo:

    • Para flavor1, o arquivo deve estar acessível em:

      https://flavor1.meuapp.com/.well-known/apple-app-site-association
    • Para flavor2, o arquivo deve estar acessível em:

      https://flavor2.meuapp.com/.well-known/apple-app-site-association
  3. Dicas:

    • O arquivo não deve ter extensão (por exemplo, .json).

    • O servidor deve servir o arquivo com o tipo MIME application/json.

    • Se você não tem um servidor, pode usar o Firebase Hosting para hospedar o arquivo.


3. Criando e Utilizando uma Classe Helper

Agora que configuramos os deep links, vamos criar uma classe helper para facilitar o gerenciamento deles no Flutter.

3.1. Criando a Classe DeepLinksHelper

A classe DeepLinksHelper encapsula toda a lógica de deep links, desde a inicialização até o processamento. Aqui está o código completo:

import 'package:app_links/app_links.dart';
import 'dart:async';

class DeepLinksHelper {
  // Singleton pattern
  static final DeepLinksHelper _instance = DeepLinksHelper._internal();
  factory DeepLinksHelper() => _instance;
  DeepLinksHelper._internal();

  late final AppLinks _appLinks;
  late final StreamSubscription<Uri>? _linkSubscription;
  final StreamController<bool> _homePageReadyController = StreamController<bool>.broadcast();
  Uri? _initialUri;

  // Inicializa o sistema de deep links
  Future<void> initDeepLinks() async {
    _appLinks = AppLinks();
    _linkSubscription = _appLinks.uriLinkStream.listen((Uri uri) {
      print('Deep link recebido: $uri');
      _initialUri = uri;
      _homePageReadyController.stream
          .firstWhere((isReady) => isReady)
          .then((_) {
        _handleIncomingLink();
      });
    });
  }

  // Notifica que a página inicial está pronta
  void notifyHomePageReady() {
    _homePageReadyController.add(true);
  }

  // Processa o link recebido
  void _handleIncomingLink() {
    if (_initialUri != null) {
      print('Processando deep link: $_initialUri');
      // Adicione a lógica para navegar para a tela correta com base no URI.
      _initialUri = null;
    }
  }

  // Cancela a inscrição no stream de deep links
  void cancelSubscription() {
    _linkSubscription?.cancel();
  }
}

3.2. Explicação dos Métodos

  • initDeepLinks(): Inicializa o sistema de deep links e começa a escutar por links recebidos.

  • notifyHomePageReady(): Notifica que a página inicial está pronta para processar o deep link.

  • _handleIncomingLink(): Processa o link recebido. Aqui você pode adicionar a lógica para navegar para a tela correta com base no URI.

  • cancelSubscription(): Cancela a inscrição no stream de deep links para evitar vazamentos de memória.


4. Utilizando o DeepLinksHelper no Seu App

4.1. Inicialização no main.dart

No arquivo main.dart, inicialize o DeepLinksHelper e passe a instância para o MaterialApp:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  final deepLinksHelper = DeepLinksHelper();
  await deepLinksHelper.initDeepLinks();
  runApp(MyApp(deepLinksHelper: deepLinksHelper));
}

class MyApp extends StatelessWidget {
  final DeepLinksHelper deepLinksHelper;

  const MyApp({Key? key, required this.deepLinksHelper}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(deepLinksHelper: deepLinksHelper),
    );
  }
}

4.2. Notificação na HomePage

Na HomePage, notifique quando a página estiver pronta:

class HomePage extends StatefulWidget {
  final DeepLinksHelper deepLinksHelper;

  const HomePage({Key? key, required this.deepLinksHelper}) : super(key: key);

  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  void initState() {
    super.initState();
    widget.deepLinksHelper.notifyHomePageReady();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Home')),
      body: Center(child: Text('Bem-vindo ao app!')),
    );
  }
}

4.3. Processamento do Link

No método _handleIncomingLink, adicione a lógica para navegar para a tela correta com base no URI:

void _handleIncomingLink() {
  if (_initialUri != null) {
    print('Deep link recebido: $_initialUri');
    // Exemplo: Navegar para uma tela específica com base no caminho do URI.
    if (_initialUri!.path == '/produto') {
      Navigator.push(context, MaterialPageRoute(builder: (_) => ProductPage()));
    }
    _initialUri = null;
  }
}

4.4. Cancelamento da Inscrição

No dispose do widget, cancele a inscrição:

@override
void dispose() {
  widget.deepLinksHelper.cancelSubscription();
  super.dispose();
}

Agora que você configurou os deep links e a classe DeepLinksHelper, é hora de testar se tudo está funcionando corretamente.

5.1. Testando no Emulador Android

Usando o Comando adb

  1. Certifique-se de que o emulador está rodando.

  2. Execute o comando abaixo no terminal:

    adb shell am start -W -a android.intent.action.VIEW -d "https://flavor1.meuapp.com/details" com.seuapp.flavor1
    • Substitua https://flavor1.meuapp.com/details pelo seu deep link.

    • Substitua com.seuapp.flavor1 pelo applicationId do flavor que você está testando.

  3. Verifique o log no Android Studio para confirmar que o deep link foi recebido.

5.2. Testando no Emulador iOS

Usando o Comando xcrun simctl openurl

  1. Certifique-se de que o emulador iOS está rodando.

  2. Execute o comando abaixo no terminal:

    xcrun simctl openurl booted "https://flavor1.meuapp.com/details"
    • Substitua https://flavor1.meuapp.com/details pelo seu deep link.

  3. Verifique o log no Xcode para confirmar que o deep link foi recebido.


Conclusão

Com essa abordagem, você terá um sistema de deep links robusto e organizado no seu aplicativo Flutter. A classe DeepLinksHelper facilita o gerenciamento dos links, permitindo que você se concentre na lógica do seu app. Agora é só testar e adaptar para o seu caso de uso! 🚀

Last updated