0 XP
?
Développement Mobile React Native/Fonctionnalités natives
Intermédiaire60 min45 XP

Objectifs de cette leçon

  • Accéder à la caméra, géolocalisation et capteurs
  • Utiliser les modules natifs via Expo
  • Comprendre les bridge natif

Fonctionnalités natives 📷

Le vrai pouvoir du mobile, c'est d'accéder au matériel du téléphone : caméra, GPS, notifications, empreinte digitale...


1. Permissions — la porte d'entrée 🚪

' Avant d'accéder à une fonctionnalité native,
' il faut DEMANDER LA PERMISSION à l'utilisateur !
' iOS : demande automatique + explication dans Info.plist
' Android : déclaration dans AndroidManifest.xml
``'

```text
' Cycle de vie d'une permission :
' 1. Vérifier si la permission est déjà accordée
' 2. Si non, demander avec une explication
' 3. L'utilisateur accepte ou refuse
' 4. Réagir en conséquence

' Conseils :
' • Expliquer POURQUOI tu as besoin de la permission
' • Gérer le cas où l'utilisateur refuse
' • Ne pas demander au lancement, mais au moment utile
``'

```tsx
import * as Location from "expo-location";
import { Alert, Linking } from "react-native";

async function demanderPermissionLocalisation() {
  const { status } = await Location.requestForegroundPermissionsAsync();

  if (status !== "granted") {
    Alert.alert(
      "Permission refusée",
      "Nous avons besoin de votre localisation pour fonctionner. Activez-la dans les paramètres.",
      [
        { text: "Annuler", style: "cancel" },
        { text: "Paramètres", onPress: () => Linking.openSettings() },
      ],
    );
    return false;
  }
  return true;
}
``'

---

## 2. Caméra — prendre des photos 📸

tsx
import { CameraView, useCameraPermissions } from "expo-camera";
import { useState, useRef } from "react";
import { View, Text, TouchableOpacity, Image, StyleSheet } from "react-native";

function AppareilPhoto() {
  const [permission, requestPermission] = useCameraPermissions();
  const cameraRef = useRef<CameraView>(null);
  const [photo, setPhoto] = useState<string | null>(null);

  if (!permission) return <Text>Chargement...</Text>;
  if (!permission.granted) {
    return (
      <View>
        <Text>Permission caméra requise</Text>
        <TouchableOpacity onPress={requestPermission}>
          <Text>Autoriser</Text>
        </TouchableOpacity>
      </View>
    );
  }

  const prendrePhoto = async () => {
    if (cameraRef.current) {
      const resultat = await cameraRef.current.takePictureAsync();
      setPhoto(resultat.uri);
    }
  };

  return (
    <View style={styles.container}>
      <CameraView ref={cameraRef} style={styles.camera} facing="back">
        <TouchableOpacity style={styles.bouton} onPress={prendrePhoto}>
          <Text style={styles.texte}>📸</Text>
        </TouchableOpacity>
      </CameraView>

      {photo && <Image source={{ uri: photo }} style={styles.apercu} />}
    </View>
  );
}
``'

---

## 3. Géolocalisation — où suis-je ? 📍

```tsx
import * as Location from "expo-location";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import MapView, { Marker } from "react-native-maps";

function CartePosition() {
  const [position, setPosition] = useState<Location.LocationObject | null>(null);

  const obtenirPosition = async () => {
    const aPermission = await demanderPermissionLocalisation();
    if (!aPermission) return;

    const loc = await Location.getCurrentPositionAsync({
      accuracy: Location.Accuracy.High,  // Haute précision (GPS)
    });
    setPosition(loc);
  };

  return (
    <View style={styles.container}>
      <TouchableOpacity onPress={obtenirPosition}>
        <Text>📍 Ma position</Text>
      </TouchableOpacity>

      {position && (
        <MapView
          style={styles.carte}
          initialRegion={{
            latitude: position.coords.latitude,
            longitude: position.coords.longitude,
            latitudeDelta: 0.01,
            longitudeDelta: 0.01,
          }}
        >
          <Marker
            coordinate={{
              latitude: position.coords.latitude,
              longitude: position.coords.longitude,
            }}
            title="Je suis ici !"
          />
        </MapView>
      )}
    </View>
  );
}
``'

---

## 4. Notifications push 🔔

```text
' Notifications push = messages qui arrivent
' même quand l'app est fermée !

' Types :
' • Locales : programmées par l'app (rappel)
' • Distantes : envoyées par un serveur (FCM/APNs)
' • Avec ou sans intervention utilisateur
``'

```tsx
import * as Notifications from "expo-notifications";
import { useEffect } from "react";
import { Platform } from "react-native";

// Configuration des notifications
Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldShowAlert: true,
    shouldPlaySound: true,
    shouldSetBadge: true,
  }),
});

async function configurerNotifications() {
  // Demander la permission
  const { status } = await Notifications.requestPermissionsAsync();
  if (status !== "granted") return;

  // Obtenir le token (à envoyer au serveur)
  const token = await Notifications.getExpoPushTokenAsync();
  console.log("Token de notification :", token.data);

  // Envoyer ce token à votre API :
  await fetch("https://api.exemple.com/notifications/token", {
    method: "POST",
    body: JSON.stringify({ token: token.data }),
  });
}

// Envoyer une notification locale
async function notificationLocale() {
  await Notifications.scheduleNotificationAsync({
    content: {
      title: "Rappel 📅",
      body: "N'oublie pas de réviser React Native !",
      data: { screen: "Profil", userId: 42 },
    },
    trigger: { seconds: 60 },  // Dans 1 minute
  });
}
``'

---

## 5. Biométrie : Face ID / Touch ID 👆

```tsx
import * as LocalAuthentication from "expo-local-authentication";

async function authentifier() {
  // Vérifier si la biométrie est disponible
  const compatible = await LocalAuthentication.hasHardwareAsync();
  if (!compatible) {
    Alert.alert("Non compatible", "Votre appareil ne supporte pas la biométrie");
    return false;
  }

  // Vérifier si des empreintes/visages sont enregistrés
  const enregistres = await LocalAuthentication.isEnrolledAsync();
  if (!enregistres) {
    Alert.alert("Aucune donnée", "Aucune empreinte ou visage enregistré");
    return false;
  }

  // Authentifier
  const resultat = await LocalAuthentication.authenticateAsync({
    promptMessage: "Authentifiez-vous pour accéder à l'app",
    fallbackLabel: "Utiliser le code",
  });

  return resultat.success;
}

// Utilisation
function EcranSecurise() {
  const [acces, setAcces] = useState(false);

  useEffect(() => {
    authentifier().then(setAcces);
  }, []);

  if (!acces) return <Text>🔒 Authentification requise</Text>;
  return <Text>🔓 Contenu secret déverrouillé !</Text>;
}
``'

---

## Exercices pour toi 🎯

1. **Caméra** : crée une app qui prend une photo, l'affiche en aperçu et permet de la sauvegarder
2. **Carte** : affiche une carte avec la position actuelle et un marqueur "Je suis ici"
3. **Notifications + Biométrie** : crée un écran "secret" qui demande Face ID avant de s'afficher, puis envoie une notification locale de bienvenue

Création des variables pas à pas

Prêt à explorer la mémoire

Appuie sur Play pour voir les variables se créer une par une

0/5

Visualisation d'exécution

ligne 8
code
1import { CameraView, useCameraPermissions } from 'expo-camera';
2import * as Location from 'expo-location';
3import * as LocalAuthentication from 'expo-local-authentication';
4
5export default function App() {
6 const [permission, requestPermission] = useCameraPermissions();
7
8 if (!permission?.granted) {
9 return <Text onPress={requestPermission}>🔐 Activer la caméra</Text>;
10 }
11
12 return (
13 <CameraView style={{ flex: 1 }}>
14 <Text>📸 Caméra prête !</Text>
15 </CameraView>
16 );
17}
Variables
permission.granted=true/false
requestPermission=ouvre la popup système

🔐 Permissions

📸
Caméra
en attente...
🗺️
GPS
en attente...
🔔
Notifications
en attente...