React Native SDK 0.1.0
Use @limelink/react-native to resolve LimeLink URLs and deferred deep links in iOS and Android React Native applications.
Requirements
| Requirement | Supported |
|---|---|
| React | 19.1.0 or later |
| React Native | 0.81.0 or later |
| Runtime | Hermes with the New Architecture |
| Host | React Native Community CLI or Expo Development Build |
| Android | API 24 or later |
| iOS | iOS 12 or later |
The package uses the Legacy Native Module interoperability layer under the New Architecture. It is not a direct TurboModule. Legacy Architecture, JSC, Expo Go, and web are unsupported.
React Native 0.81.0 is the declared installation floor. The 0.81.5 verification target passed Android Debug/Release and iOS clean pod installation, while its iOS simulator builds remain pending. Full Android and iOS build rows passed for RN 0.85 Community CLI and RN 0.86.2 packed-package fixtures. Expo SDK 57/RN 0.86 passed Development Build prebuild/build checks; this is build/configuration evidence rather than a separate Expo runtime matrix.
Install
npm install @limelink/react-native
yarn add @limelink/react-native
pnpm add @limelink/react-native
The wrapper pins Android SDK 0.4.0 and iOS SDK 0.4.0.
Community CLI Setup
Android repository
Add the public LimeLink Maven repository to dependencyResolutionManagement.repositories in android/settings.gradle:
maven {
url = uri("https://hellovelop.github.io/limelink-aos-sdk-binary/repository")
content { includeGroup("org.limelink") }
}
If your project uses project-level repositories, add the same entry to allprojects.repositories. No GitHub credentials are required.
Android warm links
Update MainActivity.kt so the current Activity retains every warm App Link Intent:
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
setIntent(intent)
}
Configure your app's App Link intent filters and domains separately. Android SDK 0.4.0 handles normal cold and warm App Link lifecycle delivery. Do not read Linking.getInitialURL() on Android and recreate it as a new Intent.
iOS autolinking
Run your normal CocoaPods installation after adding the package. React Native autolinking resolves the binary LimelinkIOSSDK CocoaPod at 0.4.0. Configure Associated Domains or URL schemes for your application; autolinking does not add them.
Expo Development Build Setup
Add the package to your Expo config, then create a Development Build:
{
"expo": {
"plugins": ["@limelink/react-native"]
}
}
The config plugin adds the LimeLink Maven repository and Android onNewIntent update idempotently. The current plugin requires a Kotlin MainActivity. Your app still owns Android intent filters and iOS Associated Domains. Expo Go and web cannot load this native package.
Initialize and Listen
Register the listener before initialization so startup results can be delivered. Use the canonical lowercase, hyphenated Project UUID from Project settings; this is a public resource identifier, not an Organization API credential.
import { useEffect } from 'react';
import { Linking, Platform } from 'react-native';
import LimeLink from '@limelink/react-native';
export function LimeLinkSetup() {
useEffect(() => {
const subscription = LimeLink.addLinkListener({
onDeeplinkReceived(result) {
authorizeAndNavigate(result.resolvedUri);
},
onDeferredDeepLinkNotFound() {
// Continue to the app's default destination.
},
onDeeplinkError(error) {
console.warn(error.code, error.message, error.platform);
},
});
LimeLink.initialize({
projectId: '12345678-1234-1234-1234-123456789abc',
loggingEnabled: false,
deferredDeeplinkEnabled: true,
});
let acceptInitialUrl = true;
const linkingSubscription =
Platform.OS === 'ios'
? Linking.addEventListener('url', ({ url }) => {
LimeLink.handleUniversalLink(url);
})
: undefined;
if (Platform.OS === 'ios') {
void Linking.getInitialURL().then((url) => {
if (acceptInitialUrl && url) LimeLink.handleUniversalLink(url);
});
}
return () => {
acceptInitialUrl = false;
linkingSubscription?.remove();
subscription.remove();
};
}, []);
return null;
}
isInitialized() synchronously reads native state. The JavaScript layer retains only the newest pending result, not-found event, and error in process memory until an eligible listener receives each category once. It is not persistent deferred storage.
Forward Links on iOS
iOS applications forward both the initial URL and later React Native Linking events. The setup component above initializes LimeLink first, installs one later-event listener before requesting the initial URL, and removes that listener during effect cleanup. Keeping all forwarding in that single iOS-only effect prevents rerenders from adding duplicate listeners; the cleanup guard also prevents a late getInitialURL() resolution from forwarding after unmount.
handleUniversalLink(url) is also available for explicitly supplied URLs. Android normal App Links should remain owned by the native cold/warm lifecycle described above.
Deferred Deep Links
Manual deferred handling returns a discriminated outcome:
const outcome = await LimeLink.handleDeferredDeepLink();
switch (outcome.status) {
case 'matched':
authorizeAndNavigate(outcome.result.resolvedUri);
break;
case 'notFound':
break;
case 'failed':
console.warn(outcome.error);
break;
}
Native listeners also receive manual deferred outcomes. Choose either the returned Promise or the listener as the navigation owner; using both for navigation can process one result twice. Malformed native outcomes and bridge failures may reject the Promise.
Destination Security
Treat resolvedUri as untrusted application input. Parse it and exactly compare its scheme and HTTPS host with an explicit app-owned allowlist before navigation. Reject unknown destinations and use a safe fallback. Do not authorize destinations with wildcards or string-prefix checks.
The wrapper performs no HTTP request, URL reconstruction, source-query merge, or persistent deferred storage. Native SDKs own Link resolution; your application owns destination authorization and navigation.
Public API
initialize(config: LimeLinkConfig): void
isInitialized(): boolean
addLinkListener(listener: LimeLinkListener): LimeLinkSubscription
handleUniversalLink(url: string): void
handleDeferredDeepLink(): Promise<DeferredDeepLinkOutcome>
LimeLinkConfig requires projectId and optionally accepts loggingEnabled and deferredDeeplinkEnabled. The listener requires onDeeplinkReceived; not-found and error callbacks are optional. The subscription exposes remove(): void.
A successful result includes optional originalUrl and resolvedUri, queryParams, pathParams, and isDeferred. Errors include numeric code, message, and platform (android or ios). Deferred status is exactly matched, notFound, or failed.
On Expo Go and web, isInitialized() returns false; the other methods throw an unsupported-native-build error.
Troubleshooting
- Invalid Project ID: copy the canonical lowercase, hyphenated UUID from Project settings. Do not use an Organization API key.
- Native module unavailable: confirm autolinking completed, install pods on iOS, and rebuild the native application. Expo Go is unsupported.
- Android warm links are missing: confirm
onNewIntentcallssetIntent(intent). - Expo prebuild rejects MainActivity: the current plugin supports Kotlin
MainActivityonly. - iOS links are missing: forward both initial and later
LinkingURLs after registering the LimeLink listener. - Navigation runs twice: make either listener delivery or the manual deferred Promise the sole navigation owner.