Интеграция Supabase в мобильное приложение

TRUETECH занимается разработкой, поддержкой и обслуживанием мобильных приложений iOS, Android, PWA. Имеем большой опыт и экспертизу для публикации мобильных приложений в популярные маркеты Google Play, App Store, Amazon, AppGallery и другие.
Разработка и поддержка любых видов мобильных приложений:
Информационные и развлекательные мобильные приложения
Новостные приложения, игры, справочники, онлайн-каталоги, погодные, фитнес и здоровье, туристические, образовательные, социальные сети и мессенджеры, квиз, блоги и подкасты, форумы, агрегаторы
Мобильные приложения электронной коммерции
Интернет-магазины, B2B-приложения, маркетплейсы, онлайн-обменники, кэшбэк-сервисы, биржи, дропшиппинг-платформы, программы лояльности, доставка еды и товаров, платежные системы
Мобильные приложения для управления бизнес-процессами
CRM-системы, ERP-системы, управление проектами, инструменты для команды продаж, учет финансов, управление производством, логистика и доставка, управление персоналом, системы мониторинга данных
Мобильные приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, платформы предоставления электронных услуг, платформы кешбека, видеохостинги, тематические порталы, платформы онлайн-бронирования и записи, платформы онлайн-торговли

Это лишь некоторые из типы мобильных приложений, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента.

Предлагаемые услуги
Показано 1 из 1 услугВсе 1735 услуг
Интеграция Supabase в мобильное приложение
Средняя
~3-5 рабочих дней
Часто задаваемые вопросы
Наши компетенции:
Этапы разработки
Последние работы
  • image_mobile-applications_feedme_467_0.webp
    Разработка мобильного приложения для компании FEEDME
    756
  • image_mobile-applications_xoomer_471_0.webp
    Разработка мобильного приложения для компании XOOMER
    624
  • image_mobile-applications_rhl_428_0.webp
    Разработка мобильного приложения для компании RHL
    1052
  • image_mobile-applications_zippy_411_0.webp
    Разработка мобильного приложения для компании ZIPPY
    947
  • image_mobile-applications_affhome_429_0.webp
    Разработка мобильного приложения для компании Affhome
    862
  • image_mobile-applications_flavors_409_0.webp
    Разработка мобильного приложения для компании FLAVORS
    445

Интеграция Supabase в мобильное приложение

Supabase позиционируется как open-source альтернатива Firebase. Под капотом — PostgreSQL, PostgREST для автогенерации REST API, Realtime через WebSocket (на основе Phoenix Channels), GoTrue для аутентификации и S3-совместимое объектное хранилище. Ключевое отличие от Firebase: реляционная база данных с полноценным SQL, внешними ключами и RLS (Row Level Security).

Инициализация в React Native

import { createClient } from '@supabase/supabase-js';
import AsyncStorage from '@react-native-async-storage/async-storage';
import 'react-native-url-polyfill/auto'; // обязательно для RN

export const supabase = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_ANON_KEY!,
  {
    auth: {
      storage: AsyncStorage, // хранение сессии
      autoRefreshToken: true,
      persistSession: true,
      detectSessionInUrl: false, // отключаем для RN (не браузер)
    },
  }
);

react-native-url-polyfill — обязателен: Supabase использует URL API, которого нет в Hermes/JSC без полифила. Без него — тихая ошибка при первом запросе.

Аутентификация и AppState

Supabase GoTrue рефрешит JWT автоматически. Но на iOS при длительном нахождении в фоне refresh-запрос может не выполниться. При возврате в foreground нужно явно проверить сессию:

useEffect(() => {
  const subscription = AppState.addEventListener('change', async (nextState) => {
    if (nextState === 'active') {
      // Принудительный refresh при возврате из фона
      await supabase.auth.getSession();
    }
  });

  const { data: authListener } = supabase.auth.onAuthStateChange((event, session) => {
    if (event === 'TOKEN_REFRESHED') {
      updateGlobalSession(session);
    }
    if (event === 'SIGNED_OUT') {
      clearLocalData();
      navigateToLogin();
    }
  });

  return () => {
    subscription.remove();
    authListener.subscription.unsubscribe();
  };
}, []);

Типизированные запросы через сгенерированные типы

Supabase CLI генерирует TypeScript-типы из схемы БД:

npx supabase gen types typescript --project-id YOUR_PROJECT_ID > database.types.ts
import type { Database } from './database.types';

const { data: posts, error } = await supabase
  .from<Database['public']['Tables']['posts']['Row']>('posts')
  .select('id, title, content, created_at, user_id')
  .eq('user_id', userId)
  .order('created_at', { ascending: false })
  .limit(20);

Типизация работает на уровне компилятора — неправильное имя столбца даёт ошибку TypeScript, не runtime. После изменения схемы нужно перегенерировать типы.

Realtime подписки

Supabase Realtime слушает PostgreSQL WAL (Write-Ahead Log) через logical replication и транслирует изменения клиентам:

useEffect(() => {
  const channel = supabase
    .channel(`posts:${userId}`)
    .on(
      'postgres_changes',
      {
        event: '*', // INSERT | UPDATE | DELETE
        schema: 'public',
        table: 'posts',
        filter: `user_id=eq.${userId}`,
      },
      (payload) => {
        if (payload.eventType === 'INSERT') {
          setPosts(prev => [payload.new as Post, ...prev]);
        } else if (payload.eventType === 'DELETE') {
          setPosts(prev => prev.filter(p => p.id !== payload.old.id));
        } else if (payload.eventType === 'UPDATE') {
          setPosts(prev => prev.map(p => p.id === payload.new.id ? payload.new as Post : p));
        }
      }
    )
    .subscribe();

  return () => { supabase.removeChannel(channel); };
}, [userId]);

Важно: Realtime передаёт только измененные строки, но payload.new содержит только поля, разрешённые через RLS. Если RLS ограничивает колонки — некоторые поля будут null в payload.

Row Level Security: защита на уровне БД

RLS — политики доступа на уровне PostgreSQL. Даже если клиент имеет anon key — без подходящей политики данные недоступны:

-- Включаем RLS для таблицы
ALTER TABLE posts ENABLE ROW LEVEL SECURITY;

-- Пользователь видит только свои посты
CREATE POLICY "user_can_read_own_posts"
ON posts FOR SELECT
USING (auth.uid() = user_id);

-- Пользователь создаёт только свои посты
CREATE POLICY "user_can_insert_own_posts"
ON posts FOR INSERT
WITH CHECK (auth.uid() = user_id);

RLS работает на уровне PostgreSQL — не обходится даже при прямом SQL-запросе. Это принципиально важно для mobile, где anon key находится в коде приложения и может быть извлечён reverse engineering'ом.

Загрузка файлов в Storage

import * as FileSystem from 'expo-file-system'; // или react-native-fs

const uploadFile = async (localUri: string, path: string) => {
  const base64 = await FileSystem.readAsStringAsync(localUri, {
    encoding: FileSystem.EncodingType.Base64,
  });

  const { data, error } = await supabase.storage
    .from('avatars') // bucket name
    .upload(path, decode(base64), {
      contentType: 'image/jpeg',
      upsert: true, // перезаписать если существует
    });

  if (error) throw error;

  const { data: { publicUrl } } = supabase.storage
    .from('avatars')
    .getPublicUrl(path);

  return publicUrl;
};

decode из пакета base64-arraybuffer. Supabase Storage принимает ArrayBuffer, не строку. На больших файлах — используйте FormData с fetch напрямую вместо base64 (base64 увеличивает размер на 33%).

Оценка

Supabase интеграция (Auth + PostgreSQL CRUD + Realtime + Storage) с RLS и TypeScript-типами: 3–5 недель. Self-hosted Supabase с кастомной конфигурацией PostgreSQL: +1–2 недели.