Функционал SDK
Предварительно вам необходимо настроить SDK для работы с вашим приложением. Подробная инструкция находится здесь.
Работа со статусами подписки
Изменение статуса подписки
AltcraftSDK (Flutter)
└─ Push subscription functions
// Подписка: status = subscribed
├─ static Future<void> pushSubscribe({
│ bool? sync,
│ Map<String, dynamic>? profileFields,
│ Map<String, dynamic>? customFields,
│ List<dynamic>? cats,
│ bool? replace,
│ bool? skipTriggers,
│ })
// Приостановка: status = suspended
├─ static Future<void> pushSuspend({
│ bool? sync,
│ Map<String, dynamic>? profileFields,
│ Map<String, dynamic>? customFields,
│ List<dynamic>? cats,
│ bool? replace,
│ bool? skipTriggers,
│ })
// Отписка: status = unsubscribed
└─ static Future<void> pushUnSubscribe({
bool? sync,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
bool? replace,
bool? skipTriggers,
})
pushSubscribe()— выполняет подписку на push-уведомления;pushSuspend()— приостанавливает подписку на push-уведомления (уведомления не приходят, но при этом не создаётся событие отписки в профиле пользователя);pushUnSubscribe()— отменяет подписку на push-уведомления;unSuspendPushSubscription()— используется для созданияLogIn-,LogOut-переходов.
Функции pushSubscribe(), pushSuspend() и pushUnSubscribe() имеют одинаковую сигнатуру.
sync: bool?
По умолчанию: true на нативной стороне, если из Dart передан null
Обязательный: Нет
Описание: Флаг, устанавливающий синхронность выполнения запроса.
Успешное выполнение запроса:
В случае успешного выполнения запроса данной группы функций будет создано событие SDK с кодом 230, 231 или 232, содержащее значение event.value, определяемое в зависимости от флага синхронизации:
Если sync == true
ResponseWithHttpCode
├─ http_code: 200
└─ response
├─ error: 0
├─ error_text: ""
└─ profile
├─ id: "000000000000000000000000"
├─ status: "subscribed"
├─ is_test: false
└─ subscription
├─ subscription_id: "provider-subscription-id"
├─ hash_id: "7f31a9c4"
├─ provider: "android-firebase"
├─ status: "subscribed"
├─ fields
│ ├─ _os: "Android"
│ ├─ _os_ver: "14"
│ ├─ _device_type: "mob"
│ ├─ _device_model: "Pixel 7"
│ └─ _app_ver: "1.0.0"
└─ cats
└─ [ { name: "developer_news", active: true } ]
При синхронном запросе в значении события event.value по ключу response_with_http_code доступны:
http_code— транспортный код ответа;response— данные ответа, содержащие:error— внутренний код ошибки сервера (0, если ошибок нет);error_text— текст ошибки (пустая строка, если ошибок нет);profile— данные профиля и подписки, если запрос успешный. Если запрос завершился с ошибкой, вернётся толькоprofile = null.
Если sync == false
ResponseWithHttpCode
├─ http_code: int?
└─ response: Map<String, dynamic>?
├─ error: int?
├─ error_text: String?
└─ profile: null // обычно null для асинхронного запроса
При асинхронном запросе в значении события event.value по ключу response_with_http_code доступны:
http_code— транспортный код ответа;response— данные ответа, содержащие:error— внутренний код ошибки сервера (0, если ошибок нет);error_text— текст ошибки (пустая строка, если ошибок нет);profile— для асинхронного запроса всегда равенnull.
Выполнение запроса с ошибкой:
Если запрос данной группы функций завершился ошибкой, будет создано событие со следующими кодами:
Операции без автоматического повтора попытки на стороне SDK:
- 430 — подписка на уведомления;
- 431 — приостановка подписки;
- 432 — отписка.
Операции с автоматическим повтором попытки на стороне SDK:
- 530 — подписка на уведомления;
- 531 — приостановка подписки;
- 532 — отписка.
Содержимое события:
- только
http_code, если сервер Altcraft был недоступен; errorиerror_text, если сервер вернул ошибку.
Получение значений событий
import 'package:altcraft_sdk/altcraft_sdk.dart';
final responseCodes = {230, 231, 232, 430, 431, 432, 530, 531, 532};
AltcraftSDK.subscribeToEvents().listen((SdkEvent event) {
if (event.code == null) return;
if (!responseCodes.contains(event.code)) return;
final raw = event.value?['response_with_http_code'];
if (raw == null) return;
final map = Map<String, dynamic>.from(raw as Map);
final httpCode = map['http_code'] ?? map['httpCode'];
final response = map['response'] as Map<dynamic, dynamic>?;
final error = response?['error'];
final errorText = response?['error_text'] ?? response?['errorText'];
final profile = response?['profile'] as Map<dynamic, dynamic>?;
final subscription = profile?['subscription'] as Map<dynamic, dynamic>?;
print('httpCode=$httpCode error=$error errorText=$errorText profileId=${profile?['id']}');
print('subscriptionId=${subscription?['subscription_id']}');
});
profileFields: Map<String, dynamic>?
По умолчанию: null
Обязательный: Нет
Описание: Объект, содержащий поля профиля.
Параметр может принимать как системные поля (например, _fname — имя или _lname — фамилия), так и опциональные (заранее создаются вручную в интерфейсе платформы). Допустимые структуры (JSON-совместимые):
- Скалярные значения:
String,bool,num(int / double),null - Объекты:
Map<String, dynamic> - Списки:
List<dynamic>
Если передано невалидное опциональное поле, запрос завершится с ошибкой:
SDK error: 430
http code: 400
error: 400
error_text: Platform profile processing error: with field "название_поля": Incorrect field
AltcraftSDK.pushSubscribe(
sync: true,
profileFields: const {
'_fname': 'Ivan',
'_lname': 'Petrov',
'_email': 'ivan.petrov@example.com',
},
);
customFields: Map<String, dynamic>?
По умолчанию: null
Обязательный: Нет
Описание: Объект, содержащий поля подписки.
Параметр может принимать как системные поля (например, _device_model — модель устройства или _os — операционная система), так и опциональные (заранее создаются вручную в интерфейсе платформы). Допустимые типы значений (JSON-совместимые, только скаляры):
Stringboolnum(int / double)null
Если передано невалидное опциональное поле, запрос завершится с ошибкой:
SDK error: 430
http code: 400
error: 400
error_text: Platform profile processing error: field "название_поля" is not valid: failed convert custom field
AltcraftSDK.pushSubscribe(
customFields: const {
'source': 'flutter_app',
'build': '100',
},
);
Большая часть системных полей подписки автоматически собирается SDK и добавляется к push-запросам. К таким системным полям относятся: "_os", "_os_tz", "_os_language", "_device_type", "_device_model", "_device_name", "_os_ver", "_ad_track", "_ad_id".
cats: List<dynamic>?
По умолчанию: null
Обязательный: Нет
Описание: Категории подписок.
Структура категории определяется классом CategoryData:
class CategoryData {
final String? name;
final String? title;
final bool? steady;
final bool? active;
}
При отправке push-запроса с указанием категорий используйте только поля name (название категории) и active (статус активности категории). Поля title и steady не используются в обработке запроса — они заполняются при получении информации о подписке.
AltcraftSDK.pushSubscribe(
cats: const [
{'name': 'developer_news', 'active': true},
{'name': 'product_updates', 'active': false},
],
);
Категории, используемые в запросе, должны быть предварительно созданы и добавлены к ресурсу в платформе Altcraft. Если в запросе будет использована категория, которая не добавлена в ресурс, запрос завершится с ошибкой:
SDK error: 430
http code: 400
error: 400
error_text: Platform profile processing error: field "subscriptions.cats" is not valid: category not found in resource
replace: bool?
По умолчанию: null
Обязательный: Нет
Описание: При активации флага все подписки других профилей с тем же push-токеном в текущей базе данных переводятся в статус unsubscribed после успешного запроса.
skipTriggers: bool?
По умолчанию: null
Обязательный: Нет
Описание: При активации флага профиль, содержащий данную подписку, будет игнорироваться в триггерах рассылок и сценариев.
Примеры реализации запроса
Пример выполнения запроса подписки на push-уве домления
Минимальная рабочая настройка:
AltcraftSDK.pushSubscribe();
Передача всех доступных параметров:
AltcraftSDK.pushSubscribe(
sync: true,
profileFields: const {'_fname': 'Ivan', '_lname': 'Petrov'},
customFields: const {'source': 'flutter_app'},
cats: const [{'name': 'developer_news', 'active': true}],
replace: false,
skipTriggers: false,
);
Для pushSubscribe, pushSuspend, pushUnSubscribe предусмотрен автоматический повтор запроса со стороны SDK, если http-код ответа находится в диапазоне 500..599. Запрос не повторяется, если код ответа в этот диапазон не входит.
Функция unSuspendPushSubscription()
Функция static Future<ResponseWithHttpCode?> unSuspendPushSubscription() предназначена для создания LogIn-, LogOut-переходов. Она работает следующим образом:
- проводит поиск подписок с тем же push-токеном, что и текущий, не относящихся к профилю, на который указывает текущий JWT-токен;
- меняет статус для найденных подписок с
subscribedнаsuspended; - меняет статус в подписках профиля, на который указывает текущий JWT, с
suspendedнаsubscribed(если профиль, на который указывает JWT, существует и в нём содержатся подписки); - возвращает
ResponseWithHttpCode?, гдеresponse?.profile— текущий профиль, на который указывает JWT (если профиля не существует, вернётсяnull).
Рекомендуемая реализация LogIn-, LogOut-переходов
LogIn-переход
- Анонимный пользователь входит в приложение. Данному пользователю присвоен
JWT_1, указывающий на базу данных #1Anonymous; - Выполнена подписка на push-уведомления, профиль создан в базе данных #1Anonymous;
- Пользователь регистрируется, ему присваивается
JWT_2, указывающий на базу данных #2Registered; - Вызывается функция
unSuspendPushSubscription()— подписка анонимного пользователя в базе данных #1Anonymous приостанавливается; - Выполняется поиск профиля в базе данных #2Registered для восстановления подписки;
- Так как подписки с таким push-токеном в базе данных #2Registered не существует, функция вернёт
null; - После получения значения
nullможно выполнить запросpushSubscribe(), который создаст новый профиль в базе #2Registered.
LogOut-переход
- Пользователь выполнил выход из профиля на стороне приложения (
LogOut); - Пользователю присваивается
JWT_1, указывающий на базу данных #1Anonymous; - Вызывается функция
unSuspendPushSubscription(), которая приостановит подписку в базе данных #2Registered и сменит статус подписки в базе #1Anonymous наsubscribed; - Запрос вернёт профиль #1Anonymous != null — подписка уже существует, новая не требуется.
Пример реализации:
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> unSuspend(bool logIn) async {
setAuth(logIn);
final ResponseWithHttpCode? result =
await AltcraftSDK.unSuspendPushSubscription();
if (result == null) {
AltcraftSDK.pushSubscribe();
return;
}
final int httpCode = result.httpCode;
final subscription = result.response?['profile']?['subscription'];
if (httpCode == 200 && subscription == null) {
AltcraftSDK.pushSubscribe();
}
}
void logIn() => unSuspend(true);
void logOut() => unSuspend(false);
Запрос статуса подписки
AltcraftSDK
├─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscription()
├─ static Future<ResponseWithHttpCode?> getStatusForCurrentSubscription()
└─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscriptionForProvider(
String? provider,
)
Функции запроса статуса подписки:
getStatusOfLatestSubscription()— статус последней подписки профиля;getStatusForCurrentSubscription()— статус подписки для текущего токена/провайдера;getStatusOfLatestSubscriptionForProvider()— статус последней подписки по провайдеру. Если указанnull, используется провайдер текущего токена.
getStatusOfLatestSubscription()
Функция получения статуса последней подписки профиля. Возвращает ResponseWithHttpCode?, содержащий response?.profile?.subscription — последнюю созданную подписку в профиле. Если такой подписки не существует, будет передан null.
final ResponseWithHttpCode? result =
await AltcraftSDK.takePush(const {'_uid': 'push-message-uid-0001'});
getStatusForCurrentSubscription()
Функция получения статуса подписки для текущего токена/провайдера. Возвращает ResponseWithHttpCode?, содержащий response?.profile?.subscription — подписку, найденную по текущему push-токену и провайдеру. Если такой подписки не существует, будет передан null.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusForCurrentSubscription();
getStatusOfLatestSubscriptionForProvider(provider)
Функция получения статуса последней подписки по провайдеру. Возвращает ResponseWithHttpCode?, содержащий response?.profile?.subscription — последнюю созданную подписку с указанным провайдером. Если провайдер не указан (provider = null), используется провайдер текущего токена. Если такой подписки не существует, будет передан null.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusOfLatestSubscriptionForProvider('android-firebase');
Ниже представлен пример извлечения данных о профиле, подписке и категориях из ответа функций получения статуса. Данный подход актуален для всех функций получения статуса:
Данные из функций получения статуса
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> readStatus() async {
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusForCurrentSubscription();
if (result == null) return;
final int httpCode = result.httpCode;
final response = result.response;
final int? error = response?['error'] ?? null;
final String? errorText = response?['error_text'] as String?;
final profile = response?['profile'] as Map<String, dynamic>?;
final subscription = profile?['subscription'] as Map<String, dynamic>?;
final cats = subscription?['cats'] ?? null;
print('httpCode=$httpCode error=$error errorText=$errorText cats=$cats');
}
Управление push-токенами провайдеров
AltcraftSDK
├─ static Future<TokenData?> getPushToken()
└─ static Future<void> setPushToken(String provider, String? token)
Функции для работы с токеном провайдера в SDK:
setPushToken()— установка push-токена устройства и провайдера;getPushToken()— получение текущего push-токена.
setPushToken(provider, token)
Функция предназначена для установки push-токена устройства и провайдера.
- В Flutter не передаётся
context— сохранение и хранение токена выполняется на нативной стороне SDK. token: null— означает очистку токена для указанного провайдера.
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> saveFcmToken(String token) async {
await AltcraftSDK.setPushToken('android-firebase', token);
}
Пример передачи токена пр и получении нового токена:
Future<void> onNewToken(String provider, String token) async {
await AltcraftSDK.setPushToken(provider, token);
}
getPushToken()
Функция возвращает текущие данные push-токена устройства и провайдера в виде TokenData.
Формат возвращаемых данных:
TokenData— объект с полями:provider: String— идентификатор провайдера (например,android-firebase,ios-apns);token: String— значение push-токена.
Если токен недоступен — будет возвращено null.
import 'package:altcraft_sdk/altcraft_sdk.dart';
Future<void> readPushToken() async {
final TokenData? data = await AltcraftSDK.getPushToken();
final String? provider = data?.provider;
final String? token = data?.token;
print('provider=$provider token=$token');
}
Регистрация и передача push-уведомлений в SDK
В нативном коде
Для настройки работы с push-уведомлениями в Flutter-проекте используйте инструкции нативных SDK.
Android:
- Подключение push-провайдеров
- Подготовка SDK к работе с push-провайдерами
- Передача push-уведомлений в SDK
iOS:
- Подключение push-провайдеров
- Настройка AppDelegate приложения
- Подготовка NSE
- Работа с push-уведомлениями
Flutter SDK предоставляет метод takePush() для передачи payload в SDK на Android. На iOS обработка APNS и rich push обычно выполняется в нативной части приложения и Notification Service Extension.
Во Flutter-коде на Android
Если входящие push-уведомления обрабатываются на Dart-стороне, передайте payload в SDK методом takePush().
AltcraftSDK.takePush(Map<String, String> message)
где message — данные push-уведомления, преобразованные в формат Map<String, String>.
FCM (Firebase Cloud Messaging)
Установите необходимые зависимости:
flutter pub add firebase_messaging
Обработка push-уведомлений через FCM:
Background push
import 'package:altcraft_sdk/altcraft_sdk.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
final Map<String, String> payload = message.data.map(
(String key, dynamic value) => MapEntry(key, value?.toString() ?? ''),
);
if (payload.isNotEmpty) {
AltcraftSDK.takePush(payload);
}
}
Foreground push
void registerFirebaseForegroundPush() {
FirebaseMessaging.onMessage.listen((RemoteMessage message) {
final Map<String, String> payload = message.data.map(
(String key, dynamic value) => MapEntry(key, value?.toString() ?? ''),
);
if (payload.isNotEmpty) {
AltcraftSDK.takePush(payload);
}
});
}
Регистрация background handler выполняется при старте приложения:
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
runApp(const AppRoot());
}
Данный подход можно объединить с использованием нативного push-сервиса FirebaseMessagingService: уведомления могут обрабатываться нативно и параллельно передаваться в Flutter/Altcraft SDK для бизнес-логики.