React Native und Expo
@unolink/react-native ist eine dünne Brücke über den nativen iOS- und Android-SDKs, die im Paket enthalten sind. Es braucht
kein Config-Plugin, keine Berechtigungen außer Internet und keine Einträge in Info.plist. Ab dem Pro-Tarif.
Voraussetzungen
- React Native 0.79+ (neue Architektur).
- Expo: ein Development Build,
npx expo prebuildoder EAS Build. In Expo Go läuft es nicht, weil es nativen Code enthält. - Ein SDK-Schlüssel: Öffne im Dashboard deine App → Einstellungen → SDK-Schlüssel → Neuer Schlüssel. Er wird nur einmal angezeigt, kopiere ihn also gleich.
Installieren
Expo:
npx expo install @unolink/react-native
npx expo prebuild # or: eas build
Reines React Native:
npm install @unolink/react-native
cd ios && pod install
Baue die App danach neu. Ein JavaScript-Reload reicht nach dem Hinzufügen von nativem Code nicht.
Wenn pod install mit einem Encoding-Fehler abbricht (Ruby 4 oder eine Locale ohne UTF-8), führe es in UTF-8 aus:
cd ios && LANG=en_US.UTF-8 pod install
Installiere nicht mit npm install --legacy-peer-deps: Es schreibt package-lock.json neu und lässt optionale Peer-Dependencies weg.
Konfigurieren
Ruf configure einmal auf, auf oberster Ebene, bevor dein erster Screen gerendert wird: in app/_layout.tsx mit Expo Router oder
in index.js.
import { Unolink } from "@unolink/react-native"
Unolink.configure("ulk_…", { debug: __DEV__ })
Ab 0.3.1:
- Aufrufe vor
configurewarten und werden direkt danach gesendet. Du kannst also problemlos zuerst eine Sitzung wiederherstellen. - Ein fehlender Schlüssel (zum Beispiel ein fehlender Eintrag in
.env) wird in der Konsole gemeldet, statt stillschweigend zu scheitern.Unolink.isConfigured()sagt, ob es läuft. debugist standardmäßig__DEV__.
Optionen
| Option | Standard | Was sie macht |
|---|---|---|
debug | __DEV__ (0.3.1+; davor false) | Markiert diese Installation als Testgerät. Dashboards blenden Testgeräte aus, solange Testgeräte einbeziehen nicht aktiv ist. |
logLevel | "warn" | Wie viel in der Xcode-Konsole oder in Logcat landet (Tag Unolink): "none", "error", "warn", "info", "debug". |
baseUrl | https://api.unolink.dev | Die SDK-API. Lass sie, wie sie ist. |
Der Schlüssel ist öffentlich: Er wird mit deiner App ausgeliefert und kann nur Daten für genau diese eine App melden. Siehe SDK-Schlüssel.
Funnel-Events
Füge an jedem wichtigen Moment eine Zeile hinzu. Daraus werden die Schritte in Funnel und Journeys.
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+)
Onboarding-Screens, ein Aufruf pro Screen, sobald er erscheint:
import { useOnboardingStep } from "@unolink/react-native"
useOnboardingStep("goal", { index: 0 }) // in each onboarding screen component
Unolink.onboardingSkipped("goal") // on Skip
Screen-IDs bestehen aus Buchstaben, Ziffern, _ und . (how_heard, nicht how-heard). In der Entwicklung mountet Reacts StrictMode
Screens zweimal, daher siehst du dort einen Screen eventuell doppelt gesendet; Release-Builds senden ihn einmal. Development Builds warnen in der
Konsole vor IDs oder Eigenschaften, die der Server ablehnen würde (0.3.1+).
Ohne RevenueCat meldest du Testphasen und Käufe selbst. Übergib den Betrag als String, damit er nie gerundet wird:
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")
Eigene Events nehmen einen Namen und bis zu 20 Eigenschaften (Strings, Zahlen oder Booleans):
Unolink.track("level_up", { level: 3 })
Die vollständige Liste mit den Namen, die im Dashboard ankommen, findest du unter Events.
Nutzer-ID und RevenueCat
Wenn du RevenueCat nutzt, verbinde es unter deiner App → Einstellungen → RevenueCat. Ruf dann nicht
purchase oder trialStarted auf: RevenueCat sendet Testphasen, Käufe, Verlängerungen, Kündigungen und Erstattungen selbst, und
Unolink ignoriert Kaufaufrufe aus der App, damit nichts doppelt zählt.
Um diese Käufe mit der Installation zu verknüpfen, melde RevenueCats eigene App-User-ID. Ab SDK 0.3.2 hält eine Zeile sie
aktuell. Ruf sie einmal beim Start auf, vor oder nach configure:
import Purchases from "react-native-purchases"
Unolink.connectRevenueCat(Purchases)
Unolink liest die ID sofort, bei jedem Update der Kundeninfos (Käufe, logIn, logOut) und jedes Mal, wenn die App wieder
in den Vordergrund kommt, und sendet sie nur, wenn sie sich geändert hat. Wenn RevenueCat noch nicht konfiguriert ist, schlägt das Lesen still fehl und wird später erneut versucht.
Der Aufruf gibt eine Funktion zurück, die die Verbindung trennt. Unolink.revenueCatUserChanged() ist auf React Native daher normalerweise nicht nötig.
Ohne sie (oder vor 0.3.2) ruf setUserId mit RevenueCats ID auf, nach Purchases.configure, nach jedem
Purchases.logIn und Purchases.logOut, und bei jedem Start. Nutze das eine oder das andere, nicht beides:
// after Purchases.configure, logIn and logOut, and on every launch
Unolink.setUserId(await Purchases.getAppUserID())
Für einen Gast ist das RevenueCats anonyme ID, sodass ein Kauf, der vor der Registrierung gemacht wird, sofort mit der
Installation verknüpft wird. Nach logIn ist es die ID des Kontos. Jede ID, die eine Installation gemeldet hat, zählt,
sodass der Kauf des Gasts verknüpft bleibt. Siehe Gäste und Konten.
Unolink speichert die ID selbst nie, nur einen Einweg-Hash, der für jede deiner Apps anders ist.
Deferred Deep Links
Wenn jemand unter Android über einen Unolink-Link mit Deeplink installiert, kommt der Link einmal an, beim ersten Öffnen. Auf dem iPhone gibt es keinen: Apple hat keinen Install-Referrer, und Unolink nutzt nie Fingerprinting.
link.deepLink ist das, was du am Link festgelegt hast: ein Pfad wie /promo/3for2 oder eine vollständige URL.
Der erste Start beginnt meistens im Onboarding. Wenn der Screen des Links hinter Onboarding oder Anmeldung liegt, öffne ihn, sobald das erledigt ist, und markiere ihn dann als verbraucht (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()
}
Ab 0.3.3 wartet der Link, bis du ihn als verbraucht markierst, auch wenn die App zwischendurch geschlossen wird (bis zu 30
Tage nach der Installation). Ein neuer Nutzer, der mitten im Onboarding aufhört, bekommt ihn beim nächsten Start trotzdem,
du musst ihn also nicht selbst speichern (kein eigener AsyncStorage-Speicher). Ruf consumeDeferredDeepLink() auf, sobald
du ihn geöffnet hast: Bis dahin gibt getPendingDeferredDeepLink() ihn bei jedem Start zurück. Vor configure und bis
Google Play geantwortet hat, ist er null. Mit 0.3.1 und 0.3.2 bleibt er nur für den aktuellen App-Start erhalten.
Wenn der Screen sofort erreichbar ist, reicht ein Listener. Listener werden einmal pro Installation aufgerufen. Mit 0.3.1
geht ein Link, der vor dem Abonnieren angekommen ist, an den ersten Listener, den du hinzufügst; mit 0.3.0 abonnierst du
direkt nach 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()
Leg Deeplink und Parameter des Links im Dashboard fest (Links → ⋯ → Bearbeiten). Wie es funktioniert, steht unter Deferred Deep Links unter Android.
Weitere Aufrufe
| Aufruf | Was er macht |
|---|---|
Unolink.getInstallId() | Die zufällige ID dieser Installation, oder null vor configure. Sie identifiziert keine Person und kein Gerät. |
Unolink.flush() | Sendet Events aus der Warteschlange sofort. Normalerweise nicht nötig. |
Unolink.setEnabled(false) | Schaltet das Tracking aus und löscht Events aus der Warteschlange, für deine Opt-out-Einstellung. Bleibt über App-Starts hinweg gespeichert. |
Aufrufe werfen nie Exceptions und blockieren nie: Events kommen auf dem Gerät in eine Warteschlange und werden vom nativen SDK im Hintergrund gesendet.
Jest
Ab 0.3.1 bringt das Paket ein eigenes Mock mit, das jeden Aufruf aufzeichnet:
jest.mock("@unolink/react-native", () => require("@unolink/react-native/jest"))
// expect(Unolink.signUp).toHaveBeenCalledWith("apple")
Testgeräte
Development Builds sind Testgeräte (übergib vor 0.3.1 debug: __DEV__). Test-Tracks von Google Play lassen sich auf dem Smartphone nicht
erkennen: Übergib in diesen Builds debug: true, zum Beispiel über eine EXPO_PUBLIC_-Variable. Ihre Daten sind echt, aber ausgeblendet, bis du Testgeräte
einbeziehen in Funnel und Journeys aktivierst. Mehr unter Testen.
Datenschutz
- Keine IDFA, keine Google Advertising ID, keine Abfrage für App Tracking Transparency, kein Fingerprinting.
- Eine zufällige Installations-ID, App-Version, OS-Version, SDK-Version, Smartphone oder Tablet, Sprache. Das Land kommt vom Netzwerk-Edge. IP-Adressen werden nie gespeichert.
- Unter iOS kommt das Privacy Manifest des nativen SDK mit dem Paket: Analysen, nicht mit der Identität verknüpft.
- Pack nie Namen, E-Mail-Adressen oder andere personenbezogene Daten in Event-Eigenschaften.
Fehlerbehebung
- „Native module not found“ oder Ähnliches? Du bist in Expo Go oder hast seit der Installation nicht neu gebaut. Erstelle einen Development Build. Ab 0.3.1 stürzt die App ohne das native Modul nicht ab: Aufrufe tun nichts, und eine Warnung sagt, warum.
- Nichts im Dashboard? Aktiviere Testgeräte einbeziehen:
__DEV__-Builds sind standardmäßig ausgeblendet. - Immer noch nichts? Konfiguriere mit
{ debug: __DEV__, logLevel: "debug" }und such in der Xcode-Konsole oder in Logcat nachUnolink. Ein falscher oder widerrufener Schlüssel wird als Fehler geloggt.
Mehr unter Fehlerbehebung.