<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Cristian Dornelles</title>
    <description>The latest articles on Forem by Cristian Dornelles (@cdornelles).</description>
    <link>https://forem.com/cdornelles</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F197395%2F68925fb8-bf0e-4b22-92cd-72f65f9ad21d.jpg</url>
      <title>Forem: Cristian Dornelles</title>
      <link>https://forem.com/cdornelles</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/cdornelles"/>
    <language>en</language>
    <item>
      <title>Checkpoint da Série: o que já funciona, o que quebrou e para onde vamos (Parte 4.5)</title>
      <dc:creator>Cristian Dornelles</dc:creator>
      <pubDate>Tue, 14 Apr 2026 17:26:53 +0000</pubDate>
      <link>https://forem.com/cdornelles/checkpoint-da-serie-o-que-ja-funciona-o-que-quebrou-e-para-onde-vamos-parte-45-52nf</link>
      <guid>https://forem.com/cdornelles/checkpoint-da-serie-o-que-ja-funciona-o-que-quebrou-e-para-onde-vamos-parte-45-52nf</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ulucega5s77zfl8z9sz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6ulucega5s77zfl8z9sz.png" alt="Header" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quatro posts, três plataformas, um bug encontrado em produção.&lt;/p&gt;

&lt;p&gt;Antes de seguir para App Links e Universal Links no ar de verdade — com domínio, verificação bidirecional e os problemas que só aparecem fora do emulador — vale um respiro para ver o que já existe e o que ainda falta.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que construímos até aqui
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Post 1 — A fundação conceitual
&lt;/h3&gt;

&lt;p&gt;Tipos de deep link, diferenças entre custom scheme, App Links e Universal Links, e a estrutura base em Dart. Nada de pacote externo — só entender o problema antes de escrever código.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@crdornelles/deep-links-em-flutter-o-guia-definitivo-para-iniciantes-parte-1-d56ea3619192" rel="noopener noreferrer"&gt;Parte 1 — O Guia para Iniciantes&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 2 — Android nativo
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AndroidManifest.xml&lt;/code&gt; com &lt;code&gt;intent-filter&lt;/code&gt; para custom scheme e HTTPS. &lt;code&gt;MainActivity.kt&lt;/code&gt; registrando os canais nativos — &lt;code&gt;MethodChannel&lt;/code&gt; para cold start, &lt;code&gt;EventChannel&lt;/code&gt; para app em execução.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/p/562bb353b3b2?postPublishedType=initial" rel="noopener noreferrer"&gt;Parte 2 — Android com Kotlin&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 3 — iOS nativo
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Info.plist&lt;/code&gt; com &lt;code&gt;CFBundleURLTypes&lt;/code&gt;, &lt;code&gt;Runner.entitlements&lt;/code&gt; com Associated Domains e &lt;code&gt;AppDelegate.swift&lt;/code&gt; espelhando a mesma lógica de canais do Android.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@crdornelles/deep-links-no-ios-implementa%C3%A7%C3%A3o-nativa-com-swift-flutter-parte-3-d37569fd0a15" rel="noopener noreferrer"&gt;Parte 3 — iOS com Swift&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 4 — Integração Flutter
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;DeepLinkService&lt;/code&gt; como ponto único de entrada: &lt;code&gt;MethodChannel&lt;/code&gt; busca o link inicial, &lt;code&gt;EventChannel&lt;/code&gt; recebe links com o app aberto, &lt;code&gt;StreamController.broadcast()&lt;/code&gt; distribui para quem estiver ouvindo. A &lt;code&gt;SignupPage&lt;/code&gt; pré-preenche o referral code e mostra um indicador visual quando o dado veio de um link.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://medium.com/@crdornelles/conectando-tudo-integra%C3%A7%C3%A3o-flutter-com-deep-links-nativos-parte-4-b9b23c6e32e5" rel="noopener noreferrer"&gt;Parte 4 — Integração Flutter&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  O bug que encontramos na prática
&lt;/h2&gt;

&lt;p&gt;Durante os testes do Post 4, o app abria normalmente mas o referral code nunca aparecia. Nenhum erro, nenhum log — o deep link simplesmente sumia.&lt;/p&gt;

&lt;p&gt;A causa: race condition com &lt;code&gt;StreamController.broadcast()&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  O problema na prática
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ como estava — evento perdido&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// link emitido aqui...&lt;/span&gt;
&lt;span class="n"&gt;_deepLinkSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deepLinkStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; &lt;span class="c1"&gt;// listener registrado tarde demais&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ✅ como ficou — listener primeiro&lt;/span&gt;
&lt;span class="n"&gt;_deepLinkSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deepLinkStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; &lt;span class="c1"&gt;// ouvindo antes de qualquer evento&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// link emitido com listener ativo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O &lt;code&gt;broadcast()&lt;/code&gt; não bufferiza. Se nenhum listener estiver ativo no momento em que o evento é emitido, ele se perde. A ordem importa.&lt;/p&gt;

&lt;p&gt;Esse é o tipo de bug que não aparece em log, não quebra o app, e passa despercebido até produção.&lt;/p&gt;




&lt;h2&gt;
  
  
  Onde estamos agora
&lt;/h2&gt;

&lt;p&gt;O fluxo ponta a ponta já funciona:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Android&lt;/strong&gt; → captura o intent corretamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iOS&lt;/strong&gt; → captura a URL corretamente&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Flutter&lt;/strong&gt; → recebe via &lt;code&gt;MethodChannel&lt;/code&gt; / &lt;code&gt;EventChannel&lt;/code&gt; e processa&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt; → reage ao deep link com o referral code pré-preenchido&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aryuswehzs26svybxti.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9aryuswehzs26svybxti.png" alt="Fluxo ponta a ponta" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mas ainda falta o mais difícil: fazer isso funcionar fora do ambiente de desenvolvimento.&lt;/p&gt;

&lt;p&gt;Código completo: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt; — branch &lt;code&gt;post/04-flutter&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Para onde vamos
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Post 5 — Produção de verdade
&lt;/h3&gt;

&lt;p&gt;App Links no Android e Universal Links no iOS exigem verificação bidirecional de domínio. Sem isso, o link abre no navegador em vez do app. Vamos configurar o &lt;code&gt;assetlinks.json&lt;/code&gt; e o &lt;code&gt;apple-app-site-association&lt;/code&gt;, entender o que o sistema verifica e o que fazer quando a verificação falha.&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 6 — Deferred Deep Links
&lt;/h3&gt;

&lt;p&gt;O usuário clica no link mas não tem o app instalado. Vai para a loja, instala, abre — e o referral code sumiu. O deferred deep link resolve isso. Vamos implementar com &lt;code&gt;LocalStorage&lt;/code&gt; no lado web e uma estratégia simples no backend.&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 7 — Página de redirect inteligente
&lt;/h3&gt;

&lt;p&gt;Uma página HTML que detecta a plataforma, tenta abrir o app, e redireciona para a loja se não conseguir. O elo que conecta o link compartilhado ao app instalado.&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 8 — Testes e troubleshooting
&lt;/h3&gt;

&lt;p&gt;Checklist de deploy, como testar cada cenário (cold start, app aberto, link inválido), e os erros mais comuns com App Links e Universal Links — incluindo os que só aparecem depois do deploy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Post 9 — Refatoração com Clean Architecture
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;DeepLinkHandler&lt;/code&gt; como alternativa ao &lt;code&gt;DeepLinkService&lt;/code&gt; atual — separando responsabilidades, facilitando testes e preparando o código para crescer sem virar bagunça.&lt;/p&gt;




&lt;p&gt;Se você chegou agora, os quatro primeiros posts constroem a fundação do zero. Se acompanhou desde o início, os próximos cinco levam para produção — com os problemas reais que aparecem quando o domínio precisa estar verificado e o usuário ainda não tem o app.&lt;/p&gt;




&lt;p&gt;Código completo disponível no repositório: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Se esse conteúdo te ajudou, deixa um ❤️ ou um 🔖 aqui no DEV.to — isso ajuda o post a alcançar mais devs.&lt;/p&gt;

&lt;p&gt;E você, já implementou deep links no seu app?&lt;/p&gt;

&lt;p&gt;Qual foi o maior desafio que encontrou?&lt;/p&gt;

&lt;p&gt;Quero usar esses casos reais nos próximos posts da série 👇&lt;/p&gt;

&lt;p&gt;Tags: Flutter, Dart, MethodChannel, Deep Links, Mobile Development&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Conectando Tudo: Integração Flutter com Deep Links Nativos (Parte 4)</title>
      <dc:creator>Cristian Dornelles</dc:creator>
      <pubDate>Sat, 11 Apr 2026 14:23:51 +0000</pubDate>
      <link>https://forem.com/cdornelles/conectando-tudo-integracao-flutter-com-deep-links-nativos-parte-4-5blb</link>
      <guid>https://forem.com/cdornelles/conectando-tudo-integracao-flutter-com-deep-links-nativos-parte-4-5blb</guid>
      <description>&lt;p&gt;Se você já tentou integrar deep links no Flutter usando código nativo, provavelmente passou por isso:&lt;/p&gt;

&lt;p&gt;o Android recebe o link…&lt;br&gt;&lt;br&gt;
o iOS também…&lt;/p&gt;

&lt;p&gt;mas o Flutter simplesmente não reage.&lt;/p&gt;

&lt;p&gt;Ou pior:&lt;br&gt;
funciona no cold start… mas não funciona com o app aberto.&lt;/p&gt;

&lt;p&gt;É exatamente esse problema que vamos resolver agora.&lt;/p&gt;

&lt;p&gt;Dando continuidade à série sobre Deep Links no Flutter, com novos artigos saindo semanalmente, ou quase. Se você ainda não viu os posts anteriores: &lt;a href="https://medium.com/p/d56ea3619192?postPublishedType=initial" rel="noopener noreferrer"&gt;Post 1 — Guia para Iniciantes&lt;/a&gt; | &lt;a href="https://medium.com/p/562bb353b3b2?postPublishedType=initial" rel="noopener noreferrer"&gt;Post 2 — Android com Kotlin&lt;/a&gt; | &lt;a href="https://medium.com/@crdornelles/deep-links-no-ios-implementa%C3%A7%C3%A3o-nativa-com-swift-flutter-parte-3-d37569fd0a15" rel="noopener noreferrer"&gt;Post 3 — iOS com Swift&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;Neste artigo, você vai aprender:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como implementar DeepLinkService com MethodChannel e EventChannel no Flutter.&lt;/li&gt;
&lt;li&gt;Por que usar StreamController.broadcast() para eventos de deep link.&lt;/li&gt;
&lt;li&gt;Como pré-preencher a UI automaticamente a partir de um link.&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  DeepLinkService no Flutter
&lt;/h2&gt;

&lt;p&gt;A solução é ter um ponto único de entrada para todos os deep links no app — o &lt;code&gt;DeepLinkService&lt;/code&gt;. Ele fala com o código nativo em dois momentos distintos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Via &lt;strong&gt;&lt;code&gt;MethodChannel&lt;/code&gt;&lt;/strong&gt;: quando o app abre e precisamos saber se havia um link pendente (app estava fechado).&lt;/li&gt;
&lt;li&gt;Via &lt;strong&gt;&lt;code&gt;EventChannel&lt;/code&gt;&lt;/strong&gt;: stream contínuo para links recebidos enquanto o app já está em execução.
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/services/deep_link_service.dart&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:async'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'dart:io'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="s"&gt;'package:flutter/services.dart'&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeepLinkService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;DeepLinkService&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeepLinkService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;DeepLinkService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;DeepLinkService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;_internal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;MethodChannel&lt;/span&gt; &lt;span class="n"&gt;_methodChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;MethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'com.fitconnect.app/deeplink'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;EventChannel&lt;/span&gt; &lt;span class="n"&gt;_eventChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'com.fitconnect.app/deeplink_stream'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;StreamController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DeepLinkData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="n"&gt;StreamController&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;broadcast&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;_initialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DeepLinkData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;deepLinkStream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_initialized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;_initialized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Busca deep link inicial (app estava fechado)&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;initialUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;_methodChannel&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;invokeMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'getInitialLink'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialUrl&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_parseDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialUrl&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Stream para links quando app está aberto&lt;/span&gt;
    &lt;span class="n"&gt;_eventChannel&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;receiveBroadcastStream&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_parseDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;_controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nl"&gt;onError:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// Log ou tratamento&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nl"&gt;cancelOnError:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;DeepLinkData&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_parseDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DeepLinkData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;url:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;_determineType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nl"&gt;scheme:&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;host:&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;path:&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;queryParameters:&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryParameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;referralCode:&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;queryParameters&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'referralCode'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="nl"&gt;receivedAt:&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;DeepLinkType&lt;/span&gt; &lt;span class="n"&gt;_determineType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Uri&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scheme&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'fitconnect'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;customScheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;scheme&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'https'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;host&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'fitconnect.app'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Platform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;isIOS&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;universalLink&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;appLink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Como esse controller vive durante todo o ciclo de vida do app, não fazemos o close manual — mas em serviços descartáveis isso seria obrigatório.&lt;/p&gt;

&lt;p&gt;Esse padrão também facilita testes e evolução futura (ex: analytics, tracking, feature flags baseadas em deep link).&lt;/p&gt;

&lt;p&gt;Mas mais importante do que isso -&lt;/p&gt;

&lt;p&gt;na prática, o DeepLinkService funciona como uma camada de tradução:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fird2y3615q2pa4tq5tb9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fird2y3615q2pa4tq5tb9.png" alt="Camada de tradução" width="800" height="147"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ele isola completamente o restante da aplicação da complexidade de cada plataforma.&lt;/p&gt;
&lt;h3&gt;
  
  
  Por que StreamController.broadcast()?
&lt;/h3&gt;

&lt;p&gt;Um &lt;code&gt;StreamController&lt;/code&gt; padrão só permite um listener. Se o app tiver múltiplas telas ouvindo deep links ao mesmo tempo — ou se o listener for registrado após o evento ser emitido — o evento se perde. O &lt;code&gt;.broadcast()&lt;/code&gt; resolve os dois problemas: aceita múltiplos listeners e não lança exceção se nenhum estiver ativo no momento do evento.&lt;/p&gt;
&lt;h3&gt;
  
  
  A responsabilidade de cada canal
&lt;/h3&gt;

&lt;p&gt;O &lt;code&gt;_methodChannel&lt;/code&gt; faz uma chamada pontual — &lt;code&gt;getInitialLink&lt;/code&gt; — e retorna uma vez. É o suficiente para o cenário de cold start. Já o &lt;code&gt;_eventChannel&lt;/code&gt; permanece aberto como um stream; qualquer link recebido com o app em execução chega por ele. Juntos, cobrem todos os cenários sem sobreposição.&lt;/p&gt;
&lt;h3&gt;
  
  
  O método _parseDeepLink
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;Uri.parse&lt;/code&gt; decompõe a URL em partes (&lt;code&gt;scheme&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;path&lt;/code&gt;, &lt;code&gt;queryParameters&lt;/code&gt;) sem nenhuma dependência externa. A partir daí, montamos o &lt;code&gt;DeepLinkData&lt;/code&gt; com os campos que o app vai precisar — incluindo o &lt;code&gt;referralCode&lt;/code&gt; extraído diretamente dos query parameters. Se a URL for inválida, o método retorna &lt;code&gt;null&lt;/code&gt; e o link é ignorado silenciosamente.&lt;/p&gt;
&lt;h3&gt;
  
  
  Evitando processamento duplicado no Flutter
&lt;/h3&gt;

&lt;p&gt;Dependendo da plataforma, o mesmo deep link pode chegar mais de uma vez (especialmente em cold start).&lt;/p&gt;

&lt;p&gt;Uma estratégia simples é manter o último link processado e ignorar duplicados —&lt;br&gt;
principalmente em cenários onde o mesmo evento pode chegar via MethodChannel e EventChannel.&lt;/p&gt;


&lt;h2&gt;
  
  
  Integrando no ciclo de vida do app
&lt;/h2&gt;

&lt;p&gt;Com o &lt;code&gt;DeepLinkService&lt;/code&gt; pronto, a integração acontece no widget raiz do app.&lt;/p&gt;

&lt;p&gt;É aqui que conectamos o serviço ao ciclo de vida da aplicação.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/app_widget.dart&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;_AppState&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;StreamSubscription&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;_deepLinkSub&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initState&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;_initDeepLinks&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_initDeepLinks&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DeepLinkService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Listener registrado antes de initialize() para não perder&lt;/span&gt;
    &lt;span class="c1"&gt;// o evento de cold start emitido durante a inicialização&lt;/span&gt;
    &lt;span class="n"&gt;_deepLinkSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deepLinkStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;'/signup'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;referralCode&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_handleSignupLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;_handleSignupLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DeepLinkData&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;WidgetsBinding&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addPostFrameCallback&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;Navigator&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;pushNamed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/signup'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delayed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;milliseconds:&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;read&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SignupController&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
      &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setReferralCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;referralCode&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nd"&gt;@override&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="n"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;_deepLinkSub&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="na"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Atenção: a ordem importa
&lt;/h3&gt;

&lt;p&gt;Repare que o listener é registrado &lt;strong&gt;antes&lt;/strong&gt; de chamar &lt;code&gt;initialize()&lt;/code&gt;. Isso não é acidente.&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;StreamController.broadcast()&lt;/code&gt; não bufferiza eventos — se nenhum listener estiver ativo no momento em que o evento é emitido, ele se perde silenciosamente. E o &lt;code&gt;initialize()&lt;/code&gt; pode emitir o link inicial (cold start) ainda durante sua execução.&lt;/p&gt;

&lt;p&gt;Se você inverter a ordem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ errado — o evento de cold start é perdido&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// evento emitido aqui...&lt;/span&gt;
&lt;span class="n"&gt;_deepLinkSub&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;deepLinkStream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt; &lt;span class="c1"&gt;// ...mas o listener só existe aqui&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O app abre, o link chega no Android/iOS, mas o Flutter nunca reage. Nenhum erro, nenhum log — o deep link simplesmente some.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;O uso de &lt;code&gt;Future.delayed&lt;/code&gt; aqui é uma simplificação didática. Em produção, o ideal é desacoplar navegação e estado — via state management (MobX, Bloc, etc.) ou via evento disparado após o build da tela. Isso elimina dependência de timing arbitrário e condições de corrida entre navegação e UI.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O &lt;code&gt;StreamSubscription&lt;/code&gt; precisa ser cancelado no &lt;code&gt;dispose&lt;/code&gt; para evitar memory leaks. Como o widget raiz raramente é removido da árvore, na prática isso raramente é acionado — mas é uma boa prática que vale manter.&lt;/p&gt;




&lt;h2&gt;
  
  
  UI da SignupPage
&lt;/h2&gt;

&lt;p&gt;A última peça é a tela de cadastro. O campo de referral code precisa de uma decisão de UX clara: mostrar ao usuário que o dado veio de um link, mas permitir que ele edite se quiser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/features/signup/signup_page.dart&lt;/span&gt;

&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;controller:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;referralCodeController&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;InputDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;labelText:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cameFromDeepLink&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;'Código de Indicação (via link)'&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Código de Indicação (opcional)'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;suffixIcon:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;cameFromDeepLink&lt;/span&gt;
        &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;green&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;maxLength:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;enabled:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Sempre editável&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O campo é sempre editável — mesmo quando pré-preenchido por deep link. O label e o ícone mudam para dar contexto ao usuário, mas nunca bloqueamos a edição. Travar o campo criaria fricção desnecessária: e se o usuário cometeu um erro no código de indicação ou quer usar outro?&lt;/p&gt;




&lt;h2&gt;
  
  
  Fluxo completo
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6kfchz1aca0608uce4y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6kfchz1aca0608uce4y.png" alt="Fluxo completo" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;A partir daqui, o deep link deixa de ser um detalhe técnico.&lt;/p&gt;

&lt;p&gt;Ele passa a ser parte da experiência do usuário.&lt;/p&gt;

&lt;p&gt;O app não apenas abre.&lt;/p&gt;

&lt;p&gt;Ele entende o contexto.&lt;/p&gt;




&lt;p&gt;No próximo post, vamos sair do ambiente de desenvolvimento e ir para produção:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;App Links funcionando de verdade no Android&lt;/li&gt;
&lt;li&gt;Universal Links validados no iOS&lt;/li&gt;
&lt;li&gt;Verificação bidirecional com domínio&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;É aqui que começam os problemas reais de produção:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domínio não verificado corretamente&lt;/li&gt;
&lt;li&gt;link abrindo no navegador em vez do app&lt;/li&gt;
&lt;li&gt;comportamento inconsistente entre Android e iOS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;E é exatamente isso que vamos resolver.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que construímos até aqui
&lt;/h2&gt;

&lt;p&gt;Ao final desta etapa, você já tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;code&gt;DeepLinkService&lt;/code&gt; como ponto único de entrada para deep links no Flutter.&lt;/li&gt;
&lt;li&gt;Integração com &lt;code&gt;MethodChannel&lt;/code&gt; (cold start) e &lt;code&gt;EventChannel&lt;/code&gt; (app em execução).&lt;/li&gt;
&lt;li&gt;Roteamento automático para a &lt;code&gt;SignupPage&lt;/code&gt; com o referral code pré-preenchido.&lt;/li&gt;
&lt;li&gt;A decisão de UX de manter o campo sempre editável, com indicador visual de origem.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este é o quarto de 9 posts da série. Com Android, iOS e Flutter integrados, o fluxo ponta a ponta já funciona — mas ainda em ambiente de desenvolvimento. No próximo post, vamos colocar isso em produção: configurar App Links no Android e Universal Links no iOS com verificação bidirecional de domínio. Se você já teve dor de cabeça com essa etapa, conta nos comentários — vou usar isso no Post 5.&lt;/p&gt;




&lt;p&gt;Código completo disponível no repositório: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Se esse conteúdo te ajudou, deixa um ❤️ ou um 🔖 aqui no DEV.to — isso ajuda o post a alcançar mais devs.&lt;/p&gt;

&lt;p&gt;E você, já implementou deep links no seu app?&lt;/p&gt;

&lt;p&gt;Qual foi o maior desafio que encontrou?&lt;/p&gt;

&lt;p&gt;Quero usar esses casos reais nos próximos posts da série 👇&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Tags: Flutter, Dart, MethodChannel, Deep Links, Mobile Development&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Deep Links no iOS: Implementação Nativa com Swift + Flutter (Parte 3)</title>
      <dc:creator>Cristian Dornelles</dc:creator>
      <pubDate>Wed, 08 Apr 2026 12:38:20 +0000</pubDate>
      <link>https://forem.com/cdornelles/deep-links-no-ios-implementacao-nativa-com-swift-flutter-parte-3-1521</link>
      <guid>https://forem.com/cdornelles/deep-links-no-ios-implementacao-nativa-com-swift-flutter-parte-3-1521</guid>
      <description>&lt;p&gt;No post anterior, configuramos o Android para capturar deep links usando Kotlin. Agora é a vez do iOS — e você vai ver como a implementação em Swift pode ficar bastante limpa.&lt;/p&gt;

&lt;p&gt;Dando continuidade à série sobre Deep Links no Flutter, agora vamos implementar o fluxo nativo no iOS. Se você ainda não viu os posts anteriores, recomendo começar por aqui: &lt;a href="https://medium.com/p/d56ea3619192?postPublishedType=initial" rel="noopener noreferrer"&gt;Post 1 — Guia para Iniciantes&lt;/a&gt; | &lt;a href="https://medium.com/p/562bb353b3b2?postPublishedType=initial" rel="noopener noreferrer"&gt;Post 2 — Android com Kotlin&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Neste artigo, você vai aprender:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como configurar Info.plist e Associated Domains para deep links.&lt;/li&gt;
&lt;li&gt;A diferença entre custom schemes e Universal Links no iOS.&lt;/li&gt;
&lt;li&gt;Como implementar AppDelegate.swift com FlutterMethodChannel e FlutterEventChannel.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Configurando o Info.plist
&lt;/h2&gt;

&lt;p&gt;No iOS, o registro de um &lt;strong&gt;custom scheme&lt;/strong&gt; é feito no &lt;code&gt;Info.plist&lt;/code&gt;, por meio da chave &lt;code&gt;CFBundleURLTypes&lt;/code&gt;. É aqui que o sistema operacional aprende que links com o scheme &lt;code&gt;fitconnect://&lt;/code&gt; devem abrir este app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ios/Runner/Info.plist --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLTypes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;dict&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleTypeRole&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;Editor&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLName&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;com.fitconnect.app&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;CFBundleURLSchemes&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;fitconnect&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/dict&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CFBundleURLSchemes&lt;/code&gt; é o que de fato registra o scheme. O &lt;code&gt;CFBundleURLName&lt;/code&gt; é um identificador interno — por convenção, usa-se o bundle ID reverso. O &lt;code&gt;CFBundleTypeRole&lt;/code&gt; como &lt;code&gt;Editor&lt;/code&gt; indica que o app não apenas lê o tipo de URL, mas também pode criar links com esse scheme.&lt;/p&gt;




&lt;h2&gt;
  
  
  Configurando Universal Links
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Universal Links&lt;/strong&gt; exigem um passo a mais: o app precisa declarar quais domínios ele está autorizado a tratar. Essa declaração vai no arquivo &lt;code&gt;Runner.entitlements&lt;/code&gt;, sob a chave &lt;code&gt;com.apple.developer.associated-domains&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- ios/Runner/Runner.entitlements --&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;key&amp;gt;&lt;/span&gt;com.apple.developer.associated-domains&lt;span class="nt"&gt;&amp;lt;/key&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;array&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;string&amp;gt;&lt;/span&gt;applinks:fitconnect.app&lt;span class="nt"&gt;&amp;lt;/string&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/array&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;O prefixo &lt;code&gt;applinks:&lt;/code&gt; é obrigatório — é ele que instrui o iOS a tratar o domínio como Universal Link. Sem ele, o sistema ignora a entrada. A verificação bidirecional (o arquivo &lt;code&gt;apple-app-site-association&lt;/code&gt; no servidor) será montada no Post 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  Implementando o AppDelegate.swift
&lt;/h2&gt;

&lt;p&gt;Com a configuração pronta, o iOS entrega os links ao &lt;code&gt;AppDelegate&lt;/code&gt;. Diferente do Android, onde a entrada costuma ser centralizada em torno do Intent, no iOS o link pode chegar por caminhos diferentes: no cold start via &lt;code&gt;launchOptions&lt;/code&gt;, por custom schemes via &lt;code&gt;open url&lt;/code&gt; e por Universal Links via &lt;code&gt;continue userActivity&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;Flutter&lt;/span&gt;
&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;UIKit&lt;/span&gt;

&lt;span class="kd"&gt;@main&lt;/span&gt;
&lt;span class="kd"&gt;@objc&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterAppDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;CHANNEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.fitconnect.app/deeplink"&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;EVENT_CHANNEL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.fitconnect.app/deeplink_stream"&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;methodChannel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterMethodChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;eventChannel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterEventChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;eventSink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterEventSink&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;initialLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;lastProcessedLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;didFinishLaunchingWithOptions&lt;/span&gt; &lt;span class="nv"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;LaunchOptionsKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;controller&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rootViewController&lt;/span&gt; &lt;span class="k"&gt;as!&lt;/span&gt; &lt;span class="kt"&gt;FlutterViewController&lt;/span&gt;
        &lt;span class="nf"&gt;setupChannels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// Captura deep link inicial (cold start)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;handleDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt;
            &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;userActivityDictionary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userActivityDictionary&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;AnyHashable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;userActivityDictionary&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;userActivity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;NSUserActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="n"&gt;userActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;NSUserActivityTypeBrowsingWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                   &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webpageURL&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nf"&gt;handleDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="kt"&gt;GeneratedPluginRegistrant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;application&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;didFinishLaunchingWithOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;launchOptions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;setupChannels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;controller&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterViewController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// MethodChannel: Flutter pede o deep link inicial&lt;/span&gt;
        &lt;span class="n"&gt;methodChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FlutterMethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;binaryMessenger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binaryMessenger&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;methodChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setMethodCallHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"getInitialLink"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;initialLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nf"&gt;result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;FlutterMethodNotImplemented&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// EventChannel: stream de deep links em tempo real enquanto o app está em execução&lt;/span&gt;
        &lt;span class="n"&gt;eventChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;FlutterEventChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EVENT_CHANNEL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nv"&gt;binaryMessenger&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;controller&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binaryMessenger&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;eventChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setStreamHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Custom URL Scheme&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="kd"&gt;open&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="kt"&gt;OpenURLOptionsKey&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[:]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;handleDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;open&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Universal Links&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;UIApplication&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;continue&lt;/span&gt; &lt;span class="nv"&gt;userActivity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSUserActivity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;restorationHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="kt"&gt;UIUserActivityRestoring&lt;/span&gt;&lt;span class="p"&gt;]?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;userActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activityType&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kt"&gt;NSUserActivityTypeBrowsingWeb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;userActivity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webpageURL&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nf"&gt;handleDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;handleDeepLink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;urlString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;absoluteString&lt;/span&gt;

        &lt;span class="c1"&gt;// Evita processar o mesmo link duas vezes&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;urlString&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;lastProcessedLink&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;lastProcessedLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlString&lt;/span&gt;
        &lt;span class="kt"&gt;NSLog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Deep link: &lt;/span&gt;&lt;span class="se"&gt;\(&lt;/span&gt;&lt;span class="n"&gt;urlString&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isInitial&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;initialLink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;urlString&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;eventSink&lt;/span&gt;&lt;span class="p"&gt;?(&lt;/span&gt;&lt;span class="n"&gt;urlString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;AppDelegate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;FlutterStreamHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;onListen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;withArguments&lt;/span&gt; &lt;span class="nv"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt;
        &lt;span class="n"&gt;eventSink&lt;/span&gt; &lt;span class="nv"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kt"&gt;FlutterEventSink&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FlutterError&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eventSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;onCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;withArguments&lt;/span&gt; &lt;span class="nv"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;FlutterError&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eventSink&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Por que dois métodos de entrada?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;open url&lt;/code&gt;: chamado quando o link usa um &lt;strong&gt;custom scheme&lt;/strong&gt; (&lt;code&gt;fitconnect://&lt;/code&gt;). O iOS já sabe que é para abrir o app porque o scheme foi registrado no &lt;code&gt;Info.plist&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;continue userActivity&lt;/code&gt;: chamado para &lt;strong&gt;Universal Links&lt;/strong&gt; (HTTPS). O iOS só chega aqui após confirmar que o domínio está no &lt;code&gt;Runner.entitlements&lt;/code&gt; e que o servidor possui o arquivo &lt;code&gt;apple-app-site-association&lt;/code&gt;. Se qualquer verificação falhar, o link abre no Safari como fallback — sem erros, sem seletor.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcncnxfg00fa7ubsqi3cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcncnxfg00fa7ubsqi3cq.png" alt="Diagrama de fluxo no iOS" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Por que o AppDelegate adota FlutterStreamHandler via extension?
&lt;/h3&gt;

&lt;p&gt;Em vez de criar uma classe separada para o stream handler, o próprio &lt;code&gt;AppDelegate&lt;/code&gt; implementa o protocolo &lt;code&gt;FlutterStreamHandler&lt;/code&gt; via extension. Isso mantém o código coeso: tudo relacionado à entrega de links fica no mesmo lugar. O &lt;code&gt;onListen&lt;/code&gt; guarda a referência para o &lt;code&gt;eventSink&lt;/code&gt;, e o &lt;code&gt;onCancel&lt;/code&gt; a limpa quando o Flutter para de ouvir.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testando no iOS
&lt;/h2&gt;

&lt;p&gt;Para testar sem precisar de um device físico, o simulador do Xcode expõe o comando &lt;code&gt;xcrun simctl openurl&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Custom scheme — não requer verificação de domínio&lt;/span&gt;
xcrun simctl openurl booted &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"fitconnect://fitconnect.app/signup?referralCode=TRAINER1234567890123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Universal Link (HTTPS)&lt;/span&gt;
xcrun simctl openurl booted &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://fitconnect.app/signup?referralCode=TRAINER1234567890123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Atenção:&lt;/strong&gt; testar Universal Links no iOS pode ser enganoso. Em muitos casos, abrir a URL diretamente no Safari não reproduz o comportamento real de associação com o app. Para validar corretamente, prefira tocar no link a partir de apps como &lt;strong&gt;Mail&lt;/strong&gt;, &lt;strong&gt;Notas&lt;/strong&gt; ou &lt;strong&gt;iMessage&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Android vs iOS: comparação rápida
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv96j97pd6h7rdfk0dldp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv96j97pd6h7rdfk0dldp.png" alt="Android vs iOS: comparação rápida" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A lógica é a mesma nas duas plataformas — o que muda são as APIs e os arquivos de configuração. O &lt;code&gt;handleDeepLink&lt;/code&gt; no Swift é o equivalente direto do &lt;code&gt;handleIntent&lt;/code&gt; no Kotlin.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que construímos até aqui
&lt;/h2&gt;

&lt;p&gt;Ao final desta etapa, você já tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O &lt;code&gt;Info.plist&lt;/code&gt; configurado para custom schemes.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;Runner.entitlements&lt;/code&gt; com o domínio para Universal Links.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;AppDelegate.swift&lt;/code&gt; com &lt;code&gt;FlutterMethodChannel&lt;/code&gt; (link inicial) e &lt;code&gt;FlutterEventChannel&lt;/code&gt; (stream em tempo real).&lt;/li&gt;
&lt;li&gt;Clareza sobre a diferença entre &lt;code&gt;open url&lt;/code&gt; e &lt;code&gt;continue userActivity&lt;/code&gt; e quando cada um é chamado.&lt;/li&gt;
&lt;li&gt;Comandos &lt;code&gt;xcrun simctl&lt;/code&gt; prontos para testar no simulador.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este é o terceiro de 9 posts da série. Com Android e iOS prontos, temos o código nativo completo das duas plataformas. Se você já passou por algum problema com Universal Links — domínio não verificado, link abrindo no Safari em vez do app — conta nos comentários, esse tipo de detalhe vai direto para os próximos artigos.&lt;/p&gt;

&lt;p&gt;No próximo post, conectamos tudo no Flutter: o &lt;code&gt;DeepLinkService&lt;/code&gt; em Dart que fala com o código nativo via &lt;code&gt;MethodChannel&lt;/code&gt; e &lt;code&gt;EventChannel&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;Código completo disponível no repositório: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Se esse conteúdo te ajudou, deixa um ❤️ ou um 🔖 aqui no DEV.to — isso ajuda o post a alcançar mais devs.&lt;/p&gt;

&lt;p&gt;E você, já implementou deep links no seu app?&lt;/p&gt;

&lt;p&gt;Qual foi o maior desafio que encontrou?&lt;/p&gt;

&lt;h2&gt;
  
  
  Quero usar esses casos reais nos próximos posts da série 👇
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Tags: Flutter, iOS, Swift, Universal Links, Deep Links&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Deep Links no Android: Implementação Nativa com Kotlin + Flutter (Parte 2)</title>
      <dc:creator>Cristian Dornelles</dc:creator>
      <pubDate>Mon, 06 Apr 2026 13:58:31 +0000</pubDate>
      <link>https://forem.com/cdornelles/deep-links-no-android-implementacao-nativa-com-kotlin-flutter-parte-2-311n</link>
      <guid>https://forem.com/cdornelles/deep-links-no-android-implementacao-nativa-com-kotlin-flutter-parte-2-311n</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3icyyd6kc77dypwtf17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr3icyyd6kc77dypwtf17.png" alt="Header" width="800" height="419"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No post anterior, preparamos a base — constantes, enum de tipos e modelo de dados. Agora é hora de sujar as mãos com código nativo. Vamos configurar o Android para capturar deep links e entregá-los ao Flutter — sem nenhum pacote externo no meio do caminho.&lt;/p&gt;

&lt;p&gt;Spoiler: é mais simples do que parece — mas alguns detalhes fazem toda a diferença na prática.&lt;/p&gt;

&lt;p&gt;Dando continuidade à série sobre Deep Links no Flutter, com novos artigos saindo semanalmente, ou quase. Se você ainda não viu a base do projeto em Flutter, recomendo começar pelo primeiro artigo da série: &lt;a href="https://medium.com/p/d56ea3619192?postPublishedType=initial" rel="noopener noreferrer"&gt;Post 1 — Guia para Iniciantes&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;Neste artigo, você vai aprender:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Como configurar o AndroidManifest.xml para deep links.&lt;/li&gt;
&lt;li&gt;A diferença entre MethodChannel e EventChannel.&lt;/li&gt;
&lt;li&gt;Como testar com adb sem precisar de um dispositivo físico.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Configurando o AndroidManifest.xml
&lt;/h2&gt;

&lt;p&gt;O Android descobre que seu app pode tratar um link por meio de &lt;strong&gt;intent-filters&lt;/strong&gt; declarados no &lt;code&gt;AndroidManifest.xml&lt;/code&gt;. Podemos declarar dois intent-filters separados (um para custom scheme e outro para HTTPS) ou um único filtro com múltiplos &lt;code&gt;&amp;lt;data&amp;gt;&lt;/code&gt;. Neste exemplo, vamos manter separados para maior clareza didática.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- android/app/src/main/AndroidManifest.xml --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;activity&lt;/span&gt;
    &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;".MainActivity"&lt;/span&gt;
    &lt;span class="na"&gt;android:launchMode=&lt;/span&gt;&lt;span class="s"&gt;"singleTop"&lt;/span&gt;
    &lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Intent filter padrão (launcher) --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.MAIN"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.LAUNCHER"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Deep Link: Custom Scheme --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.VIEW"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.DEFAULT"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.BROWSABLE"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:scheme=&lt;/span&gt;&lt;span class="s"&gt;"fitconnect"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:host=&lt;/span&gt;&lt;span class="s"&gt;"fitconnect.app"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- Deep Link: HTTPS (App Links) --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;intent-filter&lt;/span&gt; &lt;span class="na"&gt;android:autoVerify=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;action&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.action.VIEW"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.DEFAULT"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;category&lt;/span&gt; &lt;span class="na"&gt;android:name=&lt;/span&gt;&lt;span class="s"&gt;"android.intent.category.BROWSABLE"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:scheme=&lt;/span&gt;&lt;span class="s"&gt;"https"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:host=&lt;/span&gt;&lt;span class="s"&gt;"fitconnect.app"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;data&lt;/span&gt; &lt;span class="na"&gt;android:pathPrefix=&lt;/span&gt;&lt;span class="s"&gt;"/signup"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/activity&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Três atributos merecem atenção:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;android:launchMode="singleTop"&lt;/code&gt;&lt;/strong&gt;: evita criar uma nova instância da Activity quando ela já está no topo da stack, direcionando o novo intent para &lt;code&gt;onNewIntent&lt;/code&gt;. Sem isso, o usuário poderia acabar com múltiplas instâncias da mesma Activity na stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;BROWSABLE&lt;/code&gt;&lt;/strong&gt;: autoriza que links externos — de um e-mail, mensagem ou navegador — possam abrir o app. Sem essa categoria, o intent-filter é invisível para o sistema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;android:autoVerify="true"&lt;/code&gt;&lt;/strong&gt;: ativa a verificação bidirecional do App Links. O Android vai checar se o servidor confirma que este app tem permissão para tratar o domínio. Montamos esse arquivo de verificação no Post 5.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Implementando o MainActivity.kt
&lt;/h2&gt;

&lt;p&gt;Com o manifest configurado, o Android vai entregar o link como um &lt;code&gt;Intent&lt;/code&gt; para a &lt;code&gt;MainActivity&lt;/code&gt;. Agora precisamos capturá-lo e repassar ao Flutter via dois canais:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;MethodChannel&lt;/code&gt;&lt;/strong&gt;: Flutter chama quando o app abre e precisa saber se havia um link pendente.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;EventChannel&lt;/code&gt;&lt;/strong&gt;: stream contínuo para links recebidos com o app já em execução.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;com.fitconnect.app&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.content.Intent&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.net.Uri&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.os.Bundle&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.util.Log&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.embedding.android.FlutterFragmentActivity&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.embedding.engine.FlutterEngine&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.EventChannel&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;io.flutter.plugin.common.MethodChannel&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlutterFragmentActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;TAG&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"FitConnect"&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;CHANNEL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.fitconnect.app/deeplink"&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;EVENT_CHANNEL&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"com.fitconnect.app/deeplink_stream"&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;methodChannel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MethodChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;eventChannel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;eventSink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EventSink&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;initialLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;lastProcessedLink&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"onCreate - checking for deep link"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;handleIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isInitial&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;configureFlutterEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;FlutterEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configureFlutterEngine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;// MethodChannel: Flutter pede deep link inicial&lt;/span&gt;
        &lt;span class="n"&gt;methodChannel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MethodChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dartExecutor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binaryMessenger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;CHANNEL&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;methodChannel&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;setMethodCallHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;call&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="s"&gt;"getInitialLink"&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;initialLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notImplemented&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// EventChannel: Stream de deep links em tempo real&lt;/span&gt;
        &lt;span class="n"&gt;eventChannel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;flutterEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dartExecutor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;binaryMessenger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nc"&gt;EVENT_CHANNEL&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;eventChannel&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;setStreamHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="err"&gt;: &lt;/span&gt;&lt;span class="nc"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StreamHandler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onListen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EventChannel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EventSink&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;eventSink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;events&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCancel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Any&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;eventSink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNewIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNewIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"onNewIntent - app was already open"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;handleIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isInitial&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;handleIntent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;?,&lt;/span&gt; &lt;span class="n"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Uri&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;intent&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="nc"&gt;Intent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ACTION_VIEW&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;deepLinkUrl&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

            &lt;span class="c1"&gt;// Evita processar o mesmo link duas vezes&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deepLinkUrl&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;lastProcessedLink&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;

            &lt;span class="n"&gt;lastProcessedLink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deepLinkUrl&lt;/span&gt;
            &lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;i&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TAG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Deep link: $deepLinkUrl"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isInitial&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// App estava fechado&lt;/span&gt;
                &lt;span class="n"&gt;initialLink&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deepLinkUrl&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// App estava aberto — envia via stream&lt;/span&gt;
                &lt;span class="n"&gt;eventSink&lt;/span&gt;&lt;span class="o"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deepLinkUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  O que acontece em cada cenário
&lt;/h3&gt;

&lt;p&gt;O fluxo de entrega do link depende de como o app foi aberto:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed8p07ckgve6bb2inczx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fed8p07ckgve6bb2inczx.png" alt="Diagrama de fluxo no Android" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;O &lt;code&gt;lastProcessedLink&lt;/code&gt; existe para um caso específico: em algumas versões do Android, &lt;code&gt;onCreate&lt;/code&gt; e &lt;code&gt;onNewIntent&lt;/code&gt; podem ser chamados em sequência para o mesmo link. Sem essa proteção, o Flutter processaria o mesmo deep link duas vezes.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testando com adb
&lt;/h2&gt;

&lt;p&gt;Antes de integrar com o Flutter, vale confirmar que o Android está capturando os links corretamente. O &lt;code&gt;adb&lt;/code&gt; permite simular cliques em links diretamente pelo terminal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Testa o custom scheme (fitconnect://)&lt;/span&gt;
&lt;span class="c"&gt;# Deve abrir o app sem precisar de verificação de domínio&lt;/span&gt;
adb shell am start &lt;span class="nt"&gt;-a&lt;/span&gt; android.intent.action.VIEW &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"fitconnect://fitconnect.app/signup?referralCode=TRAINER1234567890123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Testa o App Link (HTTPS)&lt;/span&gt;
&lt;span class="c"&gt;# Pode abrir um seletor de aplicativos se a verificação do domínio ainda não estiver concluída&lt;/span&gt;
adb shell am start &lt;span class="nt"&gt;-a&lt;/span&gt; android.intent.action.VIEW &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s2"&gt;"https://fitconnect.app/signup?referralCode=TRAINER1234567890123"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Se o custom scheme abrir o app, o manifest está correto. Se o HTTPS mostrar um seletor de aplicativos em vez de abrir direto — é sinal de que a verificação bidirecional ainda não está configurada. Isso é esperado neste ponto da série e será resolvido no Post 5.&lt;/p&gt;




&lt;h2&gt;
  
  
  O que construímos até aqui
&lt;/h2&gt;

&lt;p&gt;Ao final desta etapa, você já tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O AndroidManifest configurado com os dois intent-filters: custom scheme e App Links.&lt;/li&gt;
&lt;li&gt;O &lt;code&gt;MainActivity.kt&lt;/code&gt; com &lt;code&gt;MethodChannel&lt;/code&gt; (link inicial) e &lt;code&gt;EventChannel&lt;/code&gt; (stream em tempo real).&lt;/li&gt;
&lt;li&gt;Clareza sobre a diferença entre &lt;code&gt;onCreate&lt;/code&gt; e &lt;code&gt;onNewIntent&lt;/code&gt; e por que ambos precisam ser tratados.&lt;/li&gt;
&lt;li&gt;Comandos &lt;code&gt;adb&lt;/code&gt; prontos para testar sem precisar de dispositivo físico.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Este é o segundo de 9 posts da série. Se você já passou por alguma situação estranha com intent-filters no Android, conta nos comentários — esse tipo de detalhe vai direto para os próximos artigos.&lt;/p&gt;

&lt;p&gt;Na próxima etapa, vamos replicar esse fluxo no iOS usando Swift — e você vai perceber como os conceitos são os mesmos, mesmo com APIs diferentes.&lt;/p&gt;




&lt;p&gt;Código completo disponível no repositório: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Se esse conteúdo te ajudou, deixa um ❤️ ou um 🔖 aqui no DEV.to — isso ajuda o post a alcançar mais devs.&lt;/p&gt;

&lt;p&gt;E você, já implementou deep links no seu app?&lt;/p&gt;

&lt;p&gt;Qual foi o maior desafio que encontrou?&lt;/p&gt;

&lt;h2&gt;
  
  
  Quero usar esses casos reais nos próximos posts da série 👇
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Tags: Flutter, Android, Kotlin, Deep Links, Mobile Development&lt;/em&gt;&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Deep Links em Flutter: O Guia Definitivo para Iniciantes (Sem Pacotes de Terceiros) (Parte 1)</title>
      <dc:creator>Cristian Dornelles</dc:creator>
      <pubDate>Sat, 04 Apr 2026 18:59:27 +0000</pubDate>
      <link>https://forem.com/cdornelles/deep-links-em-flutter-o-guia-definitivo-para-iniciantes-sem-pacotes-de-terceiros-parte-1-4a31</link>
      <guid>https://forem.com/cdornelles/deep-links-em-flutter-o-guia-definitivo-para-iniciantes-sem-pacotes-de-terceiros-parte-1-4a31</guid>
      <description>&lt;p&gt;Imagine isso: seu usuário recebe um link de desconto, clica nele — e BOOM! Ele não só abre seu app, mas já está na tela de checkout com o cupom aplicado. Isso é mágica? Não — são Deep Links!&lt;/p&gt;

&lt;p&gt;Este é o primeiro conteúdo de uma série completa sobre Deep Links no Flutter, com novos artigos saindo semanalmente, ou quase. Vamos entender os conceitos fundamentais, explorar os diferentes tipos e preparar a estrutura base do nosso projeto do zero, sem depender de pacotes de terceiros.&lt;/p&gt;

&lt;p&gt;Ao longo desta série, vou te mostrar como implementar deep links em Flutter — sem utilizar pacotes prontos. Por quê? Porque você vai aprender exatamente como tudo funciona por baixo dos panos.&lt;/p&gt;




&lt;p&gt;Neste artigo, você vai aprender:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;O que são deep links.&lt;/li&gt;
&lt;li&gt;Diferença entre App Links e Custom Schemes.&lt;/li&gt;
&lt;li&gt;Como estruturar a base no Flutter.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  O que são Deep Links?
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Deep links&lt;/em&gt; são URLs que levam o usuário diretamente para uma tela específica do seu app, em vez de abrir no navegador.&lt;/p&gt;

&lt;p&gt;Exemplo real:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Fluxo tradicional&lt;/strong&gt;: Abre navegador → usuário instala o app → abre → navega até a tela.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep link&lt;/strong&gt;: Abre o app diretamente na tela correta.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Para termos uma visão completa, o diagrama abaixo ilustra o roteamento (conhecido como &lt;em&gt;Deferred Deep Linking&lt;/em&gt;), onde — até mesmo se o usuário não tiver o app — o contexto do link é preservado após ele passar pelas lojas de apps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiviwp8xhrpjpeu5t7jxv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiviwp8xhrpjpeu5t7jxv.png" alt="Fluxo completo" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fluxo completo&lt;/p&gt;

&lt;p&gt;Esse fluxo completo, onde o usuário pode instalar o app e ainda assim manter o contexto original do link, é o que chamamos de &lt;strong&gt;Deferred Deep Linking&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Anatomia de um Deep Link
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://fitconnect.app/signup?referralCode=TRAINER12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scheme&lt;/strong&gt;: &lt;code&gt;https&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Host&lt;/strong&gt;: &lt;code&gt;fitconnect.app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Path&lt;/strong&gt;: &lt;code&gt;/signup&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt;: &lt;code&gt;?referralCode=TRAINER12345&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cada parte dessa estrutura tem um papel específico na navegação. O scheme identifica o protocolo (ou, no caso de custom schemes, o aplicativo), o host e o path determinam a rota, e os query parameters carregam dados extras (como um código de indicação — referralCode).&lt;/p&gt;




&lt;h2&gt;
  
  
  Tipos de Deep Links
&lt;/h2&gt;

&lt;p&gt;Existem dois tipos principais e a escolha entre eles tem implicações diretas na segurança e na experiência do usuário.&lt;/p&gt;

&lt;h3&gt;
  
  
  Custom Schemes (&lt;code&gt;fitconnect://&lt;/code&gt;)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fitconnect://fitconnect.app/signup?referralCode=TRAINER12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ Rápido de implementar.&lt;/li&gt;
&lt;li&gt;✅ Ótimo para testes locais.&lt;/li&gt;
&lt;li&gt;⚠️ Menos seguro — qualquer aplicativo pode registrar o mesmo scheme.&lt;/li&gt;
&lt;li&gt;⚠️ Se o app não estiver instalado, o sistema exibe um erro feio.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  App Links (Android) / Universal Links (iOS)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://fitconnect.app/signup?referralCode=TRAINER12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;✅ Seguro — verificação bidirecional entre aplicativo e servidor.&lt;/li&gt;
&lt;li&gt;✅ Se o app não estiver instalado, abre normalmente no navegador.&lt;/li&gt;
&lt;li&gt;✅ Recomendado para produção.&lt;/li&gt;
&lt;li&gt;⚠️ Requer domínio próprio.&lt;/li&gt;
&lt;li&gt;⚠️ Setup mais complexo.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;O que é essa verificação bidirecional?&lt;/strong&gt; O sistema operacional só abre o app se ambas as pontas se reconhecerem: o app declara quais domínios ele trata, e o servidor confirma quais aplicativos têm permissão para isso — por meio de um arquivo hospedado no próprio domínio da aplicação (&lt;code&gt;assetlinks.json&lt;/code&gt; no Android, &lt;code&gt;apple-app-site-association&lt;/code&gt; no iOS). Se qualquer lado estiver faltando ou inconsistente, o link abre no navegador como fallback. Isso impede que um aplicativo malicioso reivindique seu domínio e intercepte seus links. Vamos montar esses arquivos em detalhes no Post 5.&lt;/p&gt;

&lt;p&gt;Na prática: use custom schemes durante o desenvolvimento e migre para HTTPS (App Links / Universal Links) em produção.&lt;/p&gt;




&lt;h2&gt;
  
  
  Nossa Aplicação: FitConnect
&lt;/h2&gt;

&lt;p&gt;Para tornar o aprendizado concreto, vamos construir o FitConnect — uma plataforma fictícia que conecta personal trainers com clientes por meio de um sistema de indicação.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;O cenário:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Maria é personal trainer e quer indicar o app para seus alunos. Ela compartilha seu link de indicação. Quando um aluno se cadastra usando o link, Maria ganha bônus e o aluno ganha desconto.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;O deep link principal da série:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://fitconnect.app/signup?referralCode=TRAINER12345678901234
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Quando um aluno clica nesse link, o app deve abrir diretamente na tela de cadastro com o código &lt;code&gt;TRAINER12345678901234&lt;/code&gt; já preenchido. Simples de descrever, mas com bastante detalhe de implementação por baixo.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Domínio&lt;/strong&gt;: &lt;code&gt;fitconnect.app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom scheme&lt;/strong&gt;: &lt;code&gt;fitconnect://&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package&lt;/strong&gt;: &lt;code&gt;com.fitconnect.app&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Preparando a Estrutura
&lt;/h2&gt;

&lt;p&gt;Antes de escrever qualquer código nativo, vale a pena definir as constantes, tipos e modelos que vão ser compartilhados entre todas as camadas do app.&lt;/p&gt;

&lt;h3&gt;
  
  
  Constantes
&lt;/h3&gt;

&lt;p&gt;Centralizar strings como os nomes dos channels evita erros de digitação difíceis de rastrear. Se o nome do channel no Dart não bater exatamente com o do Kotlin ou Swift, a comunicação falha silenciosamente.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/shared/const/deep_link_const.dart&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeepLinkConst&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;methodChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'com.fitconnect.app/deeplink'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;eventChannel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'com.fitconnect.app/deeplink_stream'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;customScheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'fitconnect'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;httpsScheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'https'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;appHost&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'fitconnect.app'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;signupPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'/signup'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;referralCodeParam&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'referralCode'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;referralCodeLength&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enum de Tipos
&lt;/h3&gt;

&lt;p&gt;O getter &lt;code&gt;isSecure&lt;/code&gt; torna o código mais expressivo — em vez de comparar strings ou verificar o scheme manualmente, você simplesmente checa &lt;code&gt;data.type.isSecure&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/shared/enums/deep_link_type.dart&lt;/span&gt;
&lt;span class="kt"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;customScheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;appLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;// Android HTTPS&lt;/span&gt;
  &lt;span class="n"&gt;universalLink&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// iOS HTTPS&lt;/span&gt;
  &lt;span class="n"&gt;unknown&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="n"&gt;isSecure&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;appLink&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;universalLink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Modelo de Dados (Freezed)
&lt;/h3&gt;

&lt;p&gt;Se preferir, você não precisa utilizar o Freezed e pode criar seus modelos na mão. A grande vantagem de adotá-lo é a garantia de imutabilidade e a geração automática de código para comparação de objetos e o método copyWith. Como os deep links carregam parâmetros importantes (como o código de indicação), tratar esses dados de forma imutável nos protege de bugs difíceis de rastrear na navegação do app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// lib/shared/models/deep_link_data.dart&lt;/span&gt;
&lt;span class="nd"&gt;@freezed&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DeepLinkData&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;_$DeepLinkData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="kd"&gt;factory&lt;/span&gt; &lt;span class="n"&gt;DeepLinkData&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;DeepLinkType&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;scheme&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nd"&gt;@Default&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt; &lt;span class="kt"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;queryParameters&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;referralCode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="kd"&gt;required&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt; &lt;span class="n"&gt;receivedAt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_DeepLinkData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  O que construímos até aqui
&lt;/h2&gt;

&lt;p&gt;Ao final desta etapa, você já tem:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clareza sobre como deep links funcionam.&lt;/li&gt;
&lt;li&gt;Entendimento das diferenças entre os tipos de links.&lt;/li&gt;
&lt;li&gt;Uma base sólida no Flutter para começar a implementação.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Essa base será utilizada nos próximos passos para integrar o código nativo e completar o fluxo ponta a ponta.&lt;/p&gt;

&lt;p&gt;Na próxima etapa, vamos partir para a implementação nativa no Android — incluindo &lt;code&gt;AndroidManifest.xml&lt;/code&gt; e &lt;code&gt;MainActivity.kt&lt;/code&gt; completos.&lt;/p&gt;




&lt;p&gt;Código completo disponível no repositório: &lt;a href="https://github.com/crdornelles/fit_connect" rel="noopener noreferrer"&gt;FitConnect no GitHub&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Este é o primeiro post de uma série de 9 sobre deep links em Flutter. Nos próximos artigos, vamos do código nativo para o Android e iOS até deferred links, redirect pages e testes — tudo sem depender de pacotes prontos. Se você tem dúvidas, sugestões ou já passou por algum problema parecido com deep links, conta nos comentários! Adoro saber como essa experiência se aplica em projetos reais. E se quiser acompanhar os próximos posts, é só seguir aqui no Medium.&lt;/p&gt;




&lt;p&gt;Se esse conteúdo te ajudou, deixa um ❤️ ou um 🔖 aqui no DEV.to — isso ajuda o post a alcançar mais devs.&lt;/p&gt;

&lt;p&gt;E você, já implementou deep links no seu app?&lt;br&gt;&lt;br&gt;
Qual foi o maior desafio que encontrou?&lt;/p&gt;

&lt;p&gt;Quero usar esses casos reais nos próximos posts da série 👇&lt;/p&gt;




&lt;h1&gt;
  
  
  flutter #android #ios #deeplinks #mobile #programming
&lt;/h1&gt;

</description>
      <category>flutter</category>
      <category>android</category>
      <category>ios</category>
      <category>deeplinks</category>
    </item>
  </channel>
</rss>
