Идентификация пользователя во Flutter
SDK поддерживает анонимный профиль, склейку по CUID и ручную идентификацию. Не смешивайте эти идентификаторы:
Общая модель: Идентификация и омниканальность.
Анонимный профиль
Не вызывайте setUser(), если хотите стандартное управление идентификацией. При первом успешном запросе сервер возвращает идентификаторы, а SDK сохраняет и использует их в последующих запросах. Не создавайте новую сессию вручную на каждый экран.
Авторизация и CUID
После успешной авторизации отправьте LoginEvent. При регистрации можно использовать SignUpEvent. Рекомендуемый CUID — SHA-256 нормализованного телефона с cuidType: 'phone_hash'.
Номер нормализуют в международный формат без + и разделителей. Для РФ/КЗ — 7XXXXXXXXXX. Хеш вычисляют по UTF-8 строке и передают как lowercase hex. Если CDP/DWH уже хранит такой идентификатор, используйте тот же хеш; не пересчитывайте его по другому правилу.
Добавьте crypto: ^3.0.6 в зависимости. Пример для номеров РФ/КЗ:
import 'dart:convert';
import 'package:crypto/crypto.dart';
import 'package:gravity_sdk/gravity_sdk.dart';
String phoneHashRuKz(String rawPhone) {
var digits = rawPhone.replaceAll(RegExp(r'[^0-9]'), '');
if (digits.length == 11 && digits.startsWith('8')) {
digits = '7' + digits.substring(1);
}
if (digits.length != 11 || !digits.startsWith('7')) {
throw ArgumentError('Нужен полный номер РФ/КЗ в международном формате');
}
return sha256.convert(utf8.encode(digits)).toString();
}
Future<void> identifyAfterLogin(String phone) async {
await GravitySDK.instance.triggerEventNoShow(
events: [
LoginEvent(cuid: phoneHashRuKz(phone), cuidType: 'phone_hash'),
],
pageContext: const PageContext(
type: ContextType.other,
data: [],
location: 'app://login',
),
);
}
Для других стран нормализацию выполняйте по правилам их телефонных номеров. Склейка происходит на сервере после доставки события; при офлайн-отправке не считайте её завершённой сразу. Успешный возврат triggerEventNoShow() не является подтверждением авторизации или доставки.
SDK допускает nullable-поля у Login/SignUp, но серверу нужен идентификатор: cuid вместе с cuidType либо hashedEmail. Не отправляйте пустое событие.
Ручной пользователь
GravitySDK.instance.setUser('customer-42', 'app-session-2026-10-01');
Приложение само управляет внешним ID и сроком жизни этой сессии. Не меняйте session ID на каждый запрос и не используйте константу для всех клиентов. setUser() не выполняет запрос к серверу и не отправляет LoginEvent.
В 0.24.0 этот пользователь применяется и к просмотрам/событиям, и ко всем запросам контента, inline-блокам и автопоказу in-app. Сам внешний ID не заменяет CUID для омниканальной склейки. getUserId() не возвращает значение из setUser().
Выход и смена аккаунта
await GravitySDK.instance.resetUser();
Метод убирает ручного пользователя и сбрасывает серверный UID/сессию. Следующий запрос начинает новую анонимную сессию. Дождитесь завершения сброса перед запросами нового аккаунта.
resetUser() не очищает офлайн-очередь: события прежнего пользователя должны доставляться с его исходной идентификацией. Если ваша политика для общего устройства требует удалить ожидающие события:
await GravitySDK.instance.clearQueue();
await GravitySDK.instance.resetUser();
На время смены аккаунта приложение должно остановить отправку новых событий и пересоздать персонализированные виджеты/состояния. Уже загруженный UI не обновляется автоматически только от вызова setUser() или resetUser(). clearQueue() удаляет данные без возможности восстановления и не отменяет запрос уже в сети.
Получение серверного UID
final String? uid = await GravitySDK.instance.getUserId();
GravitySDK.instance.setUserIdListener((String? uid) {
// В этом примере только наблюдаем изменение.
print('Server UID: ' + (uid ?? 'не задан'));
});
// Когда подписка больше не нужна:
GravitySDK.instance.setUserIdListener(null);
До первого успешного запроса getUserId() может вернуть null. Если инициализация сессии уже выполняется, метод дожидается её; ошибку ожидания обрабатывайте в вызывающем коде.
Listener сообщает о появлении/изменении известного процессу UID, включая сброс на null и восстановление. Повторный серверный ответ с тем же UID его не вызывает. Подписка одна; новый listener заменяет старый. Чтобы получить текущее сохранённое значение, отдельно вызовите getUserId() — подписка не заменяет чтение.
Восстановление после переустановки
Если приложение сохранило серверный UID вне удаляемого локального хранилища, его можно передать перед первым запросом:
Future<void> restoreProfile(String savedServerUid) async {
await GravitySDK.instance.restoreUserId(savedServerUid);
}
restoreUserId() принимает серверный UID, полученный через getUserId(). Он сбрасывает текущую сессию и пользователя из setUser(); следующий запрос передаёт восстановленный UID серверу. Неизвестный серверу UID не восстанавливает профиль — сервер присваивает новый.
Пустая строка вызывает ArgumentError. Методы чтения UID, подписки и восстановления доступны до initialize(). Восстановление само по себе не проверяет UID на сервере. Хранение внешней копии UID и её удаление при выходе организует приложение.