Flutter
O pacote unolink é uma camada fina sobre os SDKs nativos de iOS e Android, que vêm dentro dele. Ele não precisa de
nenhuma permissão além de internet e de nenhuma entrada no Info.plist. Publicado no pub.dev por unolink.dev. Plano Pro
ou superior.
Requisitos
- Flutter 3.22+ (Dart 3.4+).
- Android 6.0+ (
minSdk 23) e iOS 13+. - Uma chave do SDK: no painel, abra seu app → Configurações → Chaves do SDK → Nova chave. Ela aparece uma única vez, então copie-a nesse momento.
Instalação
flutter pub add unolink
Isso adiciona unolink: ^0.3.3 ao pubspec.yaml e baixa o pacote. Recompile o app depois; um hot reload não basta
depois de adicionar código nativo.
Se o CocoaPods falhar no build de iOS com um erro de codificação (Ruby 4, ou um locale que não é UTF-8), rode você mesmo em UTF-8 e gere o build de novo:
cd ios && LANG=en_US.UTF-8 pod install
Configuração
Chame configure uma vez em main(), depois de WidgetsFlutterBinding.ensureInitialized() e antes de runApp:
import 'package:flutter/foundation.dart';
import 'package:flutter/widgets.dart';
import 'package:unolink/unolink.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Unolink.configure('ulk_…', debug: kDebugMode);
runApp(const MyApp());
}
Opções
| Opção | Padrão | O que faz |
|---|---|---|
debug | false | Marca esta instalação como dispositivo de teste. Passe kDebugMode. Os painéis escondem dispositivos de teste, a menos que Incluir dispositivos de teste esteja ativado. |
logLevel | UnolinkLogLevel.warn | Quanto vai para o console do Xcode ou para o Logcat (tag Unolink): none, error, warn, info, debug. |
baseUrl | https://api.unolink.dev | A API do SDK. Deixe como está. |
A chave é pública: ela vai dentro do seu app e só pode reportar dados desse app. Veja Chaves do SDK.
Eventos do funil
Adicione uma linha em cada momento importante. Elas viram as etapas em Funil e Jornadas.
Unolink.onboardingCompleted(); // the last onboarding screen is done
Unolink.paywallViewed(placement: 'onboarding'); // a paywall appeared; placement says which one
Unolink.paywallSkipped(placement: 'onboarding'); // closed without buying
Unolink.signUp(method: 'apple'); // an account was created
Unolink.signUpSkipped(); // went on as a guest (0.3.2+)
Sem RevenueCat, reporte você mesmo os testes grátis e as compras. O valor é uma string, então nunca é arredondado:
Unolink.trialStarted(productId: 'pro_yearly');
Unolink.purchase('49.99', 'USD', productId: 'pro_yearly');
Unolink.purchaseCancelled(productId: 'pro_yearly'); // closed the purchase sheet
Unolink.purchaseFailed(productId: 'pro_yearly', reason: 'payment_failed');
Seus próprios eventos recebem um nome e até 20 propriedades:
Unolink.track('level_up', {'level': 3});
A lista completa, com os nomes que chegam ao painel, está em Eventos.
ID de usuário e RevenueCat
Se você usa RevenueCat, conecte-o no seu app → Configurações → RevenueCat. Depois disso, não
chame purchase nem trialStarted: o próprio RevenueCat envia testes grátis, compras, renovações, cancelamentos e
reembolsos, e o Unolink ignora as chamadas de compra do app para que nada conte duas vezes.
Para ligar essas compras à instalação, informe o próprio app user ID do RevenueCat. Com o SDK 0.3.2 ou posterior,
uma linha o mantém atualizado. Chame-a uma vez na abertura, antes ou depois de configure:
Unolink.connectRevenueCat(
() => Purchases.appUserID,
addListener: Purchases.addCustomerInfoUpdateListener,
removeListener: Purchases.removeCustomerInfoUpdateListener,
);
O Unolink lê o ID assim que o RevenueCat está configurado, a cada atualização das informações do cliente (compras, logIn,
logOut) e sempre que o app é retomado, e só o envia quando ele mudou. Se o RevenueCat ainda não estiver configurado,
a leitura falha em silêncio e é tentada de novo depois. Ele retorna uma função que desconecta. Por isso, Unolink.revenueCatUserChanged() normalmente não é necessário no Flutter.
Sem ela (ou antes da 0.3.2), chame setUserId com o ID do RevenueCat depois de Purchases.configure, depois de cada
Purchases.logIn e Purchases.logOut, e em toda abertura. Use um ou outro, não os dois:
// after Purchases.configure, logIn and logOut, and on every launch
Unolink.setUserId(await Purchases.appUserID);
Para um convidado, esse é o ID anônimo do RevenueCat, então uma compra feita antes do cadastro se junta à instalação
na hora. Depois do logIn, é o ID da conta. Todo ID que uma instalação reportou conta, então a compra do convidado
continua ligada. Veja Convidados e contas.
O Unolink nunca guarda o ID em si, apenas um hash unidirecional que é diferente para cada um dos seus apps.
Deep links adiados
No Android, quando alguém instala a partir de um link do Unolink que tem deep link, o listener roda uma vez, na primeira abertura. No iPhone ele não é chamado: a Apple não tem referrer de instalação, e o Unolink nunca faz fingerprinting.
Unolink.setDeferredDeepLinkListener((link) {
// link.deepLink: '/promo/3for2', link.params: {'offer': '3for2'}
// link.linkSlug: 'tiktok' or null, link.clickId: 'clk_01JA…'
if (link.deepLink != null) router.go(link.deepLink!);
Unolink.consumeDeferredDeepLink();
});
O listener é chamado uma vez por instalação. Um link que chegou antes de você defini-lo é entregue assim que você o define.
Abrir depois do onboarding
A primeira abertura geralmente começa no onboarding. Se a tela do link fica depois do onboarding ou do login, não a abra pelo listener. Quando o onboarding (ou o login) terminar, leia o link pendente, abra-o e depois marque-o como consumido:
// when onboarding (or sign-in) is done, and on every launch after that until it's consumed
final link = await Unolink.getPendingDeferredDeepLink();
if (link?.deepLink != null) {
router.go(link!.deepLink!);
await Unolink.consumeDeferredDeepLink();
}
O link espera até você consumi-lo, mesmo que o app seja fechado nesse meio-tempo (até 30 dias depois da instalação;
0.3.3+). Um usuário novo que sai no meio do onboarding ainda o recebe na próxima abertura, então você não precisa
guardá-lo. Chame consumeDeferredDeepLink() depois de abri-lo: até lá, getPendingDeferredDeepLink() o retorna a cada
abertura. Ele é null antes de configure e até o Google Play responder, e sempre null no iPhone.
Defina o Deep link e os Parâmetros do link no painel (Links → ⋯ → Editar). Como isso funciona está em Deep links adiados no Android.
Outras chamadas
| Chamada | O que faz |
|---|---|
await Unolink.getInstallId() | O ID aleatório desta instalação, ou null antes de configure. Ele não identifica nenhuma pessoa nem dispositivo. |
Unolink.flush() | Envia agora os eventos na fila. Normalmente não é necessário. |
Unolink.setEnabled(false) | Desativa o rastreamento e apaga os eventos na fila, para a sua opção de desativação (opt-out). true ativa de novo. |
Dispositivos de teste
Com debug: kDebugMode, as builds de depuração são dispositivos de teste. Os dados delas são reais, mas ficam ocultos
até você ativar Incluir dispositivos de teste em Funil e Jornadas. Mais em Testes.
Privacidade
- Sem IDFA, sem Google Advertising ID, sem o aviso do App Tracking Transparency, sem fingerprinting.
- Um ID de instalação aleatório, versão do app, versão do sistema, versão do SDK, celular ou tablet, idioma. O país vem da borda da rede. Endereços IP nunca são guardados.
- No iOS, o manifesto de privacidade do SDK nativo vem com o pacote: análises, não vinculados à identidade.
- Nunca coloque nomes, e-mails ou outros dados pessoais nas propriedades dos eventos.
Solução de problemas
- MissingPluginException? Pare o app e rode-o de novo. Hot reload e hot restart não carregam código nativo novo.
- Nada no painel? Ative Incluir dispositivos de teste: builds com
kDebugModeficam ocultas por padrão. - Ainda nada? Configure com
logLevel: UnolinkLogLevel.debuge procure porUnolinkno console do Xcode ou no Logcat. Uma chave errada ou revogada aparece no log como erro.
Mais em Solução de problemas.