Адаптер Supabase Postgres
Пакет tracelet_supabase предоставляет встраиваемый адаптер для синхронизации фоновых расположений непосредственно с Supabase Postgres с помощью функции RPC Postgres или Edge Function Supabase.
Установка
Добавьте адаптер в pubspec.yaml:
flutter pub add tracelet_supabaseЭтот адаптер использует supabase_flutter. Вы должны инициализировать клиент Supabase перед его использованием.
Как это работает
Адаптер подключается к энергосберегающему собственному механизму синхронизации HTTP Tracelet: buildHttpConfig создает HttpConfig, указывающий на конечную точку REST Supabase — либо /rest/v1/rpc/<function> (RPC), либо /functions/v1/<function> (Edge Function) — с установленными для вас заголовками apikey и Authorization: Bearer <token>.
Поскольку синхронизация выполняется на собственном движке, пакеты загружаются с экспоненциальной задержкой и постановкой в очередь в автономном режиме даже при принудительном закрытии. При 401 configureTokenRefresh обновляет сеанс Supabase — на переднем плане и в изолированном фоновом режиме — и повторяет попытку. Вы указываете ровно одну цель: rpcFunction или edgeFunction.
Настройка и конфигурация
Создайте таблицу и функцию приема
Создайте таблицу для получения местоположений, включите RLS и добавьте функцию Postgres, которая вставляет входящий пакет. Tracelet отправляет пакет объектов местоположения, поэтому функция принимает массив jsonb:
-- Table
CREATE TABLE public.locations (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
user_id uuid REFERENCES auth.users NOT NULL DEFAULT auth.uid(),
latitude double precision NOT NULL,
longitude double precision NOT NULL,
accuracy double precision,
speed double precision,
timestamp timestamptz NOT NULL,
is_moving boolean,
created_at timestamptz DEFAULT now()
);
ALTER TABLE public.locations ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Users insert their own locations" ON public.locations
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- RPC function: receives the batch as a jsonb array and inserts each row.
-- (The exact field names come from Tracelet's sync payload — see the
-- Tracelet Sync docs for the payload schema.)
CREATE OR REPLACE FUNCTION public.insert_tracelet_locations(payload jsonb)
RETURNS void
LANGUAGE sql
SECURITY INVOKER
AS $$
INSERT INTO public.locations (latitude, longitude, accuracy, speed, timestamp, is_moving)
SELECT
(e->'coords'->>'latitude')::double precision,
(e->'coords'->>'longitude')::double precision,
(e->'coords'->>'accuracy')::double precision,
(e->'coords'->>'speed')::double precision,
(e->>'timestamp')::timestamptz,
(e->>'is_moving')::boolean
FROM jsonb_array_elements(payload) AS e;
$$;Предпочитаете более индивидуальную обработку (проверку, разветвление, обогащение)? Вместо этого разверните Supabase Edge Function и передайте ее имя как edgeFunction — адаптер отправит пакет POST в /functions/v1/<name>.
Инициализировать Супабазу
Инициализируйте клиент Supabase в main.dart:
import 'package:supabase_flutter/supabase_flutter.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'https://xyzcompany.supabase.co',
anonKey: 'public-anon-key',
);
runApp(const MyApp());
}Настройте обновление токена и создайте конфигурацию HTTP
Вызовите configureTokenRefresh() один раз, создайте HttpConfig, предназначенный для вашего RPC (или Edge Function), и передайте его Tracelet.ready:
import 'package:tracelet_supabase/tracelet_supabase.dart';
import 'package:tracelet/tracelet.dart';
const supabaseUrl = 'https://xyzcompany.supabase.co';
const supabaseAnonKey = 'public-anon-key';
// 1. Keep the Supabase session token fresh in the background (resolves 401s).
await TraceletSupabase.configureTokenRefresh(anonKey: supabaseAnonKey);
// 2. Build the native HTTP config. Provide EITHER rpcFunction OR edgeFunction.
final httpConfig = TraceletSupabase.buildHttpConfig(
supabaseUrl: supabaseUrl,
anonKey: supabaseAnonKey,
rpcFunction: 'insert_tracelet_locations', // ...or: edgeFunction: 'tracelet-ingest'
// autoSync: true, batchSync: true, maxBatchSize: 250 are the defaults
);
// 3. Start Tracelet with the adapter's HTTP config.
await Tracelet.ready(Config(
geo: const GeoConfig(distanceFilter: 50),
http: httpConfig,
));
await Tracelet.start();Прикрепление пользовательских метаданных
Чтобы пометить каждое местоположение бизнес-данными (например, driver_id или trip_id), используйте setRouteContext() — он проходит с каждым местоположением через очередь SQLite и включается в полезную нагрузку, которую получает ваша функция:
await Tracelet.setRouteContext(RouteContext(
taskId: 'order_123',
custom: {'trip_id': 'trip_456'},
));Производительность
Синхронизация выполняется через пакетный механизм Tracelet, поэтому накопившиеся автономные точки сбрасываются пакетами (по умолчанию maxBatchSize: 250), а не по одному запросу на точку. В сочетании с массовой вставкой Postgres внутри вашего RPC это обеспечивает эффективное высокочастотное отслеживание (например, точка каждые 10 м) как для батареи устройства, так и для передачи данных туда и обратно.