react-native-deeplink-manager
v1.0.0
Published
A comprehensive deep linking solution for React Native
Maintainers
Readme
react-native-deeplink-manager
A comprehensive deep linking solution for React Native that handles everything related to deep linking - from parsing URLs to navigation integration.
Features
- Universal Deep Link Support: Handle both custom schemes (
myapp://) and universal/app links (https://myapp.com) - Smart Routing: Pattern-based URL matching with path parameters (
:id) and query strings - Cold & Warm Start Handling: Seamlessly handle links whether your app is closed or running
- Navigation Adapters: Out-of-the-box support for React Navigation and Expo Router
- Link Building: Programmatically generate deep links with type safety
- Auth Guards: Run validation before navigation with
beforeNavigatehooks - Deferred Deep Links: Store and process links when app isn't ready
- TypeScript First: Full TypeScript support with excellent type inference
Installation
npm install react-native-deeplink-manager
# or
yarn add react-native-deeplink-managerQuick Start
With React Navigation
import { useRef, useEffect } from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import {
createDeepLinkHandler,
createReactNavigationAdapter,
createNavigationRef,
} from 'react-native-deeplink-manager';
const Stack = createNativeStackNavigator();
const navigationRef = createNavigationRef();
function App() {
useEffect(() => {
const handler = createDeepLinkHandler({
config: {
schemes: ['myapp'],
prefixes: ['https://myapp.com', 'https://www.myapp.com'],
routes: [
{ path: '/home', name: 'Home' },
{ path: '/user/:id', name: 'UserProfile' },
{ path: '/posts/:postId', name: 'PostDetail' },
],
},
});
const adapter = createReactNavigationAdapter(navigationRef);
handler.initialize(adapter);
return () => handler.destroy();
}, []);
return (
<NavigationContainer ref={navigationRef}>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="UserProfile" component={UserProfileScreen} />
<Stack.Screen name="PostDetail" component={PostDetailScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}With Expo Router
import { useEffect } from 'react';
import { useRouter } from 'expo-router';
import {
createDeepLinkHandler,
createExpoRouterAdapter,
} from 'react-native-deeplink-manager';
export default function Layout() {
const router = useRouter();
useEffect(() => {
const handler = createDeepLinkHandler({
config: {
schemes: ['myapp'],
prefixes: ['https://myapp.com'],
routes: [
{ path: '/', name: 'index' },
{ path: '/user/:id', name: 'user' },
{ path: '/posts/:postId', name: 'post' },
],
},
});
const adapter = createExpoRouterAdapter(router);
handler.initialize(adapter);
return () => handler.destroy();
}, []);
return <Slot />;
}Core Concepts
Route Configuration
Define your app's deep link routes with path patterns:
const routes = [
{
path: '/home',
name: 'Home',
exact: true, // Optional: exact match only
},
{
path: '/user/:id',
name: 'UserProfile',
},
{
path: '/posts/:postId/comments/:commentId',
name: 'CommentDetail',
},
];Path Parameters
Use :paramName syntax to capture dynamic segments:
// URL: myapp://myapp.com/user/123
// Route: /user/:id
// Extracted params: { id: '123' }
// URL: myapp://myapp.com/posts/456/comments/789
// Route: /posts/:postId/comments/:commentId
// Extracted params: { postId: '456', commentId: '789' }Query Parameters
Query parameters are automatically parsed:
// URL: myapp://myapp.com/search?q=react&category=mobile
// Extracted queryParams: { q: 'react', category: 'mobile' }Auth Guards
Add navigation guards with beforeNavigate:
const routes = [
{
path: '/profile',
name: 'Profile',
beforeNavigate: async (params) => {
const isAuthenticated = await checkAuth();
if (!isAuthenticated) {
// Navigate to login instead
return false;
}
return true;
},
},
];Advanced Usage
Building Deep Links
Generate deep links programmatically:
import { createDeepLinkBuilder } from 'react-native-deeplink-manager';
const builder = createDeepLinkBuilder('myapp', 'myapp.com');
// Simple path
const homeLink = builder.build('/home');
// Result: myapp://myapp.com/home
// With path params
const userLink = builder.build('/user/:id', { id: '123' });
// Result: myapp://myapp.com/user/123
// With query params
const searchLink = builder.build('/search', undefined, {
q: 'react native',
page: 1,
});
// Result: myapp://myapp.com/search?q=react%20native&page=1
// Combined
const link = builder.build(
'/user/:id/posts/:postId',
{ id: '123', postId: '456' },
{ ref: 'notification' }
);
// Result: myapp://myapp.com/user/123/posts/456?ref=notificationManual Link Handling
Handle links manually when needed:
const handler = createDeepLinkHandler({ config });
const adapter = createReactNavigationAdapter(navigationRef);
await handler.initialize(adapter);
// Handle a specific URL
await handler.handleLink('myapp://myapp.com/user/123');Deferred Deep Links
Handle links when your app isn't ready:
const handler = createDeepLinkHandler({ config });
// Store a link for later
handler.setPendingLink('myapp://myapp.com/user/123');
// Later, when ready...
const pendingLink = handler.getPendingLink();
if (pendingLink) {
await handler.handleLink(pendingLink);
handler.clearPendingLink();
}Custom Adapters
Create a custom navigation adapter:
import type { NavigationAdapter, RouteMatch } from 'react-native-deeplink-manager';
const customAdapter: NavigationAdapter = async (match: RouteMatch) => {
// Your custom navigation logic
const { route, params, queryParams } = match;
console.log('Navigating to:', route.name);
console.log('Params:', params);
console.log('Query:', queryParams);
// Implement your navigation
MyNavigator.navigate(route.name, { ...params, ...queryParams });
};
handler.initialize(customAdapter);Event Callbacks
Track deep link events:
const handler = createDeepLinkHandler({
config: {
schemes: ['myapp'],
routes: [...],
onLinkNotMatched: (url) => {
console.log('No route matched for:', url);
// Track analytics, show error, etc.
},
},
onColdStart: (url, match) => {
console.log('App opened from link:', url);
// Track app opens from links
},
onWarmStart: (url, match) => {
console.log('Link received while app running:', url);
// Track in-app deep links
},
});Working with the Router
Access the router directly for advanced use cases:
const handler = createDeepLinkHandler({ config });
const router = handler.getRouter();
// Add a route dynamically
router.addRoute({
path: '/new-feature',
name: 'NewFeature',
});
// Remove a route
router.removeRoute('OldFeature');
// Get all routes
const allRoutes = router.getRoutes();
// Match a URL
const match = router.match('myapp://myapp.com/user/123');
if (match) {
console.log('Route:', match.route.name);
console.log('Params:', match.params);
}
// Match and validate
const validMatch = await router.matchAndValidate(url);Platform Setup
iOS - Universal Links
- Add associated domains to your entitlements:
<!-- ios/YourApp/YourApp.entitlements -->
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:myapp.com</string>
<string>applinks:www.myapp.com</string>
</array>- Host an
apple-app-site-associationfile on your domain athttps://myapp.com/.well-known/apple-app-site-association
Android - App Links
- Add intent filters in
AndroidManifest.xml:
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" android:host="myapp.com" />
</intent-filter>- Host a
assetlinks.jsonfile athttps://myapp.com/.well-known/assetlinks.json
Custom URL Schemes
iOS
Add to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>Android
Add to AndroidManifest.xml:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>API Reference
createDeepLinkHandler(options: LinkHandlerOptions)
Creates a deep link handler instance.
Options:
config.schemes: Array of custom URL schemesconfig.prefixes: Array of universal link prefixesconfig.routes: Array of route configurationsconfig.onLinkNotMatched: Callback when no route matchesonColdStart: Callback for cold start linksonWarmStart: Callback for warm start links
handler.initialize(adapter: NavigationAdapter)
Initialize the handler with a navigation adapter.
handler.destroy()
Clean up listeners and resources.
createReactNavigationAdapter(navigationRef, screenMapping?)
Create an adapter for React Navigation.
createExpoRouterAdapter(router, navigationType?)
Create an adapter for Expo Router.
createDeepLinkBuilder(scheme, host)
Create a link builder instance.
TypeScript Support
The library is written in TypeScript and provides full type definitions:
import type {
DeepLinkConfig,
RouteConfig,
RouteMatch,
NavigationAdapter,
} from 'react-native-deeplink-manager';License
MIT
Contributing
Contributions are welcome! Please open an issue or submit a PR.
Author
Oluwaseyi Roy (https://github.com/oluseyi-ged)
