ScaleRocket/Mobile

Permissions

Demander les permissions d'app pour la caméra, les notifications et la localisation avec des patterns de dégradation gracieuse.

Permissions

Les applications mobiles doivent demander la permission avant d'accéder aux capacités de l'appareil comme la caméra, la localisation ou les notifications. ScaleRocket Mobile utilise l'API de permissions d'Expo pour une expérience multi-plateforme cohérente.

Comment fonctionnent les permissions

PlateformeComportement
iOSAffiche un dialogue système une seule fois. Si refusé, l'utilisateur doit aller dans Réglages
AndroidAffiche un dialogue système. Peut être "refusé définitivement" après deux refus

Les deux plateformes suivent le même pattern : vérifier, demander, gérer le refus.

Vérifier avant de demander

Vérifiez toujours l'état actuel avant d'afficher un prompt :

import * as ImagePicker from "expo-image-picker";

async function pickImage() {
  const { status } = await ImagePicker.getMediaLibraryPermissionsAsync();

  if (status !== "granted") {
    const { status: newStatus } = await ImagePicker.requestMediaLibraryPermissionsAsync();
    if (newStatus !== "granted") {
      Alert.alert(
        "Permission Required",
        "Please enable photo access in Settings to upload images.",
        [
          { text: "Cancel", style: "cancel" },
          { text: "Open Settings", onPress: () => Linking.openSettings() },
        ]
      );
      return;
    }
  }

  // Permission accordée — continuer
  const result = await ImagePicker.launchImageLibraryAsync();
}

Permissions courantes

Caméra

import { Camera } from "expo-camera";

const [permission, requestPermission] = Camera.useCameraPermissions();

if (!permission?.granted) {
  return (
    <View>
      <Text>Camera access is required to take photos</Text>
      <Button title="Grant Permission" onPress={requestPermission} />
    </View>
  );
}

Notifications push

import * as Notifications from "expo-notifications";

async function requestNotificationPermission() {
  const { status: existing } = await Notifications.getPermissionsAsync();
  let finalStatus = existing;

  if (existing !== "granted") {
    const { status } = await Notifications.requestPermissionsAsync();
    finalStatus = status;
  }

  if (finalStatus !== "granted") {
    console.log("Notification permission denied");
    return false;
  }

  return true;
}

Localisation

import * as Location from "expo-location";

async function requestLocation() {
  const { status } = await Location.requestForegroundPermissionsAsync();
  if (status !== "granted") {
    Alert.alert("Permission Denied", "Location access is needed for this feature.");
    return null;
  }

  const location = await Location.getCurrentPositionAsync({});
  return location;
}

Quand demander

Le timing compte pour le taux d'acceptation :

TimingTaux d'acceptationQuand l'utiliser
Au lancement de l'appFaibleJamais — les utilisateurs ne savent pas encore pourquoi
Avant la première utilisationÉlevéQuand l'utilisateur déclenche une fonctionnalité
Après explicationLe plus élevéMontrer pourquoi vous en avez besoin, puis demander

Pattern d'écran de pré-permission

Montrez une explication avant le dialogue système :

function CameraPermissionScreen({ onGranted }: { onGranted: () => void }) {
  const [permission, requestPermission] = Camera.useCameraPermissions();

  if (permission?.granted) {
    onGranted();
    return null;
  }

  return (
    <View style={{ flex: 1, justifyContent: "center", padding: 24 }}>
      <Ionicons name="camera" size={64} color="#3B82F6" />
      <Text style={{ fontSize: 20, fontWeight: "600", marginTop: 16 }}>
        Camera Access
      </Text>
      <Text style={{ color: "#6B7280", marginTop: 8 }}>
        We need camera access to scan QR codes and take profile photos.
      </Text>
      <Button title="Enable Camera" onPress={requestPermission} />
    </View>
  );
}

Dégradation gracieuse

Fournissez toujours une alternative quand la permission est refusée :

function AvatarUpload() {
  const [permission] = ImagePicker.useMediaLibraryPermissions();

  if (!permission?.granted) {
    return (
      <View>
        <Avatar name={user.name} size="lg" />
        <Text style={{ color: "#9CA3AF", marginTop: 8 }}>
          Enable photo access in Settings to upload a profile picture
        </Text>
      </View>
    );
  }

  return <AvatarWithUpload user={user} />;
}

Descriptions Info.plist iOS

iOS nécessite des descriptions lisibles pour chaque permission. Ajoutez-les dans app.json :

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSCameraUsageDescription": "We use the camera to take profile photos and scan QR codes",
        "NSPhotoLibraryUsageDescription": "We access your photos to let you upload a profile picture",
        "NSLocationWhenInUseUsageDescription": "We use your location to show nearby services",
        "NSFaceIDUsageDescription": "We use Face ID to secure your account"
      }
    }
  }
}

Important : Les apps avec des descriptions de permission vagues ou manquantes seront rejetées par Apple.

On this page