Começar

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 prebuild ou 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 configure esperam 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.
  • debug tem __DEV__ como padrão.

Opções

OpçãoPadrãoO 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".
baseUrlhttps://api.unolink.devA 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.

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

ChamadaO 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 por Unolink no console do Xcode ou no Logcat. Uma chave errada ou revogada aparece no log como erro.

Mais em Solução de problemas.