Функционал 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 для бизнес-логики.
Мобильные события
AltcraftSDK
└─ static Future<void> mobileEvent({
required String sid,
required String eventName,
String? sendMessageId,
Map<String, dynamic>? payload,
Map<String, dynamic>? matching,
String? matchingType,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? subscription,
Map<String, dynamic>? utm,
})
Для регистрации мобильного события используйте функцию mobileEvent() из AltcraftSDK.
sid: String
Обязательный: Да
Описание: Строковый идентификатор пикселя, к которому привязываются мобильные события.
eventName: String
Обязательный: Да
Описание: Имя мобильного события.
sendMessageId: String?
Обязательный: Нет
Описание: SMID-идентификатор отправленного сообщения, если событие связано с конкретной рассылкой.
payload: Map<String, dynamic>?
Обязательный: Нет
Описание: Данные события — карта со строковыми ключами. Передавайте JSON-совместимые значения: String, num, bool, Map, List и null. На Android значения передаются в нативный SDK как codec-safe Map, на iOS bridge приводит их к JSON-совместимому виду.
Несериализуемые объекты могут быть преобразованы в строку или отброшены нативной частью, поэтому для стабильного результата используйте только JSON-совместимые данные.
matching: Map<String, dynamic>?
Обязательный: Нет
Описание: Карта, в которую можно передавать значения с типами и идентификаторами матчинга, например {'email': 'ivan.petrov@example.com'}. Сериализация происходит по тем же правилам, что и payload.
matchingType: String?
Обязательный: Нет
Описание: Тип матчинга.
profileFields: Map<String, dynamic>?
Обязательный: Нет
Описание: Поля профиля. Сериализация происходит по тем же правилам, что и payload.
Параметр profileFields используется при сценариях, где профиль идентифицируется через JWT-авторизацию и matching.
subscription: Map<String, dynamic>?
Обязательный: Нет
Описание: Параметр добавления подписки для выбранного канала.
SDK предоставляет класс Subscription с factory-конструкторами для каждого типа подписки:
class Subscription {
final String type;
final int resourceId;
final String? status;
final int? priority;
final String? email;
final String? phone;
final String? provider;
final String? subscriptionId;
final Map<String, dynamic>? customFields;
final List<dynamic>? cats;
final Map<String, dynamic>? ccData;
final String? ccChannel;
}
Параметр subscription используется только при работе с JWT-авторизацией.
Общие поля подписки (для всех реализаций)
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
type / channel | String | Да | Тип канала (дискриминатор). toMap() добавляет оба ключа. |
resourceId / resource_id | int | Да | Идентификатор ресурса/источника подписки. |
status | String? | Нет | Статус подписки. |
priority | int? | Нет | Приоритет доставки. |
customFields / custom_fields | Map<String, dynamic>? | Нет | Пользовательские поля подписки. |
cats | List<dynamic>? | Нет | Категории подписки. Для mobileEvent рекомендуется список строк. |
Варианты подписки
Email-подписка (type = "email")
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
resourceId | int | Да | ID ресурса Altcraft |
email | String | Да | Адрес электронной почты |
final emailSub = Subscription.email(
resourceId: 10,
email: 'user@example.com',
status: 'subscribed',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
SMS-подписка (type = "sms")
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
resourceId | int | Да | ID ресурса Altcraft |
phone | String | Да | Номер телефона в международном формате |
final smsSub = Subscription.sms(
resourceId: 10,
phone: '+79001234567',
status: 'subscribed',
);
Push-подписка (type = "push")
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
resourceId | int | Да | ID ресурса Altcraft |
provider | String | Да | Провайдер (например, "android-firebase") |
subscriptionId | String | Да | Уникальный идентификатор подписки у провайдера |
final pushSub = Subscription.push(
resourceId: 10,
provider: 'android-firebase',
subscriptionId: 'provider-sub-id',
status: 'subscribed',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
CcData-подписка (type = "cc_data")
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
resourceId | int | Да | ID ресурса Altcraft |
channel | String | Да | Название custom-channel, например telegram_bot |
ccData | Map<String, dynamic> | Да | Канал-специфичные данные (chat ID, номер, токены) |
final ccSub = Subscription.ccData(
resourceId: 10,
channel: 'telegram_bot',
ccData: {'chat_id': '123456'},
);
utm: Map<String, dynamic>?
Обязательный: Нет
Описание: UTM-метки. SDK предоставляет класс UTM:
class UTM {
final String? source;
final String? medium;
final String? campaign;
final String? content;
final String? keyword;
final String? temp;
}
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'app_install',
utm: const {
'campaign': 'summer_campaign',
'content': 'main_banner',
'keyword': 'mobile_sdk',
'medium': 'push',
'source': 'flutter_app',
'temp': 'a1',
},
);
Примеры использования
Простое событие
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'app_open',
);
Передача данных через payload
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'purchase',
payload: const {
'orderId': 'A-1001',
'amount': 3990,
'currency': 'RUB',
'items': [
{'sku': 'sku-1', 'qty': 2},
],
},
);
Пер едача matching / matchingType
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'profile_update',
payload: const {'source': 'settings'},
matching: const {'email': 'ivan.petrov@example.com'},
matchingType: 'email',
);
Передача subscription (JWT)
import 'package:altcraft_sdk/altcraft_sdk.dart';
final pushSub = Subscription.push(
resourceId: 10,
provider: 'android-firebase',
subscriptionId: 'provider-sub-id',
status: 'subscribed',
priority: 1,
customFields: {'source': 'flutter_app'},
cats: ['promo', 'news'],
);
AltcraftSDK.mobileEvent(
sid: 'pixel-000000000000000000000000',
eventName: 'jwt_bind_subscription',
subscription: pushSub.toMap(),
);
Передавайте subscription через Subscription.toMap(). Если обязательные поля выбранного канала отсутствуют, native bridge не сможет собрать модель подписки и отправит мобильное событие без неё.
Получение событий SDK в приложении
Во Flutter события SDK доставляются в Dart через Stream<SdkEvent> (под капотом используется EventChannel).
class SdkEvent {
final String function;
final int? code;
final String message;
final String type;
final Map<String, dynamic>? value;
final String? timestamp;
}
Типы событий:
event— информационные события и успешные операции;error— ошибки выполнения;retryError— ошибки операций, для которых SDK выполняет автоматический повтор.
Поле timestamp содержит временную метку события в формате yyyy-MM-dd HH:mm:ss.SSS (поставляется нативным SDK).
Подписка на события
Метод subscribeToEvents() возвращает общий broadcast Stream<SdkEvent>, который кэшируется на Dart-стороне. Для отписки конкретного слушателя сохраните StreamSubscription и вызовите cancel().
import 'dart:async';
import 'package:altcraft_sdk/altcraft_sdk.dart';
StreamSubscription<SdkEvent>? sdkEventsSubscription;
void subscribeToSdkEvents() {
sdkEventsSubscription = AltcraftSDK.subscribeToEvents().listen(
(SdkEvent event) {
switch (event.type) {
case 'event':
print('SDK event: ${event.message}');
break;
case 'error':
print('SDK error: ${event.message}');
break;
case 'retryError':
print('SDK retry error: ${event.message}');
break;
default:
print('SDK unknown event type: ${event.type}');
}
},
);
}
Отписка от событий
Future<void> unsubscribeFromSdkEvents() async {
await sdkEventsSubscription?.cancel();
sdkEventsSubscription = null;
await AltcraftSDK.unsubscribeFromEvents();
}
После вызова unsubscribeFromEvents() доставка событий из нативного SDK останавливается. Для повторного получения событий вызовите subscribeToEvents() снова.
Обработка ошибок SDK
SDK может выбрасывать AltcraftException при ошибках вызова методов через MethodChannel:
class AltcraftException implements Exception {
final String code;
final String message;
final Object? details;
}
Стандартная MethodChannel-реализация конвертирует ошибки нативной стороны в AltcraftException. Проверяйте e.code; например, Android-only методы на iOS возвращают код UNAVAILABLE_ON_IOS. Класс SdkNotInitializedException экспортируется пакетом, но в стандартном bridge такие ошибки обычно приходят как обычный AltcraftException:
import 'package:altcraft_sdk/altcraft_sdk.dart';
try {
await AltcraftSDK.takePush(const {'_uid': 'push-message-uid-0001'});
} on AltcraftException catch (e) {
if (e.code == 'UNAVAILABLE_ON_IOS') {
print('Method is Android-only');
return;
}
print('SDK error (${e.code}): ${e.message}');
}
Список всех событий SDK
Список событий
| Код | Описание |
|---|---|
| 200 | SDK configuration is installed |
| 201 | push provider set |
| 202 | received a notification unrelated to the Altcraft Platform |
| 203 | received Altcraft push notification |
| 204 | push is posted |
| 205 | SDK data has been cleared |
| 206 | waiting for SDK initialization to complete |
| 207 | waiting for push token update to complete |
| 220 | receiver override event |
| 230 | subscribe request succeeded |
| 231 | push suspend request succeeded |
| 232 | push unsubscribed request succeeded |
| 233 | push update request succeeded |
| 234 | push unsuspend request succeeded |
| 235 | profile status request succeeded |
| 236 | push event delivered successfully |
| 237 | mobile event delivered successfully |
| 401 | the configuration is not set |
| 402 | userTag is null. It is impossible to identify the user |
| 404 | SDK initialization timeout has expired |
| 405 | mobile event parts is null |
| 422 | unsuspend request data is null |
| 423 | profile request data is null |
| 430 | subscribe request failed |
| 431 | suspend request failed |
| 432 | unsubscribed request failed |
| 433 | update request failed |
| 434 | unsuspend request failed |
| 435 | status request failed |
| 436 | push event delivery failed |
| 437 | mobile event request failed |
| 450 | push data is null |
| 451 | uid in the push data is null or empty, it is impossible to send a push event to the server |
| 452 | error uploading the notification image |
| 453 | couldn't create notification |
| 454 | foreground info is null |
| 455 | the notification channel has not been created |
| 471 | invalid provider. Available - android-firebase, android-huawei, android-rustore |
| 472 | invalid customFields: not all values are primitives |
| 480 | subscribe retry limit reached (request removed from DB) |
| 484 | push event retry limit reached (request removed from DB) |
| 485 | mobile event retry limit reached (request removed from DB) |
| 501 | config data is null |
| 502 | current push token is null |
| 503 | userTag is null. It is impossible to identify the user |
| 504 | no permission to send notifications |
| 505 | no internet connection, retry when connection is restored |
| 506 | failed to update the push token. The subscription request was rejected |
| 520 | push subscribe request data is null |
| 521 | token update request data is null |
| 524 | push event request data is null |
| 525 | mobile event request data is null |
| 529 | common data is null |
| 530 | subscribe request failed (retryable) |
| 531 | suspend request failed (retryable) |
| 532 | unsubscribed request failed (retryable) |
| 533 | update request failed (retryable) |
| 534 | push event delivery failed (retryable) |
| 535 | mobile event delivery failed (retryable) |
| 540 | JWT token is null |
| 541 | matching mode is null |
| 542 | JWT payload exceeds allowed size (16 KB limit): input rejected to prevent DoS |
| 543 | JWT does not contain a payload |
| 544 | auth data is null |
| 545 | matching claim does not contain a matching ID |
| 560 | response data is null |
ActionFieldBuilder
SDK предоставляет ActionFieldBuilder для структурированного управления полями профиля. Builder производит к арту, совместимую с нативным SDK, которую следует объединить с profileFields перед передачей в pushSubscribe, updateProfileFields или подобные API.
class ActionFieldBuilder {
final String key;
Map<String, dynamic> set(dynamic value);
Map<String, dynamic> unset(dynamic value);
Map<String, dynamic> incr(dynamic value);
Map<String, dynamic> add(dynamic value);
Map<String, dynamic> delete(dynamic value);
Map<String, dynamic> upsert(dynamic value);
}
ActionFieldBuilder actionField(String key);
Доступные действия:
| Метод | Описание |
|---|---|
set(value) | Установить поле в заданное значение. |
unset(value) | Удалить значение поля. |
incr(value) | Увеличить числовое поле на заданное значение. |
add(value) | Добавить значение в поле-множество/массив. |
delete(value) | Удалить значение из поля-множества/массива. |
upsert(value) | Установить, если поле отсутствует; обновить, если существует. |
Пример использования:
import 'package:altcraft_sdk/altcraft_sdk.dart';
final profileFields = <String, dynamic>{
...actionField('_fname').set('Ivan'),
...actionField('_lname').set('Petrov'),
...actionField('login_count').incr(1),
...actionField('visited_pages').add('/settings'),
...actionField('old_field').unset(null),
};
AltcraftSDK.updateProfileFields(
profileFields: profileFields,
skipTriggers: false,
);
Дополнительные функции SDK
Очистка данных SDK
await AltcraftSDK.clear();
Функция позволяет выполнить очистку данных SDK и отменить работу всех фоновых задач, которые ожидают выполнения.
Ручная регистрация push-событий
Эти функции применяются только в том случае, если вы реализуете собственную логику обработки уведомлений и не передаёте их в SDK автоматически.
Android
Во Flutter доступны функции ручной регистрации push-событий на Android:
deliveryEvent(message, messageUID)— регистрация доставки уведомления;openEvent(message, messageUID)— регистрация открытия уведомления.
Параметры:
message: Map<String, String>?— data payload уведомления в виде словаря строк.messageUID: String?— идентификатор сообщения.
AltcraftSDK.deliveryEvent(
const {
'_uid': 'push-message-uid-0001',
'_provider': 'android-firebase',
},
'push-message-uid-0001',
);
AltcraftSDK.openEvent(
const {
'_uid': 'push-message-uid-0001',
'_provider': 'android-firebase',
},
'push-message-uid-0001',
);
Правила передачи:
- можно передать только
message(SDK возьмёт идентификатор сообщения из payload, если он в нём присутствует); - можно передать только
messageUID(если payload недоступен, но идентификатор известен); - если оба параметра
null— событие не будет зарегистрировано корректно (нет данных для идентификации сообщения).
iOS
Ручная р егистрация push-событий SDK на стороне Flutter не реализуется. Вызовы deliveryEvent() и openEvent() на iOS завершатся AltcraftException с кодом UNAVAILABLE_ON_IOS. Если требуется ручная регистрация событий, выполните её в нативной части приложения.
См. инструкцию для iOS.
Обновление полей профиля
AltcraftSDK.updateProfileFields({
Map<String, dynamic>? profileFields,
bool? skipTriggers,
});
Функция обновляет поля профиля на сервере.
profileFields— карта полей профиля для обновлен ия.skipTriggers— при активации флага профиль будет игнорироваться в триггерах рассылок и сценариев.
AltcraftSDK.updateProfileFields(
profileFields: const {
'_fname': 'Ivan',
'_lname': 'Petrov',
},
skipTriggers: false,
);
Принудительное обновление токена
await AltcraftSDK.forcedTokenUpdate();
Функция запускает принудительное обновление push-токена.
Удаление токена устройства
await AltcraftSDK.deleteDeviceToken('android-firebase');
Функция удаляет токен устройства для указанного провайдера.
Изменение приоритета push-провайдеров
await AltcraftSDK.changePushProviderPriorityList(
const ['android-firebase', 'android-huawei', 'android-rustore'],
);
Функция изменяет список приоритетов push-провайдеров.
Проверка Altcraft push
final bool isAltcraft = await AltcraftSDK.isAltcraftPush(
const {
'_ac_push': 'Altcraft',
'_uid': 'push-message-uid-0001',
},
);
Функция проверяет, относится ли push-сообщение к Altcraft. Возвращает true, если сообщение принадлежит Altcraft, и false в противном случае. На iOS метод всегда возвращает false.
Разблокировка начальных операций в сессии
AltcraftSDK.unlockInitialOperationsInThisSession();
Функция разблокирует начальные операции в текущей сессии. Метод используется на Android. На iOS вызов является no-op и завершается успешно.
App Group и UserDefaults
AltcraftSDK.setAppGroup(String? groupName);
AltcraftSDK.setUserDefaultsValue(String? suiteName, String key, String? value);
setAppGroup()— используется на iOS для установки App Group, которая определяет пространствоUserDefaults, разделяемое между основным приложением и Notification Service Extension. На Android метод является no-op. На iOSgroupNameне должен бытьnull.setUserDefaultsValue()— сохраняет строковое значение в нативном хранилище:UserDefaultsна iOS иSharedPreferencesна Android. Еслиvalue == null, ключ удаляется. На AndroidsuiteNameигнорируется.
import 'dart:io';
import 'package:altcraft_sdk/altcraft_sdk.dart';
void configureIosAppGroup() {
if (!Platform.isIOS) return;
const String appGroup = 'group.altcraft.flutter.example';
AltcraftSDK.setAppGroup(appGroup);
AltcraftSDK.setUserDefaultsValue(
appGroup,
'altcraft_jwt',
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
);
}