🔗Deep Links
Neste guia, vamos explorar o que são deep links, como configurá-los no Flutter para iOS e Android, e como criar e utilizar uma classe helper para facilitar o gerenciamento de deep links no seu app
Utilizando Deep Links no Flutter
1. O que são Deep Links?
Deep links são URLs que direcionam os usuários para partes específicas de um aplicativo, em vez de simplesmente abrir a tela inicial. Eles são úteis para:
Integração com marketing: Direcionar usuários para promoções, produtos ou conteúdos específicos.
Compartilhamento de conteúdo: Permitir que usuários compartilhem links que abrem diretamente em uma tela específica do app.
Melhorar a experiência do usuário: Reduzir o número de passos necessários para acessar um recurso.
Exemplo de deep link:
https://meuapp.com/produto/123
pode abrir diretamente a tela de detalhes do produto com ID 123.
2. Configuração de Deep Links no Flutter
2.1. Configuração no Android
Passo 1: Adicionar Intent Filters no AndroidManifest.xml
No arquivo android/app/src/main/AndroidManifest.xml
, adicione o seguinte dentro da tag <activity>
da sua atividade principal:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" android:host="@string/deep_link_host" />
<data android:scheme="https" />
</intent-filter>
O que isso faz?
Define que a atividade pode ser aberta por um link (
android.intent.action.VIEW
).Configura o domínio (
meuapp.com
) e o esquema (https
) que serão usados para os deep links.
Passo 2: Configuração dos flavors
Para configurar o @string/deep_link_host
, no diretório android/app/src/
, crie pastas para cada flavor (se ainda não existirem). Por exemplo:
android/app/src/flavor1/
android/app/src/flavor2/
Dentro de cada pasta, crie um arquivo res/values/strings.xml
para definir o valor de deep_link_host
específico para cada flavor.
Exemplo para flavor1
:
Arquivo: android/app/src/flavor1/res/values/strings.xml
<resources>
<string name="deep_link_host">flavor1.meuapp.com</string>
</resources>
Exemplo para flavor2
:
Arquivo: android/app/src/flavor2/res/values/strings.xml
<resources>
<string name="deep_link_host">flavor2.meuapp.com</string>
</resources>
O que isso faz?
Define o valor de
deep_link_host
comoflavor1.meuapp.com
paraflavor1
.Define o valor de
deep_link_host
comoflavor2.meuapp.com
paraflavor2
.
Passo 3: Configurar o assetlinks.json
Para que o Android valide automaticamente os deep links, você precisa hospedar um arquivo assetlinks.json
no seu domínio. Ele deve estar acessível em https://meuapp.com/.well-known/assetlinks.json
.
Exemplo de assetlinks.json
:
[{
"relation": ["delegate_permission/common.handle_all_urls"],
"target": {
"namespace": "android_app",
"package_name": "com.seuapp",
"sha256_cert_fingerprints": ["SEU_FINGERPRINT_AQUI"]
}
}]
O que isso faz?
Associa o domínio
meuapp.com
ao seu aplicativo Android.Substitua
com.seuapp
pelo pacote do seu app eSEU_FINGERPRINT_AQUI
pelo fingerprint SHA-256 do seu certificado.
2.2. Configuração no iOS
Passo 1: Adicionar a Capacidade "Associated Domains"
No Xcode:
Abra o projeto iOS no Xcode (
ios/Runner.xcworkspace
).Selecione o target
Runner
e vá para a aba Signing & Capabilities.Clique no botão + Capability e adicione
Associated Domains
.
Configurar os Domínios:
Na seção
Associated Domains
, adicione os domínios que você deseja associar ao aplicativo.O formato é
applinks:<domínio>
.
Exemplo:
Para
flavor1
, adicione:applinks:flavor1.meuapp.com
Para
flavor2
, adicione:applinks:flavor2.meuapp.com
No Apple Developer Portal:
Acesse o portal Apple Developer.
Vá para Certificates, Identifiers & Profiles > Identifiers.
Selecione o identificador do seu aplicativo.
Habilite a capacidade
Associated Domains
e adicione os mesmos domínios configurados no Xcode.
Passo 2: Hospedar o Arquivo apple-app-site-association
Crie o Arquivo:
Crie um arquivo chamado
apple-app-site-association
(sem extensão).O conteúdo do arquivo deve seguir o formato JSON e associar o domínio aos IDs dos aplicativos (um para cada flavor).
Exemplo:
{ "applinks": { "apps": [], "details": [ { "appID": "<team_id>.com.seuapp", "paths": ["*"] }, ] } }
Substitua
<team_id>
pelo seu Team ID (encontrado no Apple Developer Portal).Substitua
com.seuapp.flavor1
ecom.seuapp.flavor2
pelos bundle IDs dos seus flavors.
Hospede o Arquivo:
O arquivo deve ser hospedado no diretório
.well-known
do seu domínio.O caminho completo deve ser:
https://<domínio>/.well-known/apple-app-site-association
.
Exemplo:
Para
flavor1
, o arquivo deve estar acessível em:https://flavor1.meuapp.com/.well-known/apple-app-site-association
Para
flavor2
, o arquivo deve estar acessível em:https://flavor2.meuapp.com/.well-known/apple-app-site-association
Dicas:
O arquivo não deve ter extensão (por exemplo,
.json
).O servidor deve servir o arquivo com o tipo MIME
application/json
.Se você não tem um servidor, pode usar o Firebase Hosting para hospedar o arquivo.
3. Criando e Utilizando uma Classe Helper
Agora que configuramos os deep links, vamos criar uma classe helper para facilitar o gerenciamento deles no Flutter.
3.1. Criando a Classe DeepLinksHelper
A classe DeepLinksHelper
encapsula toda a lógica de deep links, desde a inicialização até o processamento. Aqui está o código completo:
import 'package:app_links/app_links.dart';
import 'dart:async';
class DeepLinksHelper {
// Singleton pattern
static final DeepLinksHelper _instance = DeepLinksHelper._internal();
factory DeepLinksHelper() => _instance;
DeepLinksHelper._internal();
late final AppLinks _appLinks;
late final StreamSubscription<Uri>? _linkSubscription;
final StreamController<bool> _homePageReadyController = StreamController<bool>.broadcast();
Uri? _initialUri;
// Inicializa o sistema de deep links
Future<void> initDeepLinks() async {
_appLinks = AppLinks();
_linkSubscription = _appLinks.uriLinkStream.listen((Uri uri) {
print('Deep link recebido: $uri');
_initialUri = uri;
_homePageReadyController.stream
.firstWhere((isReady) => isReady)
.then((_) {
_handleIncomingLink();
});
});
}
// Notifica que a página inicial está pronta
void notifyHomePageReady() {
_homePageReadyController.add(true);
}
// Processa o link recebido
void _handleIncomingLink() {
if (_initialUri != null) {
print('Processando deep link: $_initialUri');
// Adicione a lógica para navegar para a tela correta com base no URI.
_initialUri = null;
}
}
// Cancela a inscrição no stream de deep links
void cancelSubscription() {
_linkSubscription?.cancel();
}
}
3.2. Explicação dos Métodos
initDeepLinks()
: Inicializa o sistema de deep links e começa a escutar por links recebidos.notifyHomePageReady()
: Notifica que a página inicial está pronta para processar o deep link._handleIncomingLink()
: Processa o link recebido. Aqui você pode adicionar a lógica para navegar para a tela correta com base no URI.cancelSubscription()
: Cancela a inscrição no stream de deep links para evitar vazamentos de memória.
4. Utilizando o DeepLinksHelper
no Seu App
DeepLinksHelper
no Seu App4.1. Inicialização no main.dart
No arquivo main.dart
, inicialize o DeepLinksHelper
e passe a instância para o MaterialApp
:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final deepLinksHelper = DeepLinksHelper();
await deepLinksHelper.initDeepLinks();
runApp(MyApp(deepLinksHelper: deepLinksHelper));
}
class MyApp extends StatelessWidget {
final DeepLinksHelper deepLinksHelper;
const MyApp({Key? key, required this.deepLinksHelper}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(deepLinksHelper: deepLinksHelper),
);
}
}
4.2. Notificação na HomePage
Na HomePage
, notifique quando a página estiver pronta:
class HomePage extends StatefulWidget {
final DeepLinksHelper deepLinksHelper;
const HomePage({Key? key, required this.deepLinksHelper}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
void initState() {
super.initState();
widget.deepLinksHelper.notifyHomePageReady();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: Center(child: Text('Bem-vindo ao app!')),
);
}
}
4.3. Processamento do Link
No método _handleIncomingLink
, adicione a lógica para navegar para a tela correta com base no URI:
void _handleIncomingLink() {
if (_initialUri != null) {
print('Deep link recebido: $_initialUri');
// Exemplo: Navegar para uma tela específica com base no caminho do URI.
if (_initialUri!.path == '/produto') {
Navigator.push(context, MaterialPageRoute(builder: (_) => ProductPage()));
}
_initialUri = null;
}
}
4.4. Cancelamento da Inscrição
No dispose
do widget, cancele a inscrição:
@override
void dispose() {
widget.deepLinksHelper.cancelSubscription();
super.dispose();
}
5. Testando Deep Links no Emulador Android e iOS
Agora que você configurou os deep links e a classe DeepLinksHelper
, é hora de testar se tudo está funcionando corretamente.
5.1. Testando no Emulador Android
Usando o Comando adb
Certifique-se de que o emulador está rodando.
Execute o comando abaixo no terminal:
adb shell am start -W -a android.intent.action.VIEW -d "https://flavor1.meuapp.com/details" com.seuapp.flavor1
Substitua
https://flavor1.meuapp.com/details
pelo seu deep link.Substitua
com.seuapp.flavor1
peloapplicationId
do flavor que você está testando.
Verifique o log no Android Studio para confirmar que o deep link foi recebido.
5.2. Testando no Emulador iOS
Usando o Comando xcrun simctl openurl
Certifique-se de que o emulador iOS está rodando.
Execute o comando abaixo no terminal:
xcrun simctl openurl booted "https://flavor1.meuapp.com/details"
Substitua
https://flavor1.meuapp.com/details
pelo seu deep link.
Verifique o log no Xcode para confirmar que o deep link foi recebido.
Conclusão
Com essa abordagem, você terá um sistema de deep links robusto e organizado no seu aplicativo Flutter. A classe DeepLinksHelper
facilita o gerenciamento dos links, permitindo que você se concentre na lógica do seu app. Agora é só testar e adaptar para o seu caso de uso! 🚀
Last updated