Stockage
Stockage sécurisé des tokens avec SecureStore, préférences avec AsyncStorage et uploads de fichiers avec Supabase ou Convex.
Stockage
ScaleRocket Mobile utilise différentes solutions de stockage selon le type de données.
SecureStore (Tokens)
Les tokens d'authentification sont stockés avec expo-secure-store, qui fournit un stockage chiffré sur l'appareil. C'est plus sécurisé qu'AsyncStorage pour les données sensibles.
// lib/supabase.ts
import * as SecureStore from "expo-secure-store";
const SecureStoreAdapter = {
getItem: (key: string) => SecureStore.getItemAsync(key),
setItem: (key: string, value: string) => SecureStore.setItemAsync(key, value),
removeItem: (key: string) => SecureStore.deleteItemAsync(key),
};Le client Supabase utilise cet adaptateur automatiquement :
createClient(supabaseUrl, supabaseAnonKey, {
auth: {
storage: SecureStoreAdapter,
autoRefreshToken: true,
persistSession: true,
detectSessionInUrl: false,
},
});Note : SecureStore nécessite un build de développement. Il ne fonctionne pas dans Expo Go.
Limites de SecureStore
- iOS : Données stockées dans le Keychain (chiffrées, sauvegardées sur iCloud si activé)
- Android : Données stockées dans SharedPreferences avec chiffrement Android Keystore
- Limite de taille : 2KB par valeur. Pour des données plus volumineuses, utilisez AsyncStorage ou le stockage de fichiers
AsyncStorage (Préférences)
Pour les données non sensibles comme les préférences utilisateur, les paramètres de thème ou l'état d'onboarding, utilisez @react-native-async-storage/async-storage :
npx expo install @react-native-async-storage/async-storageimport AsyncStorage from "@react-native-async-storage/async-storage";
// Sauvegarder une préférence
await AsyncStorage.setItem("theme", "dark");
await AsyncStorage.setItem("onboarding_complete", "true");
// Lire une préférence
const theme = await AsyncStorage.getItem("theme");
// Supprimer une préférence
await AsyncStorage.removeItem("theme");Upload de fichiers
Utilisez Supabase Storage pour uploader des fichiers depuis l'appareil :
import * as ImagePicker from "expo-image-picker";
import { supabase } from "../lib/supabase";
async function uploadAvatar() {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 0.8,
});
if (result.canceled) return;
const file = result.assets[0];
const fileName = `${user.id}/avatar.jpg`;
const formData = new FormData();
formData.append("file", {
uri: file.uri,
name: "avatar.jpg",
type: "image/jpeg",
} as any);
const { error } = await supabase.storage
.from("avatars")
.upload(fileName, formData, { upsert: true });
if (error) throw error;
}Obtenez une URL publique pour les fichiers uploadés :
const { data } = supabase.storage
.from("avatars")
.getPublicUrl(`${user.id}/avatar.jpg`);
const avatarUrl = data.publicUrl;Utilisez Convex File Storage pour uploader des fichiers :
import * as ImagePicker from "expo-image-picker";
import { useMutation } from "convex/react";
import { api } from "../convex/_generated/api";
async function uploadAvatar() {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
quality: 0.8,
});
if (result.canceled) return;
const file = result.assets[0];
// Obtenir l'URL d'upload depuis Convex
const uploadUrl = await generateUploadUrl();
// Uploader le fichier
const response = await fetch(file.uri);
const blob = await response.blob();
const uploadResult = await fetch(uploadUrl, {
method: "POST",
body: blob,
headers: { "Content-Type": "image/jpeg" },
});
const { storageId } = await uploadResult.json();
// Sauvegarder le storage ID dans le profil utilisateur
await saveAvatar({ storageId });
}Quand utiliser quoi
| Type de données | Solution | Exemple |
|---|---|---|
| Tokens d'auth | SecureStore | Tokens de session, clés API |
| Préférences utilisateur | AsyncStorage | Thème, langue, état d'onboarding |
| Fichiers | Supabase Storage / Convex Files | Avatars, documents, images |
| État de l'app | État React / contexte | Données de l'écran actuel, champs de formulaire |