Nowy standard. Twoje centrum tworzenia inteligentnego, szybkiego i zrównoważonego oprogramowania AI
Table of Contents
and 8 more
Supabase zapewnia aplikacji Flutter hostowaną bazę danych PostgreSQL, uwierzytelnianie, przechowywanie plików i aktualizacje w czasie rzeczywistym, a do wszystkiego możesz się dostać z poziomu pakietu supabase_flutter, bez pisania serwera.
Dla zespołów, których wąskim gardłem są zasoby backendowe, oznacza to, że jeden deweloper Fluttera może dostarczać funkcje end-to-end.
W tym przewodniku przejdziesz przez konfigurację, a potem przez kwestie bezpieczeństwa i ustawienia potrzebne w aplikacji produkcyjnej. Cały kod opiera się na supabase_flutter v2 (2.18.3 w chwili pisania).
Podsumowanie
Supabase to platforma backendowa open source oparta na PostgreSQL, która obejmuje uwierzytelnianie, storage, subskrypcje w czasie rzeczywistym i serverless Edge Functions, dzięki czemu wiele aplikacji Flutter możesz uruchomić bez własnego backendu.
Ma to jednak swoją cenę: bezpieczeństwo przenosi się do bazy danych. To polityki Row Level Security (RLS), a nie warstwa API, decydują o tym, kto i co może odczytać.
Jeśli włączysz RLS na każdej tabeli, nie umieścisz tajnych kluczy w pliku binarnym aplikacji i przetestujesz deep linki na każdej platformie, zyskasz produkcyjny backend bez konieczności jego budowania. Jeśli pominiesz pierwszy krok, wdrożysz publicznie zapisywalną bazę danych.
Dlaczego zespoły Fluttera wybierają Supabase jako backend?
Zespoły Fluttera wybierają Supabase, bo usuwa backend z listy zależności potrzebnych do dostarczania funkcji: auth, relacyjna baza danych i storage są gotowe już w dniu utworzenia projektu, co ma największe znaczenie, gdy ścigasz się z czasem, by uruchomić MVP. Flutter już teraz pozwala jednemu zespołowi dostarczać aplikacje na iOS i Androida z jednej bazy kodu. Właśnie tak stworzyliśmy dwujęzyczną aplikację do inwestowania w nieruchomości na obie platformy w mniej niż 12 tygodni. Dzięki Supabase deweloper Fluttera może zmienić schemat za pomocą migracji SQL, zamiast czekać na wdrożenie backendu.
Model relacyjny to główna różnica względem Firestore z Firebase. Jeśli twoje dane mają rzeczywiste relacje, na przykład między użytkownikami, organizacjami, zamówieniami czy uprawnieniami, joiny i ograniczenia w Postgresie oszczędzają ci pracy związanej z denormalizacją, którą magazyn dokumentowy przerzuca na klienta. Supabase obsługuje też długą listę dostawców uwierzytelniania, w tym Google, Apple, Azure, GitHub i Slack.
Nie jest to rozwiązanie pozbawione kompromisów. Nadal potrzebujesz osoby, która dobrze zna SQL i RLS, a rozbudowana, niestandardowa logika serwerowa i tak trafi do Edge Functions albo do osobnej usługi.
Jak skonfigurować projekt Supabase dla aplikacji Flutter?
Utwórz projekt w panelu Supabase, wybierz region najbliższy twoim użytkownikom, bo to tam będą działać baza danych, auth i storage, a potem utwórz swoje tabele.
Tworzenie tabeli z Row Level Security w SQL Editorze
Otwórz SQL Editor i uruchom skrypt podobny do tego poniżej. Tabele utworzone w SQL mają domyślnie wyłączone RLS, co oznacza, że każdy, kto ma publiczny klucz twojej aplikacji, może je odczytywać i zapisywać. Włącz RLS w tym samym skrypcie:
create table colors (
id serial primary key,
name varchar(255) not null
);
alter table colors enable row level security;
-- Allow anyone using the app to read colors (but not write them)
create policy "Colors are readable by everyone"
on colors for select
using (true);
insert into colors (name) values ('red'), ('blue'), ('green');Gdy RLS jest włączone, ale nie ma żadnej polityki, tabela nie zwraca nic przez API. To bezpieczne ustawienie domyślne i dlatego zapytanie, które „działało w panelu”, może zwrócić pustą listę w aplikacji. Zajrzyj do przewodnika po RLS w Supabase, jeśli chcesz tworzyć polityki ograniczone do zalogowanego użytkownika.
Konfiguracja przekierowań uwierzytelniania
W sekcji Authentication > URL Configuration dodaj adres URL przekierowania swojej aplikacji, na przykład io.supabase.flutter://login-callback/. Potwierdzenia e-mail, magic linki i OAuth odsyłają użytkownika właśnie pod ten adres, więc musi on odpowiadać schematowi deep linku, który skonfigurujesz później.
Jak połączyć aplikację Flutter z Supabase?
Dodaj pakiet do pubspec.yaml:
dependencies:
supabase_flutter: ^2.18.3Zainicjalizuj Supabase przed runApp(), używając adresu URL projektu i klucza publishable (sb_publishable_...). Oba znajdziesz w oknie Connect w panelu. Poza tutorialem przekazuj je osobno dla każdego środowiska za pomocą flagi dart-define-from-file, zamiast wpisywać je na stałe w kodzie:
import 'package:flutter/material.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
publishableKey: 'YOUR_SUPABASE_PUBLISHABLE_KEY',
);
runApp(const MyApp());
}
final supabase = Supabase.instance.client;Pobieranie danych w aplikacji Flutter
Odpytaj tabelę za pomocą from().select(), a wynik wyrenderuj przy użyciu FutureBuilder, jednego z podstawowych widgetów Fluttera do pracy z danymi asynchronicznymi:
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final _future = supabase.from('colors').select();
@override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Map<String, dynamic>>>(
future: _future,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final colors = snapshot.data!;
return ListView.builder(
itemCount: colors.length,
itemBuilder: (context, index) =>
ListTile(title: Text(colors[index]['name'] as String)),
);
},
),
);
}
}Jak działa uwierzytelnianie Supabase we Flutterze?
Supabase Auth wystawia sesję, czyli token dostępu i token odświeżania, które supabase_flutter automatycznie zapisuje i odświeża. Każde żądanie do bazy danych zawiera wtedy tożsamość użytkownika, którą sprawdzają twoje polityki RLS.
Logowanie za pomocą e-maila i hasła to jedno wywołanie:
Future<void> signInWithEmail(String email, String password) async {
await supabase.auth.signInWithPassword(email: email, password: password);
}W przypadku zewnętrznych dostawców signInWithOAuth() otwiera w przeglądarce stronę logowania dostawcy, a potem wraca do twojej aplikacji przez adres URL przekierowania:
Future<void> signInWithGitHub() async {
await supabase.auth.signInWithOAuth(
OAuthProvider.github,
redirectTo: 'io.supabase.flutter://login-callback/',
);
}W przypadku Google i Apple na urządzeniach mobilnych lepiej użyć natywnego logowania: pobierz token ID z SDK danej platformy i przekaż go do signInWithIdToken(). Dzięki temu użytkownik pozostaje w aplikacji, zamiast być przerzucanym do przeglądarki. Konfigurację dostawców opisują przewodniki Supabase dla Google i Apple.
Jak przesyłać dane Supabase w czasie rzeczywistym do Fluttera?
Dodaj tabelę do publikacji supabase_realtime (Database > Publications w panelu, zobacz dokumentację Realtime), a następnie użyj stream() z StreamBuilder. Strumień emituje przy każdej zmianie pełny, aktualny zestaw wyników i respektuje polityki RLS:
final _stream = supabase.from('colors').stream(primaryKey: ['id']);
@override
Widget build(BuildContext context) {
return StreamBuilder<List<Map<String, dynamic>>>(
stream: _stream,
builder: (context, snapshot) {
// Build your UI from snapshot.data
return const SizedBox.shrink();
},
);
}Jeśli chcesz reagować na pojedyncze inserty, aktualizacje lub usunięcia zamiast za każdym razem odświeżać całą listę, zasubskrybuj kanał:
supabase
.channel('colors_changes')
.onPostgresChanges(
event: PostgresChangeEvent.all,
schema: 'public',
table: 'colors',
callback: (payload) {
final newRecord = payload.newRecord;
final oldRecord = payload.oldRecord;
// React to the change
},
)
.subscribe();Usuń kanał za pomocą supabase.removeChannel(), gdy widget jest niszczony, bo inaczej połączenia będą się nawarstwiać.
Jak wysyłać pliki do Supabase Storage z poziomu Fluttera?
Utwórz bucket w sekcji Storage w panelu, a następnie wyślij File, na przykład zwrócony przez image_picker, do ścieżki w jego obrębie:
Future<void> uploadAvatar(File file) async {
final userId = supabase.auth.currentUser!.id;
await supabase.storage
.from('avatars')
.upload('$userId/avatar.png', file, fileOptions: const FileOptions(upsert: true));
}Dostęp do Storage jest kontrolowany przez polityki RLS w tabeli storage.objects, tak samo jak w twoich własnych tabelach. Jeśli, tak jak wyżej, zaczniesz ścieżki od ID użytkownika, politykę „użytkownicy mogą zapisywać tylko we własnym folderze” sprowadzisz do jednej linijki. Przykłady znajdziesz w przewodniku po kontroli dostępu do Storage.
Kiedy aplikacja Flutter powinna używać Supabase Edge Functions?
Używaj Edge Functions wszędzie tam, gdzie logika wymaga tajnego klucza: przy wywołaniach do dostawcy płatności, wysyłce e-maili albo zapisie danych z podwyższonymi uprawnieniami. To funkcje TypeScript działające po stronie serwera na Deno, a z Fluttera wywołasz je przez supabase.functions.invoke('function-name'). Jeśli dana funkcja wymagałaby w przeciwnym razie umieszczenia tajnego klucza w aplikacji, powinna trafić do Edge Function.
Jak bezpiecznie przechowywać sesje Supabase we Flutterze?
Domyślnie supabase_flutter v2 zapisuje sesję w SharedPreferences, które nie jest szyfrowane i nie spełnia większości wymagań dotyczących bezpieczeństwa aplikacji mobilnych. Jeśli aplikacja przetwarza wrażliwe dane, zapisuj sesję w systemowym keychainie lub keystore przy użyciu flutter_secure_storage, rozszerzając LocalStorage i przekazując własną implementację przez authOptions:
class SecureLocalStorage extends LocalStorage {
final _storage = const FlutterSecureStorage();
@override
Future<void> initialize() async {}
@override
Future<String?> accessToken() =>
_storage.read(key: supabasePersistSessionKey);
@override
Future<bool> hasAccessToken() =>
_storage.containsKey(key: supabasePersistSessionKey);
@override
Future<void> persistSession(String persistSessionString) =>
_storage.write(key: supabasePersistSessionKey, value: persistSessionString);
@override
Future<void> removePersistedSession() =>
_storage.delete(key: supabasePersistSessionKey);
}
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
publishableKey: 'YOUR_SUPABASE_PUBLISHABLE_KEY',
authOptions: FlutterAuthClientOptions(localStorage: SecureLocalStorage()),
);Jeśli chcesz całkowicie wyłączyć utrwalanie sesji, przekaż w ten sam sposób EmptyLocalStorage().
Jak skonfigurować deep linki dla Supabase Auth we Flutterze?
Magic linki, potwierdzenia e-mail i przekierowania OAuth wracają do twojej aplikacji przez własny schemat URL, więc każda platforma musi go zarejestrować. supabase_flutter v2 automatycznie wykrywa callback uwierzytelniania, a ty zajmujesz się tylko konfiguracją platformy.
Android
Dodaj filtr intencji do głównej aktywności w pliku android/app/src/main/AndroidManifest.xml:
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="YOUR_SCHEME" android:host="YOUR_HOST" />
</intent-filter>Szczegóły znajdziesz w dokumentacji deep linków na Androidzie.
iOS i macOS
Zarejestruj schemat w ios/Runner/Info.plist (oraz w macos/Runner/Info.plist dla macOS):
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>YOUR_SCHEME</string>
</array>
</dict>
</array>Dostępne opcje opisuje przewodnik Apple o definiowaniu własnego schematu URL.
Windows
W Windowsie trzeba zmienić kod runnera i dodać wpis w rejestrze dla schematu. Postępuj zgodnie z konfiguracją Windows w app_links i zarejestruj schemat z poziomu aplikacji przy użyciu url_protocol albo z instalatora.
Co musi być gotowe, zanim aplikacja Flutter z Supabase trafi na produkcję?
Przed uruchomieniem przejdź przez tę checklistę, najlepiej w ramach security by design już od pierwszego sprintu:
Włącz RLS na każdej wystawionej tabeli i przetestuj polityki. Security Advisor w panelu wskazuje tabele bez RLS. Testuj polityki jako zalogowany użytkownik, a nie jako administrator w SQL Editorze, bo administrator je omija.
Nie umieszczaj tajnego klucza w aplikacji. Tajny klucz (
sb_secret_...albo starszy kluczservice_role) całkowicie omija RLS i można go wyciągnąć ze skompilowanego pliku binarnego. Używaj go wyłącznie w Edge Functions albo na własnym serwerze.Przejdź na nowe klucze API. Supabase wycofuje starsze klucze
anoniservice_roledo końca 2026 roku. Udostępnij wersje aplikacji korzystające z klucza publishable, zanim wyłączysz stare klucze, bo użytkownicy starszych wersji stracą dostęp dokładnie w momencie ich wyłączenia.Przechowuj schemat i polityki w migracjach wersjonowanych za pomocą Supabase CLI i używaj osobnych projektów dla środowiska stagingowego i produkcyjnego, zamiast edytować produkcję w panelu.
Przetestuj deep linki na każdej platformie. Błędny schemat może po cichu zepsuć magic linki i OAuth na jednej platformie, mimo że na pozostałych wszystko działa.
Potwierdź wymagania dotyczące zgodności z przepisami na początku. Hostowana platforma obsługuje obciążenia HIPAA w ramach Business Associate Agreement w płatnych planach, a dane są przechowywane w regionie wybranym przy tworzeniu projektu, którego później nie da się zmienić bez migracji. Jeśli twoje wymagania wykraczają poza ten zakres, zrób przegląd zgodności i bezpieczeństwa, zanim zdecydujesz się na wersję hostowaną albo self-hosted.
Najważniejsze wnioski
Supabase pozwala zespołowi Fluttera wdrożyć auth, bazę danych Postgres, storage i funkcje czasu rzeczywistego bez budowania backendu.
Bezpieczeństwo jest osadzone w bazie danych: o dostępie decydują polityki RLS, a tabele tworzone w SQL startują z wyłączonym RLS.
Nigdy nie umieszczaj w aplikacji Flutter tajnego klucza ani klucza
service_role. Logikę z podwyższonymi uprawnieniami przenieś do Edge Functions.Przejdź na klucze publishable, zanim starsze klucze zostaną wycofane z końcem 2026 roku.
Supabase oszczędza najwięcej czasu wtedy, gdy wąskim gardłem są zasoby backendowe, a nie złożoność backendu.
Kiedy Supabase ma sens w aplikacji Flutter?
Supabase sprawdza się w zespołach, które ogranicza brak zasobów backendowych, a nie złożoność backendu. Jeśli aplikacja potrzebuje auth, relacyjnej bazy danych, storage i aktualizacji w czasie rzeczywistym, platforma zapewnia wszystkie cztery elementy, a deweloper Fluttera może wziąć odpowiedzialność za całą funkcję. Aplikacje oparte na rozbudowanej, niestandardowej logice serwerowej, nietypowych modelach danych albo rygorystycznych wymaganiach infrastrukturalnych spędzą więcej czasu na obchodzeniu ograniczeń platformy, niż zaoszczędzą na samej konfiguracji.
W Monterail tworzymy aplikacje mobilne cross-platformowe we Flutterze i pomagamy zespołom zdecydować, gdzie powinien działać ich backend. Jeśli porównujesz Supabase z własnym backendem albo przygotowujesz aplikację Supabase do wdrożenia produkcyjnego, porozmawiaj z naszym zespołem.
FAQ: Supabase i Flutter



)

