Docs

React Native SDK 3.0

What changes when you move the Grovs React Native wrapper from 1.x to 3.0

3.0.0 is a major release of react-native-grovs-wrapper. It moves the native dependencies to the Grovs iOS SDK 3.0 and Android SDK 3.0.0, and with them inherits automatic screen tracking, consent gating, and clipboard-assisted deferred deep linking. One JavaScript signature changes: logInAppPurchase takes an object instead of a string. Everything else from 1.x still compiles, including the positional generateLink. Most apps upgrade by bumping the packages, updating the two native configure calls, and fixing their logInAppPurchase calls.

Requirements are unchanged: React Native 0.70 or later, iOS 13.0, Android 5.0 (API 21).

There is no 2.x. The wrapper goes from 1.x straight to 3.0.0 so that it shares a major version with the native SDKs it wraps.

Checklist

  1. Bump the packages: the wrapper, io.grovs:Grovs in your app's build.gradle, and the iOS pods.
  2. Update the native configure calls: turn native screen tracking off and pass the stored consent value.
  3. Update logInAppPurchase calls: the argument is now an object.
  4. Review your consent gating: setSDK is persisted, and three methods reject with SDK_DISABLED while disabled.
  5. Check the other behavior changes: the clipboard read on first launch, startDate on Android, and your store privacy declarations.

1. Bump the packages

Bash
npm install react-native-grovs-wrapper@^3.0.0
# or
yarn add react-native-grovs-wrapper@^3.0.0

Android. Your app declares its own dependency on the Grovs Android SDK because MainApplication and MainActivity call it directly. Move it from 1.1.1 to 3.0.0 in android/app/build.gradle:

Groovy
dependencies {
    implementation 'io.grovs:Grovs:3.0.0'
}

The wrapper is built against this exact coordinate, so keep the two in step. In 1.x the wrapper's own build.gradle hard-coded io.grovs:Grovs:1.1.1; it now reads the coordinate from its gradle.properties.

iOS. The podspec dependency moves from Grovs ~> 2.3 to Grovs ~> 3.0. Run:

Bash
cd ios && pod install

If pod install keeps a 2.x Grovs pinned in your Podfile.lock, run pod update Grovs.

Expo. The config plugin injects different configure calls in 3.0, but it never edits a file that already contains Grovs.configure. Regenerate the native projects:

Bash
npx expo prebuild --clean

Save any manual native edits first. The plugin also gained an optional clipboardDomains option; see Expo integration.

2. Update the native configure calls

Skipping this step changes behavior without any code edit on your side: the native SDKs' automatic screen tracking is on by default in 3.0.

Turn native screen tracking off. The native trackers only see the single Activity or view controller that hosts React Native, so leaving them on reports one meaningless screen. Pass autoTrackScreenViews: false and track screens from JavaScript with startScreenTracking or trackScreenView.

Pass the stored consent value. setSDK now persists its value, and the wrapper exposes it to native code as GrovsConsent.isEnabled(context) on Android and GrovsWrapperSwift.isSDKEnabled() on iOS. Pass it as enabled so a user who opted out stays opted out from the first frame of the next launch.

Kotlin
// 1.x
Grovs.configure(this, "your-api-key", useTestEnvironment = false)
 
// 3.0
import com.grovswrapper.GrovsConsent
 
Grovs.configure(
    this, "your-api-key", useTestEnvironment = false, baseURL = null,
    autoTrackScreenViews = false, clipboardDomains = null,
    enabled = GrovsConsent.isEnabled(this)
)
Swift
// 1.x
Grovs.configure(APIKey: "your-api-key", useTestEnvironment: false, delegate: nil)
 
// 3.0
import react_native_grovs_wrapper
 
Grovs.configure(
    APIKey: "your-api-key", useTestEnvironment: false,
    autoTrackScreenViews: false, clipboardDomains: nil,
    enabled: GrovsWrapperSwift.isSDKEnabled(), delegate: nil
)

The Android configure has no defaults after baseURL, so every parameter must be passed. Delegate handling is unchanged: keep delegate: nil (or GrovsWrapperSwift.shared, as the Expo plugin injects) and keep returning super.application(...). The MainActivity forwarding and the intent filters are unchanged too. See the Quick Start for the complete files.

3. Update logInAppPurchase calls

In 1.x the method took one string, and on Android that string was passed to the native SDK as the purchase JSON:

// 1.x
import { Platform } from 'react-native';
 
await Grovs.logInAppPurchase(Platform.OS === 'ios' ? transaction.id : purchase.originalJson);

In 3.0 it takes an InAppPurchase object with one field per platform:

// 3.0
import { Platform } from 'react-native';
import Grovs from 'react-native-grovs-wrapper';
 
await Grovs.logInAppPurchase(
    Platform.OS === 'ios'
        ? { transactionId: transaction.id }
        : { originalJson: purchase.originalJson }
);

The wrapper now validates before calling native: it rejects if transactionId is missing or not numeric on iOS, or if originalJson is missing on Android. A call that still passes a string fails to type-check and rejects at runtime. See Revenue.

setSDK(false) now stops everything natively. In the native SDKs the 1.x wrapper used (Android 1.1.1, iOS 2.x) it blocked link generation and deep link resolution but left lifecycle event collection running. In 3.0, while disabled, the native SDK does not authenticate, resolve the device, read the clipboard, or send lifecycle events, custom events, screen views, or purchases. Identifier, attributes, push token, and screen aliases are held and synced when you enable it again.

The value is persisted by the wrapper. setSDK writes the flag to SharedPreferences / UserDefaults, and the enabled parameter from step 2 reads it at the next launch. Without step 2, each launch starts enabled until your JavaScript calls setSDK(false).

Three methods reject while disabled. generateLink, displayMessages, and numberOfUnreadMessages reject with an error whose code is 'SDK_DISABLED' and whose message ends with Grovs SDK is disabled. Call setSDK(true) first. In 1.x the wrapper rewrapped every native error as a plain Error with only a message; the code property is new. track, trackScreenView, and the purchase methods do not reject; the native SDK sends nothing while disabled.

Enabling replays the launch link on Android only. setSDK(true) forwards onStart for the current Activity again, so a link the app was opened with while disabled is delivered. On iOS it is not replayed.

See Privacy & Consent.

5. Check the other behavior changes

Clipboard-assisted deferred deep linking is on. On the first launch after install, when fingerprint matching found nothing and the backend reports recent clicks on copy-to-clipboard links for your project, the native SDK reads the clipboard to attribute the install and delivers the match through onDeeplinkReceived. iOS may show its paste notice and Android 12 and later show the "pasted from your clipboard" toast once. If you never enable copy-to-clipboard for your project or its links, the clipboard is never read. See Clipboard-assisted deferred deep linking and Copy to Clipboard.

logCustomPurchase honors startDate on Android. In 1.x the Android bridge always used the current time; 3.0 parses the ISO 8601 string and falls back to now only if it cannot be parsed.

Events are batched and held during install attribution. These are native 3.0 behaviors; see the Android and iOS upgrade guides.

Update your store privacy declarations. Screen views and custom events are new categories of collection. Check your Google Play Data safety form and App Store privacy details against what the SDKs collect.

What's new in 3.0

Nothing here is required:

  • Custom events and screen tracking: track, trackScreenView, startScreenTracking for React Navigation, setGlobalTags, and setScreenAliases.
  • Consent gating: a persisted setSDK, the enabled wiring for native configure, and the SDK_DISABLED error code.
  • Clipboard-assisted deferred deep linking: deterministic install attribution on first launch, with clipboardDomains in the Expo plugin and the native configure calls for custom link domains.
  • generateLink(options): a GenerateLinkOptions object instead of eleven positional arguments, plus per-link copyToClipboardIos and copyToClipboardAndroid flags. The positional form still works and accepts the two flags at the end.
  • New types: GenerateLinkOptions, InAppPurchase, and NavigationContainerRefLike are exported.

Verifying the upgrade

Turn on info logging and watch the native logs (Logcat or Console.app, prefixed GROVS) and the Metro console (prefixed GROVS JS):

Grovs.setDebug('info');

Then check that deep links still reach your onDeeplinkReceived listener, that generateLink resolves, and, if you added startScreenTracking, that screen views appear in the dashboard under your route names. Use setScreenAliases to rename any you want to read differently.

See also

Edit this page on GitHubLast updated 2026-09-15