React Native e Expo
@unolink/react-native é uma ponte fina sobre os SDKs nativos de iOS e Android, que vêm dentro do pacote. Ele não precisa
de config plugin, de nenhuma permissão além de internet nem de entradas no Info.plist. Plano Pro ou superior.
Requisitos
- React Native 0.79+ (nova arquitetura).
- Expo: uma development build,
npx expo prebuildou EAS Build. Ele não roda no Expo Go, porque tem código nativo. - 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
Expo:
npx expo install @unolink/react-native
npx expo prebuild # or: eas build
React Native puro:
npm install @unolink/react-native
cd ios && pod install
Depois, recompile o app. Recarregar o JavaScript não basta depois de adicionar código nativo.
Se o pod install falhar com um erro de codificação (Ruby 4, ou um locale que não é UTF-8), rode em UTF-8:
cd ios && LANG=en_US.UTF-8 pod install
Não instale com npm install --legacy-peer-deps: ele reescreve o package-lock.json e remove as dependências peer opcionais.
Configuração
Chame configure uma vez, no nível mais alto, antes de a sua primeira tela renderizar: em app/_layout.tsx com o Expo
Router, ou em index.js.
import { Unolink } from "@unolink/react-native"
Unolink.configure("ulk_…", { debug: __DEV__ })
Com a 0.3.1 ou posterior:
- Chamadas feitas antes de
configureesperam e são enviadas logo depois dele, então não tem problema restaurar uma sessão primeiro. - Uma chave ausente (por exemplo, uma entrada faltando no
.env) é reportada no console, em vez de falhar em silêncio.Unolink.isConfigured()diz se ele está rodando. debugtem__DEV__como padrão.
Opções
| Opção | Padrão | O que faz |
|---|---|---|
debug | __DEV__ (0.3.1+; false antes) | Marca esta instalação como dispositivo de teste. Os painéis escondem dispositivos de teste, a menos que Incluir dispositivos de teste esteja ativado. |
logLevel | "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("onboarding") // a paywall appeared; placement says which one
Unolink.paywallSkipped("onboarding") // closed without buying
Unolink.signUp("apple") // a new account was created
Unolink.signIn("apple") // signed in to an account they already had
Unolink.signUpSkipped() // went on as a guest (0.3.1+)
Telas de onboarding, uma chamada por tela quando ela aparece:
import { useOnboardingStep } from "@unolink/react-native"
useOnboardingStep("goal", { index: 0 }) // in each onboarding screen component
Unolink.onboardingSkipped("goal") // on Skip
Os IDs de tela usam letras, dígitos, _ e . (how_heard, não how-heard). Em desenvolvimento, o StrictMode do React
monta as telas duas vezes, então você pode ver uma tela enviada duas vezes ali; builds de release a enviam uma vez. As
builds de desenvolvimento avisam no console sobre IDs ou propriedades que o servidor rejeitaria (0.3.1+).
Sem RevenueCat, reporte você mesmo os testes grátis e as compras. Passe o valor como string para que ele nunca seja arredondado:
Unolink.trialStarted("pro_yearly")
Unolink.purchase("49.99", "USD", "pro_yearly")
Unolink.purchaseCancelled("pro_yearly") // closed the purchase sheet
Unolink.purchaseFailed("pro_yearly", "payment_failed")
Seus próprios eventos recebem um nome e até 20 propriedades (strings, números ou booleanos):
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:
import Purchases from "react-native-purchases"
Unolink.connectRevenueCat(Purchases)
O Unolink lê o ID na hora, a cada atualização das informações do cliente (compras, logIn, logOut) e sempre que o
app volta ao primeiro plano, 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 React Native.
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.getAppUserID())
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 link chega uma vez, na primeira abertura. No iPhone não há nenhum: a Apple não tem referrer de instalação, e o Unolink nunca faz fingerprinting.
link.deepLink é o que você definiu no link: um caminho como /promo/3for2, ou uma URL completa.
A primeira abertura geralmente começa no onboarding. Se a tela do link fica depois do onboarding ou do login, abra-o quando isso terminar e depois marque-o como consumido (0.3.1+):
// when onboarding (or sign-in) is done, and on every launch after that until it's consumed:
const link = Unolink.getPendingDeferredDeepLink()
if (link?.deepLink) {
router.push(link.deepLink) // a path; open a full URL with Linking.openURL
Unolink.consumeDeferredDeepLink()
}
A partir da 0.3.3, o link espera até você consumi-lo, mesmo que o app seja fechado nesse meio-tempo (até 30 dias depois da
instalação). 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 (nada de AsyncStorage). 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.
Com a 0.3.1 e a 0.3.2, ele fica guardado só durante a abertura atual do app.
Se a tela pode ser acessada de imediato, um listener basta. Os listeners são chamados uma vez por instalação. Com a 0.3.1,
um link que chegou antes da sua inscrição vai para o primeiro listener que você adicionar; com a 0.3.0, inscreva-se logo
após configure.
import { router } from "expo-router"
const subscription = Unolink.addDeferredDeepLinkListener((link) => {
// link.deepLink: "/promo/3for2", link.params: { offer: "3for2" }
// link.linkSlug: "tiktok" or null, link.clickId: "clk_01JA…"
if (link.deepLink) router.push(link.deepLink)
Unolink.consumeDeferredDeepLink()
})
// when the component unmounts
subscription.remove()
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 |
|---|---|
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). É lembrado entre aberturas do app. |
As chamadas nunca lançam exceções e nunca bloqueiam: os eventos ficam numa fila no dispositivo e são enviados em segundo plano pelo SDK nativo.
Jest
A partir da 0.3.1, o pacote tem o próprio mock, que registra todas as chamadas:
jest.mock("@unolink/react-native", () => require("@unolink/react-native/jest"))
// expect(Unolink.signUp).toHaveBeenCalledWith("apple")
Dispositivos de teste
As builds de desenvolvimento são dispositivos de teste (passe debug: __DEV__ antes da 0.3.1). As faixas de teste do
Google Play não podem ser reconhecidas no celular: passe debug: true nessas builds, por exemplo a partir de uma variável EXPO_PUBLIC_. 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
- "Native module not found" ou algo parecido? Você está no Expo Go, ou não recompilou desde a instalação. Faça uma development build. A partir da 0.3.1, o app não trava sem o módulo nativo: as chamadas não fazem nada e um aviso explica o motivo.
- Nada no painel? Ative Incluir dispositivos de teste: builds com
__DEV__ficam ocultas por padrão. - Ainda nada? Configure com
{ debug: __DEV__, logLevel: "debug" }e procure porUnolinkno console do Xcode ou no Logcat. Uma chave errada ou revogada aparece no log como erro.
Mais em Solução de problemas.