Cours React Native · Module 3: Navigation
Deep Linking - Les portails magiques
Dans cette leçon8
Le Deep Linking est comme les portails magiques d'Atlantis : il permet aux utilisateurs de sauter directement vers des écrans précis de l'application depuis des liens externes.
Qu'est-ce que le Deep Linking ?
Le Deep Linking permet de :
- Ouvrir l'application depuis des liens URL
- Naviguer directement vers un écran précis
- Passer des paramètres via l'URL
- Gérer les notifications push
Configuration dans Expo
// app.json
{
"expo": {
"scheme": "atlantis",
"web": {
"bundler": "metro"
}
}
}Configurer linking dans NavigationContainer
import { NavigationContainer, LinkingOptions } from '@react-navigation/native';
import * as Linking from 'expo-linking';
// Préfixe d'URL pour l'application
const prefix = Linking.createURL('/');
type RootStackParamList = {
Home: undefined;
Profile: { userId: string };
Item: { itemId: number };
Settings: undefined;
};
const linking: LinkingOptions<RootStackParamList> = {
prefixes: [prefix, 'atlantis://', 'https://atlantis.app'],
config: {
screens: {
Home: '',
Profile: 'user/:userId',
Item: {
path: 'item/:itemId',
parse: {
itemId: (itemId: string) => parseInt(itemId, 10),
},
},
Settings: 'settings',
// Navigateurs imbriqués
MainTabs: {
screens: {
Feed: 'feed',
Messages: 'messages/:conversationId?',
},
},
},
},
};
function App() {
return (
<NavigationContainer
linking={linking}
fallback={<LoadingScreen />}
>
<Stack.Navigator>
{/* Écrans */}
</Stack.Navigator>
</NavigationContainer>
);
}Formats d'URL pris en charge
atlantis:// → Home
atlantis://user/123 → Profile { userId: '123' }
atlantis://item/42 → Item { itemId: 42 }
atlantis://settings → Settings
atlantis://feed → MainTabs > Feed
atlantis://messages/abc → MainTabs > Messages { conversationId: 'abc' }Créer des liens au sein de l'application
import * as Linking from 'expo-linking';
function ShareButton({ itemId }: { itemId: number }) {
const handleShare = async () => {
// Lien interne (vers l'application)
const internalUrl = Linking.createURL(`item/${itemId}`);
console.log(internalUrl); // exp://192.168.1.5:8081/--/item/42
// Lien universel (web + application)
const universalUrl = `https://atlantis.app/item/${itemId}`;
// Partage
await Share.share({
message: `Regarde cet élément : ${universalUrl}`,
url: universalUrl,
});
};
return (
<Pressable onPress={handleShare}>
<Text>Partager</Text>
</Pressable>
);
}Ouvrir des URL externes
import * as Linking from 'expo-linking';
function ExternalLinks() {
const openWebsite = async () => {
await Linking.openURL('https://atlantis.app');
};
const openSettings = async () => {
// Ouvre les réglages système de l'application
await Linking.openSettings();
};
const sendEmail = async () => {
await Linking.openURL('mailto:contact@atlantis.app?subject=Question');
};
const makeCall = async () => {
await Linking.openURL('tel:+48123456789');
};
const openMaps = async () => {
// iOS
await Linking.openURL('maps://app?daddr=52.2297,21.0122');
// Android
await Linking.openURL('geo:52.2297,21.0122');
};
return (
<View>
<Pressable onPress={openWebsite}><Text>Site web</Text></Pressable>
<Pressable onPress={openSettings}><Text>Réglages</Text></Pressable>
<Pressable onPress={sendEmail}><Text>E-mail</Text></Pressable>
<Pressable onPress={makeCall}><Text>Appeler</Text></Pressable>
</View>
);
}Écouter les liens
import * as Linking from 'expo-linking';
import { useEffect } from 'react';
function App() {
useEffect(() => {
// Vérifier si l'application a été ouverte depuis un lien
const getInitialURL = async () => {
const initialUrl = await Linking.getInitialURL();
if (initialUrl) {
console.log('Ouvert depuis le lien :', initialUrl);
}
};
getInitialURL();
// Écouter les nouveaux liens (quand l'application est en arrière-plan)
const subscription = Linking.addEventListener('url', ({ url }) => {
console.log('Lien reçu :', url);
});
return () => subscription.remove();
}, []);
return <NavigationContainer linking={linking}>{/* ... */}</NavigationContainer>;
}Persistance de l'état (conserver l'état de navigation)
import AsyncStorage from '@react-native-async-storage/async-storage';
const NAVIGATION_STATE_KEY = 'NAVIGATION_STATE';
function App() {
const [isReady, setIsReady] = useState(false);
const [initialState, setInitialState] = useState();
useEffect(() => {
const restoreState = async () => {
try {
const savedState = await AsyncStorage.getItem(NAVIGATION_STATE_KEY);
if (savedState) {
setInitialState(JSON.parse(savedState));
}
} finally {
setIsReady(true);
}
};
restoreState();
}, []);
if (!isReady) return <LoadingScreen />;
return (
<NavigationContainer
initialState={initialState}
onStateChange={(state) => {
AsyncStorage.setItem(NAVIGATION_STATE_KEY, JSON.stringify(state));
}}
>
{/* ... */}
</NavigationContainer>
);
}Le Deep Linking améliore considérablement l'UX de ton application : il permet de partager du contenu précis et de s'intégrer aux notifications push.
Code de cette leçon : App.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import * as Linking from 'expo-linking';
const Stack = createNativeStackNavigator();
// Préfixe d'URL de l'application, ex. atlantis://item/42
const prefix = Linking.createURL('/');
const linking = {
prefixes: [prefix],
// TODO : complète la config qui associe les chemins aux écrans :
// config: {
// screens: {
// Home: '',
// Details: 'item/:itemId',
// },
// },
};
function HomeScreen() {
return (
<View style={styles.screen}>
<Text style={styles.title}>Portail de l'Atlantide</Text>
</View>
);
}
function DetailsScreen({ route }) {
return (
<View style={styles.screen}>
<Text style={styles.title}>Objet #{route.params?.itemId}</Text>
</View>
);
}
export default function App() {
return (
// TODO : transmets la prop linking={linking} à <NavigationContainer>
<NavigationContainer>
<Stack.Navigator>
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Details" component={DetailsScreen} />
</Stack.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
screen: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1a5276',
},
title: {
fontSize: 22,
color: '#fff',
fontWeight: '600',
},
});Entrées de la documentation utilisées dans cette leçon
Tu as repéré une erreur dans cette leçon ?
Teste tes connaissances
Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.
1. Que définit la propriété « scheme » dans app.json ?
2. Quelle méthode ouvre une URL externe ou une application ?
Tâches pratiques dans le jeu
- Tri horizontal
Range la création d'une URL à partager :
- Éditeur de code
Complète la configuration linking.