Complete step-by-step guide to migrate your React Native app from Firebase Dynamic Links to Redirectly. Includes TypeScript code examples and troubleshooting tips.
This guide covers a basic migration. Complex setups with custom logic may require additional time for testing and verification.
15-30 minutes for basic migration, plus testing time
Remove the firebase/dynamic-links package from your project:
npm uninstall @react-native-firebase/dynamic-links firebase # or if using yarn yarn remove @react-native-firebase/dynamic-links firebase
Find and remove any Firebase initialization code from your app. Look for files like:
You can safely delete files that were only used for Firebase Dynamic Links initialization.
Add Redirectly SDK to your project:
npm install @redirectly/react-native # or if using yarn yarn add @redirectly/react-native
For React Native 0.60+, autolinking handles most of the setup. If you need manual linking:
cd ios && pod install && cd .. # or for android cd android && ./gradlew clean
Create a new file to manage Redirectly initialization:
import { Redirectly, DeepLinkData } from '@redirectly/react-native';
export class DeepLinkingService {
private static initialized = false;
static async initialize(apiKey: string): Promise<void> {
if (this.initialized) return;
await Redirectly.init({
apiKey: apiKey,
// Optional: set user for attribution tracking
userId: null,
});
this.initialized = true;
}
static async createLink(
path: string,
campaign?: string,
data?: Record<string, string>
): Promise<string> {
const link = await Redirectly.createLink({
path,
campaign,
data: data || {},
});
return link.url;
}
static onDeepLink(
callback: (deepLink: DeepLinkData) => void
): () => void {
return Redirectly.onDeepLink(callback);
}
static async getInitialLink(): Promise<DeepLinkData | null> {
return Redirectly.getInitialLink();
}
}Call the initialization in your main app component:
import React, { useEffect } from 'react';
import { SafeAreaView } from 'react-native';
import { DeepLinkingService } from './services/DeepLinkingService';
export default function App() {
useEffect(() => {
// Initialize Redirectly with your API key
DeepLinkingService.initialize('your-api-key-here');
}, []);
return (
<SafeAreaView style={{ flex: 1 }}>
{/* Your app content */}
</SafeAreaView>
);
}Your existing Firebase implementation:
import { useEffect } from 'react';
import dynamicLinks from '@react-native-firebase/dynamic-links';
import { useNavigation } from '@react-navigation/native';
export const useFirebaseDeepLinks = () => {
const navigation = useNavigation();
useEffect(() => {
let unsubscribe: (() => void) | undefined;
dynamicLinks()
.getInitialLink()
.then((link) => {
if (link?.url != null) {
handleDeepLink(link.url);
}
});
unsubscribe = dynamicLinks().onLink((link) => {
const { url } = link;
handleDeepLink(url);
});
return () => unsubscribe?.();
}, [navigation]);
const handleDeepLink = (url: string) => {
const parsedUrl = new URL(url);
const path = parsedUrl.pathname;
if (path.startsWith('/product/')) {
const productId = path.split('/')[2];
navigation.navigate('ProductScreen', { productId });
}
};
};Migrated to use Redirectly:
import { useEffect } from 'react';
import { useNavigation } from '@react-navigation/native';
import { DeepLinkingService } from '../services/DeepLinkingService';
import { DeepLinkData } from '@redirectly/react-native';
export const useRedirectlyDeepLinks = () => {
const navigation = useNavigation();
useEffect(() => {
// Handle initial deep link when app is launched from terminated state
DeepLinkingService.getInitialLink().then((deepLink) => {
if (deepLink) {
handleDeepLink(deepLink);
}
});
// Listen for deep links when app is already running
const unsubscribe = DeepLinkingService.onDeepLink((deepLink) => {
handleDeepLink(deepLink);
});
return unsubscribe;
}, [navigation]);
const handleDeepLink = (deepLink: DeepLinkData) => {
const { path, campaign, data } = deepLink;
// Log attribution data
if (campaign) {
console.log('User came from campaign:', campaign);
console.log('Additional data:', data);
}
// Route based on path
if (path.startsWith('/product/')) {
const productId = path.split('/')[2];
navigation.navigate('ProductScreen', { productId });
} else if (path.startsWith('/user/')) {
const userId = path.split('/')[2];
navigation.navigate('UserProfile', { userId });
} else {
navigation.navigate('Home');
}
};
};Creating links with Firebase:
const shareProduct = async (productId: string, productName: string) => {
const link = await dynamicLinks().buildLink({
link: `https://yourdomain.com/product/${productId}`,
domainUriPrefix: 'https://yourdomain.page.link',
android: {
packageName: 'com.example.myapp',
fallbackUrl: 'https://yourdomain.com/fallback',
},
ios: {
bundleId: 'com.example.MyApp',
fallbackUrl: 'https://yourdomain.com/fallback',
appStoreId: '123456789',
},
});
return link;
};Creating links with Redirectly:
const shareProduct = async (productId: string, productName: string) => {
const linkUrl = await DeepLinkingService.createLink(
`/product/${productId}`,
'social_share', // campaign identifier
{
productName,
timestamp: new Date().toISOString(),
}
);
return linkUrl;
};1. Build and run your app on a test device:
npm run android # or for iOS npm run ios
2. Test initial deep link:
adb shell am start -W -a android.intent.action.VIEW -d "redirectly://product/123" com.example.myapp
3. Test deep link while app is running:
Create a link via Redirectly dashboard, share it, and tap to verify navigation works.
Your React Native app is now using Redirectly instead of Firebase Dynamic Links. Check out our advanced guides for more features.