Deine erste App mit Flutter
Eine To-do-Liste für iPhone und Android, in der sich Leute registrieren und nur ihre eigenen Aufgaben sehen. Sie nutzt das Espobase-Paket für Dart; Datenbank und Schlüssel kommen aus dem Dashboard.
1. Projekt und Tabelle anlegen
Lege im Dashboard ein Projekt an. Öffne den SQL-Editor und führe aus:
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. Einstellungen und Schlüssel
- API: Erstelle einen veröffentlichbaren Schlüssel und kopiere ihn jetzt; Schlüssel werden nur beim Erstellen angezeigt. Lege nie einen geheimen Schlüssel (
eb_sk_…) in eine App: Jeder kann eine App entpacken und ihn lesen. - Authentifizierung › Einstellungen: Trage den Link deiner App unter Erlaubte Weiterleitungs-URLs ein, zum Beispiel
myapp://auth/callback. Bestätigungs-E-Mails und die Anmeldung über soziale Konten kehren dorthin zurück. Registriere dasselbe Schema in deinen Android- und iOS-Projekten.
3. Installieren
Das Espobase-Paket läuft auf allen Flutter-Plattformen. Die anderen Pakete halten die Sitzung sicher und öffnen die Anmeldeseiten:
flutter pub add espobase flutter_secure_storage flutter_web_auth_2 sign_in_with_apple
4. Der Client
Standardmäßig liegt die Sitzung im Speicher. Gib dem Client einen sicheren Speicher, und die Person bleibt beim Neustart der App angemeldet. Die Sitzung wird für dich erneuert.
// 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. Registrieren und anmelden
// 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));
Ist die E-Mail-Bestätigung aktiv, bekommt die Person einen Link, der deine App unter der Adresse öffnet, die du als redirectTo übergeben hast, mit dem Token nach einem #. Bestätige ihn mit espobase.auth.verifyEmail(token: …).
6. Mit Apple anmelden
Schalte es unter Authentifizierung › Anbieter › Apple mit deinem eigenen Apple-Developer-Konto ein und trage dort die Bundle-ID deiner App ein. Gib Apple den gehashten Nonce und Espobase den Rohwert:
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
);
}8. Daten lesen und schreiben
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']);Jede Anfrage trägt die angemeldete Person, und die Datenbank wendet deine Regel an. Wer nicht angemeldet ist, bekommt eine leere Liste, und niemand kann die Aufgaben eines anderen lesen oder ändern, auch nicht durch direkten Aufruf der API.
9. Ein Foto hochladen
Lege unter Storage einen Bucket an und füge eine Richtlinie hinzu, damit jede Person in ihren eigenen Ordner schreiben darf (siehe die Anleitung zu Datei-Uploads). Übergib die Bytes der Datei an upload: Datei-Uploads
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');Gut zu wissen
- Fehler sind
EspobaseExceptionmit einemcode(zum Beispielinvalid_credentials) und einermessage, die du anzeigen kannst. - Realtime ist in diesem Paket noch nicht enthalten: Nutze vorerst die REST-API.
- Dasselbe Paket läuft auch in Dart auf dem Server.
7. Mit Google oder GitHub anmelden
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); }Schalte zuerst den Anbieter unter Authentifizierung › Anbieter ein. Die App öffnet den Anbieter im System-Browser und holt die Person über den Link deiner App zurück;
exchangeCodeForSessionschließt die Anmeldung ab. Nur diese App kann sie abschließen: Das einmalige Geheimnis bleibt auf dem Telefon.