GUIDE

Votre première application avec Flutter

Une liste de tâches pour iPhone et Android où les gens s'inscrivent et ne voient que leurs propres tâches. Elle utilise le paquet Espobase pour Dart ; la base de données et les clés viennent du tableau de bord.

← Tous les guides

1. Créez un projet et une table

Dans le tableau de bord, créez un projet. Ouvrez Éditeur SQL et exécutez :

create table todos (
  id bigint generated by default as identity primary key,
  owner_id uuid not null default espobase.user_id(),
  title text not null,
  done boolean not null default false,
  created_at timestamptz not null default now()
);

-- Row level security is already on. Each signed-in user sees and changes only their own todos:
create policy "Users manage their own todos" on todos
  for all
  using (owner_id = espobase.user_id())
  with check (owner_id = espobase.user_id());

2. Réglages et clés

  • API : créez une clé publiable et copiez-la maintenant ; les clés ne sont affichées qu'à la création. Ne mettez jamais de clé secrète (eb_sk_…) dans une application : n'importe qui peut ouvrir une application et la lire.
  • Authentification › Réglages : ajoutez le lien de votre application dans URL de redirection autorisées, par exemple myapp://auth/callback. Les e-mails de confirmation et la connexion sociale y reviennent. Déclarez le même schéma dans vos projets Android et iOS.

3. Installez

Le paquet Espobase fonctionne sur toutes les plateformes Flutter. Les autres paquets protègent la session et ouvrent les pages de connexion :

flutter pub add espobase flutter_secure_storage flutter_web_auth_2 sign_in_with_apple

4. Le client

Par défaut, la session reste en mémoire. Donnez au client un stockage sécurisé et la personne reste connectée quand l'application redémarre. La session est renouvelée pour vous.

// lib/espobase.dart
import 'package:espobase/espobase.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureSessionStorage implements SessionStorage {
  final _store = const FlutterSecureStorage();
  @override Future<String?> get(String key) => _store.read(key: key);
  @override Future<void> set(String key, String value) => _store.write(key: key, value: value);
  @override Future<void> remove(String key) => _store.delete(key: key);
}

final espobase = EspobaseClient(
  const String.fromEnvironment('ESPOBASE_URL'), // https://api.espobase.com/project/<your project ref>
  const String.fromEnvironment('ESPOBASE_KEY'), // the PUBLISHABLE key (eb_pk_…): safe in an app
  options: ClientOptions(sessionStorage: SecureSessionStorage()),
);

5. Inscription et connexion

// myapp://auth/callback (the scheme is in your Android and iOS projects). Add it under Authentication › Settings.
const redirectTo = 'myapp://auth/callback';

await espobase.auth.signUp(email: email, password: password, redirectTo: redirectTo);
await espobase.auth.signInWithPassword(email: email, password: password);

// The confirmation email opens the app at redirectTo#type=signup&token=…
await espobase.auth.verifyEmail(token: token);

// Re-render when the user signs in or out.
espobase.auth.onAuthStateChange.listen((change) => setState(() => session = change.session));

Avec la confirmation par e-mail activée, la personne reçoit un lien qui ouvre votre application à l'adresse que vous avez passée comme redirectTo, avec le jeton après un #. Confirmez-le avec espobase.auth.verifyEmail(token: …).

6. Connexion avec Apple

Activez-la dans Authentification › Fournisseurs › Apple avec votre propre compte Apple Developer, et ajoutez-y le bundle ID de votre application. Donnez à Apple le nonce haché et à Espobase le nonce brut :

import 'package:sign_in_with_apple/sign_in_with_apple.dart';

Future<void> signInWithApple() async {
  final nonce = AppleNonce();
  final credential = await SignInWithApple.getAppleIDCredential(
    scopes: [AppleIDAuthorizationScopes.email],
    nonce: nonce.hashed, // Apple gets the hash …
  );
  await espobase.auth.signInWithIdToken(
    token: credential.identityToken!,
    nonce: nonce.raw, // … Espobase gets the raw value
  );
}

7. Connexion avec Google ou GitHub

import 'package:flutter_web_auth_2/flutter_web_auth_2.dart';

Future<void> signInWithGoogle() async {
  final url = await espobase.auth.signInWithOAuth(
    provider: OAuthProvider.google,
    redirectTo: 'myapp://auth/callback',
  );
  final result = await FlutterWebAuth2.authenticate(url: url.toString(), callbackUrlScheme: 'myapp');
  final code = Uri.parse(result).queryParameters['code'];
  if (code != null) await espobase.auth.exchangeCodeForSession(code);
}

Activez d'abord le fournisseur dans Authentification › Fournisseurs. L'application ouvre le fournisseur dans le navigateur du système et récupère la personne via le lien de votre application ; exchangeCodeForSession termine la connexion. Seule cette application peut la terminer : le secret à usage unique reste sur le téléphone.

8. Lisez et écrivez vos données

final todos = await espobase.from('todos').select().order('created_at'); // List<Map<String, dynamic>>

// owner_id fills itself in (its default is espobase.user_id()).
await espobase.from('todos').insert({'title': 'Buy milk'});
await espobase.from('todos').update({'done': true}).eq('id', todo['id']);
await espobase.from('todos').delete().eq('id', todo['id']);

Chaque requête porte la personne connectée, et la base de données applique votre règle. Une personne non connectée reçoit une liste vide, et personne ne peut lire ni modifier les tâches d'un autre, même en appelant directement l'API.

9. Envoyez une photo

Créez un bucket dans Storage et ajoutez une politique pour que chaque personne puisse écrire dans son propre dossier (voir le guide d'envoi de fichiers). Passez les octets du fichier à upload : Envoi de fichiers

final bytes = await pickedFile.readAsBytes();
final userId = (await espobase.auth.currentUser())!.id;
await espobase.storage.from('photos').upload('$userId/photo.jpg', bytes, contentType: 'image/jpeg');

Bon à savoir

  • Les erreurs sont des EspobaseException avec un code (par exemple invalid_credentials) et un message que vous pouvez afficher.
  • Le temps réel n'est pas encore dans ce paquet : utilisez l'API REST pour l'instant.
  • Le même paquet fonctionne en Dart côté serveur.