SDK Public API
class AltcraftSDK
The entry point to the SDK. All methods are static. The JWT provider and push token providers are registered natively: Application.onCreate on Android and AppDelegate on iOS. The Dart API passes configuration, subscription commands, mobile events, push tokens, SDK events, and auxiliary operations.
AltcraftSDK
// ---- Initialization and State ----
├─ static Future<void> initialize(AltcraftConfig config)
├─ static Future<void> clear()
├─ static Future<bool> requestNotificationPermission()
└─ static Future<void> unlockInitialOperationsInThisSession()
// ---- Push Subscription ----
├─ static Future<void> pushSubscribe({bool? sync, ...})
├─ static Future<void> pushSuspend({bool? sync, ...})
├─ static Future<void> pushUnSubscribe({bool? sync, ...})
└─ static Future<ResponseWithHttpCode?> unSuspendPushSubscription()
// ---- Subscription Status ----
├─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscription()
├─ static Future<ResponseWithHttpCode?> getStatusForCurrentSubscription()
└─ static Future<ResponseWithHttpCode?> getStatusOfLatestSubscriptionForProvider(String? provider)
// ---- SDK Events ----
├─ static Stream<SdkEvent> subscribeToEvents()
└─ static Future<void> unsubscribeFromEvents()
// ---- Mobile Events and Profile ----
├─ static Future<void> mobileEvent({required String sid, required String eventName, ...})
└─ static Future<void> updateProfileFields({Map<String, dynamic>? profileFields, bool? skipTriggers})
// ---- Push Tokens ----
├─ static Future<TokenData?> getPushToken()
├─ static Future<void> setPushToken(String provider, String? token)
├─ static Future<void> forcedTokenUpdate()
├─ static Future<void> deleteDeviceToken(String provider)
└─ static Future<void> changePushProviderPriorityList(List<String> priorityList)
// ---- Push Notifications ----
├─ static Future<void> takePush(Map<String, String> message)
├─ static Future<bool> isAltcraftPush(Map<String, String> message)
├─ static Future<void> deliveryEvent(Map<String, String>? message, String? messageUID)
└─ static Future<void> openEvent(Map<String, String>? message, String? messageUID)
// ---- Native storage ----
├─ static Future<void> setAppGroup(String? groupName)
└─ static Future<void> setUserDefaultsValue(String? suiteName, String key, String? value)
Most methods return Future<void> and do not return the server response directly. Platform call errors come as AltcraftException. Server results for subscription operations, profile updates, mobile events, and retry errors must be read via subscribeToEvents().
Initialization
initialize(config)
static Future<void> initialize(AltcraftConfig config)
Initializes the Altcraft SDK with the given configuration. Called once at application startup, before main SDK operations.
| Parameter | Type | Description |
|---|---|---|
config | AltcraftConfig | SDK configuration object. The apiUrl field is required. |
Returns: Future<void> — completes when the native SDK has finished initialization.
Throws: AltcraftException on configuration or initialization error. Main codes: ALTCRAFT_INIT_INVALID_CONFIG, ALTCRAFT_INIT_ERROR, INITIALIZATION_FAILED, SDK_ERROR.
import 'package:altcraft_sdk/altcraft_sdk.dart';
import 'package:flutter/widgets.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await AltcraftSDK.initialize(
const AltcraftConfig(
apiUrl: 'https://pxl-demo.altcraft.com',
appInfo: AppInfo(
appID: '1:100000000000:android:1000000000000000',
appIID: '10000000-0000-4000-8000-000000000001',
appVer: '1.0.0',
),
providerPriorityList: ['android-firebase'],
enableLogging: true,
),
);
runApp(const MyApp());
}
clear()
static Future<void> clear()
Clears SDK data on the native side: local SDK storage, saved tokens, and deferred operations.
Returns: Future<void>.
Throws: AltcraftException on error.
requestNotificationPermission()
static Future<bool> requestNotificationPermission()
Requests the POST_NOTIFICATIONS permission on Android 13+. On Android below 13, returns true since runtime permission is not required. On iOS, this Dart method does not request permission and returns false; iOS permissions are configured natively via UNUserNotificationCenter.
Returns: Future<bool> — true if permission is granted or not required, false on denial, missing Activity, or on iOS.
final bool granted = await AltcraftSDK.requestNotificationPermission();
if (granted) {
await AltcraftSDK.pushSubscribe(sync: true);
}
unlockInitialOperationsInThisSession()
static Future<void> unlockInitialOperationsInThisSession()
Unlocks initial operations in the current Android application session. On iOS, the method is a no-op and completes successfully.
Push Subscription
pushSubscribe() / pushSuspend() / pushUnSubscribe()
static Future<void> pushSubscribe({
bool? sync,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
bool? replace,
bool? skipTriggers,
})
static Future<void> pushSuspend({
bool? sync,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
bool? replace,
bool? skipTriggers,
})
static Future<void> pushUnSubscribe({
bool? sync,
Map<String, dynamic>? profileFields,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
bool? replace,
bool? skipTriggers,
})
| Method | Status | Success | Error | Retry Error |
|---|---|---|---|---|
pushSubscribe() | subscribed | 230 | 430 | 530 |
pushSuspend() | suspended | 231 | 431 | 531 |
pushUnSubscribe() | unsubscribed | 232 | 432 | 532 |
All three methods have the same signature.
| Parameter | Type | Description |
|---|---|---|
sync | bool? | true — synchronous request on the SDK side; false — asynchronous. If null is passed, the native SDK uses true. |
profileFields | Map<String, dynamic>? | Profile fields. Values should be JSON-compatible. |
customFields | Map<String, dynamic>? | Custom subscription fields. Scalar JSON values are recommended. |
cats | List<dynamic>? | Subscription categories. Pass a list of Map, e.g., CategoryData(...).toMap(). |
replace | bool? | When true, the SDK may replace existing subscriptions with the same push token according to the native SDK's logic. |
skipTriggers | bool? | When true, the profile is ignored in mailing and scenario triggers. |
Returns: Future<void> — means the command was accepted by the bridge/native SDK. Server result comes through subscribeToEvents().
await AltcraftSDK.pushSubscribe(
sync: true,
profileFields: const {
'_fname': 'Ivan',
'_lname': 'Petrov',
},
customFields: const {
'source': 'flutter_app',
},
cats: const [
{'name': 'developer_news', 'active': true},
],
);
How to read an error from an event: if event.type == 'error' or event.type == 'retryError', check event.code, event.message, and event.value. For the server response, the key response_with_http_code is typically used; nested fields come in snake_case.
AltcraftSDK.subscribeToEvents().listen((SdkEvent event) {
final raw = event.value?['response_with_http_code'];
if (raw is! Map) return;
final responseWithHttp = Map<String, dynamic>.from(raw);
final int? httpCode = responseWithHttp['http_code'] as int?;
final response = responseWithHttp['response'] as Map<dynamic, dynamic>?;
final int? error = response?['error'] as int?;
final String? errorText = response?['error_text'] as String?;
if (event.type == 'error' || event.type == 'retryError') {
print('SDK error code=${event.code} http=$httpCode error=$error text=$errorText');
}
});
unSuspendPushSubscription()
static Future<ResponseWithHttpCode?> unSuspendPushSubscription()
Resumes a suspended push subscription. Used for LogIn/LogOut transitions between profiles.
Returns: Future<ResponseWithHttpCode?>. Returns null if the native SDK did not return a response.
Throws: AltcraftException on platform call error.
final ResponseWithHttpCode? result =
await AltcraftSDK.unSuspendPushSubscription();
if (result == null) {
await AltcraftSDK.pushSubscribe(sync: true);
return;
}
final response = result.response;
final profile = response?['profile'] as Map<String, dynamic>?;
final subscription = profile?['subscription'] as Map<String, dynamic>?;
if (result.httpCode == 200 && subscription == null) {
await AltcraftSDK.pushSubscribe(sync: true);
}
Subscription Status
getStatusOfLatestSubscription()
static Future<ResponseWithHttpCode?> getStatusOfLatestSubscription()
Returns the status of the latest profile subscription.
getStatusForCurrentSubscription()
static Future<ResponseWithHttpCode?> getStatusForCurrentSubscription()
Returns the subscription status for the current push token and current provider.
getStatusOfLatestSubscriptionForProvider(provider)
static Future<ResponseWithHttpCode?> getStatusOfLatestSubscriptionForProvider(
String? provider,
)
Returns the status of the latest subscription for the specified provider. If provider == null, the current token's provider is used.
| Parameter | Type | Description |
|---|---|---|
provider | String? | Provider identifier, e.g., android-firebase or ios-apns. |
All three methods return Future<ResponseWithHttpCode?>. If result == null, there is no response. If result.response?['error'] != 0, the server returned an error — handle error and error_text.
final ResponseWithHttpCode? result =
await AltcraftSDK.getStatusForCurrentSubscription();
if (result == null) return;
final response = result.response;
final int? error = response?['error'] as int?;
final String? errorText = response?['error_text'] as String?;
if (error != null && error != 0) {
print('Status error: $errorText');
return;
}
final profile = response?['profile'] as Map<String, dynamic>?;
final subscription = profile?['subscription'] as Map<String, dynamic>?;
print('status=${subscription?['status']} provider=${subscription?['provider']}');
SDK Events
subscribeToEvents()
static Stream<SdkEvent> subscribeToEvents()
Returns a shared broadcast Stream<SdkEvent> from EventChannel (com.altcraft/events). The stream is cached on the Dart side, so multiple subscribers listen to one event source.
Returns: Stream<SdkEvent>.
unsubscribeFromEvents()
static Future<void> unsubscribeFromEvents()
Stops event delivery from the native SDK and clears the current native event sink. To receive events again, subscribe to subscribeToEvents() again.
Returns: Future<void>.
Throws: AltcraftException on platform call error.
import 'dart:async';
import 'package:altcraft_sdk/altcraft_sdk.dart';
StreamSubscription<SdkEvent>? sdkEventsSubscription;
void startListening() {
sdkEventsSubscription = AltcraftSDK.subscribeToEvents().listen(
(SdkEvent event) {
print('[${event.type}] ${event.function}: ${event.message}');
},
);
}
Future<void> stopListening() async {
await sdkEventsSubscription?.cancel();
sdkEventsSubscription = null;
await AltcraftSDK.unsubscribeFromEvents();
}
Mobile Events and Profile
mobileEvent()
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,
})
Registers an Altcraft mobile event.
| Parameter | Type | Description |
|---|---|---|
sid | String | Pixel identifier. Must not be empty. |
eventName | String | Event name. Must not be empty. |
sendMessageId | String? | SMID of the sent message. |
payload | Map<String, dynamic>? | Event data. Use JSON-compatible values. |
matching | Map<String, dynamic>? | Matching data, e.g., {'email': 'ivan.petrov@example.com'}. |
matchingType | String? | Matching type. |
profileFields | Map<String, dynamic>? | Profile fields. |
subscription | Map<String, dynamic>? | Subscription for a channel. Pass Subscription.toMap(). |
utm | Map<String, dynamic>? | UTM tags. Pass UTM(...).toMap() or a regular Map. |
Returns: Future<void> — command accepted by SDK. Send result is tracked via SDK events (237, 437, 535).
Throws: AltcraftException with code ERR if sid or eventName are empty/missing.
await AltcraftSDK.mobileEvent(
sid: 'pixel-100000000000000000000000',
eventName: 'purchase',
payload: const {
'order_id': 'A-1001',
'amount': 3990,
'currency': 'RUB',
},
);
updateProfileFields()
static Future<void> updateProfileFields({
Map<String, dynamic>? profileFields,
bool? skipTriggers,
})
Updates profile fields on the server.
| Parameter | Type | Description |
|---|---|---|
profileFields | Map<String, dynamic>? | Map of profile fields to update. |
skipTriggers | bool? | When true, the profile is ignored in mailing and scenario triggers. |
Returns: Future<void> — command accepted by SDK. Server result comes through SDK events (233, 433, 533).
Push Tokens
getPushToken()
static Future<TokenData?> getPushToken()
Returns the current device push token and provider data.
Returns: Future<TokenData?> — TokenData object or null if the token is unavailable.
Throws: AltcraftException on platform call error.
setPushToken(provider, token)
static Future<void> setPushToken(String provider, String? token)
Sets or clears the push token for the specified provider. If token == null, the token is cleared.
| Parameter | Type | Description |
|---|---|---|
provider | String | Provider identifier, e.g., android-firebase, android-huawei, android-rustore, ios-apns, ios-firebase, ios-huawei. |
token | String? | Token value. null — clears the token. |
forcedTokenUpdate()
static Future<void> forcedTokenUpdate()
Initiates a forced push token update via the native SDK.
deleteDeviceToken(provider)
static Future<void> deleteDeviceToken(String provider)
Deletes the device token for the specified provider.
| Parameter | Type | Description |
|---|---|---|
provider | String | Provider identifier. |
changePushProviderPriorityList(priorityList)
static Future<void> changePushProviderPriorityList(List<String> priorityList)
Changes the push provider priority list. Index 0 is the highest priority provider.
| Parameter | Type | Description |
|---|---|---|
priorityList | List<String> | New priority list. |
await AltcraftSDK.changePushProviderPriorityList(
['android-firebase', 'android-huawei', 'android-rustore'],
);
All methods in this group throw AltcraftException on platform call error.
Push Notifications
takePush(message)
static Future<void> takePush(Map<String, String> message)
Passes incoming push payload to the SDK. The method is available on Android. On iOS, the call will throw an AltcraftException with code UNAVAILABLE_ON_IOS.
| Parameter | Type | Description |
|---|---|---|
message | Map<String, String> | Push notification data payload. |
isAltcraftPush(message)
static Future<bool> isAltcraftPush(Map<String, String> message)
Checks whether a push message belongs to Altcraft.
| Parameter | Type | Description |
|---|---|---|
message | Map<String, String> | Push notification data payload. |
Returns: Future<bool> — true if the message belongs to Altcraft. On iOS, always returns false.
deliveryEvent(message, messageUID)
static Future<void> deliveryEvent(Map<String, String>? message, String? messageUID)
Manual push notification delivery registration. The method is available on Android. On iOS, the call will throw an AltcraftException with code UNAVAILABLE_ON_IOS.
| Parameter | Type | Description |
|---|---|---|
message | Map<String, String>? | Notification data payload. |
messageUID | String? | Message identifier. |
You can pass only message or only messageUID. If both values are null, the SDK cannot correctly identify the push message.
openEvent(message, messageUID)
static Future<void> openEvent(Map<String, String>? message, String? messageUID)
Manual push notification opening registration. The method is available on Android. On iOS, the call will throw an AltcraftException with code UNAVAILABLE_ON_IOS.
Native storage
setAppGroup(groupName)
static Future<void> setAppGroup(String? groupName)
Sets the App Group for the iOS SDK. On Android, the method is a no-op. Despite the nullable Dart signature, on iOS the groupName value must be a non-empty string; null will return an AltcraftException with code ERR.
| Parameter | Type | Description |
|---|---|---|
groupName | String? | App Group identifier, e.g., group.altcraft.flutter.example. |
setUserDefaultsValue(suiteName, key, value)
static Future<void> setUserDefaultsValue(String? suiteName, String key, String? value)
Saves a string value to native storage. On iOS, UserDefaults is used; if suiteName is specified, the App Group suite is used. On Android, suiteName is ignored and the value is saved to the plugin's SharedPreferences (altcraft_sdk). If value == null, the key is removed.
| Parameter | Type | Description |
|---|---|---|
suiteName | String? | App Group / suite name for iOS. Ignored on Android. |
key | String | Storage key. Must not be null. |
value | String? | Value to save. null removes the key. |
class AltcraftConfig
class AltcraftConfig {
final String apiUrl;
final String? rToken;
final AppInfo? appInfo;
final List<String>? providerPriorityList;
final bool? enableLogging;
// Android-only
final int? icon;
final List<String>? pushReceiverModules;
final String? pushChannelName;
final String? pushChannelDescription;
}
Altcraft SDK configuration class. In toMap(), Android-only fields are passed with the android_ prefix: android_icon, android_pushReceiverModules, android_pushChannelName, android_pushChannelDescription.
| Field | Type | Required | Description |
|---|---|---|---|
apiUrl | String | Yes | Altcraft API URL. |
rToken | String? | No | Role token for scenarios without JWT. |
appInfo | AppInfo? | No | Application metadata. |
providerPriorityList | List<String>? | No | Push provider priority. Index 0 is the highest priority. |
enableLogging | bool? | No | Enables/disables native SDK logs. |
icon | int? | No | Notification icon resource ID. Used only on Android. |
pushReceiverModules | List<String>? | No | Packages of modules with overridden PushReceiver. Used only on Android. |
pushChannelName | String? | No | Push notification channel name. Used only on Android. |
pushChannelDescription | String? | No | Push notification channel description. Used only on Android. |
AppInfo:
class AppInfo {
final String appID;
final String appIID;
final String appVer;
}
| Field | Type | Description |
|---|---|---|
appID | String | Application identifier. |
appIID | String | Application installation identifier. |
appVer | String | Application version. |
Data Classes
SdkEvent
class SdkEvent {
final String function;
final int? code;
final String message;
final String type;
final Map<String, dynamic>? value;
final String? timestamp;
}
Universal SDK event, delivered to Dart via Stream<SdkEvent>.
| Field | Type | Description |
|---|---|---|
function | String | Name of the SDK function that triggered the event. |
code | int? | Event code. |
message | String | Event message. |
type | String | event, error, retryError. |
value | Map<String, dynamic>? | Additional data, e.g., response_with_http_code. |
timestamp | String? | Timestamp in yyyy-MM-dd HH:mm:ss.SSS format. |
TokenData
class TokenData {
final String provider;
final String token;
}
Device provider push token data.
| Field | Type | Description |
|---|---|---|
provider | String | Provider identifier. |
token | String | Push token value. |
ResponseWithHttpCode
class ResponseWithHttpCode {
final int httpCode;
final Map<String, dynamic>? response;
}
API response wrapper with HTTP code. ResponseWithHttpCode.fromMap() understands both top-level keys: http_code and httpCode, but the nested response remains in the format returned by the native bridge. In the current bridge, nested response fields come in snake_case.
| Dart Field | Type | Description |
|---|---|---|
httpCode | int | HTTP response code. If no HTTP code is in the map, it will be 0. |
response | Map<String, dynamic>? | Response body or null. |
Main fields of response:
| Key | Type | Description |
|---|---|---|
error | int? | Internal server error code (0 — no errors). |
error_text | String? | Error text. |
profile | Map<String, dynamic>? | Profile and subscription data. |
Nested profile structure:
| Key | Type | Description |
|---|---|---|
id | String? | Profile identifier. |
status | String? | Profile status. |
is_test | bool? | Test mode flag. |
subscription | Map<String, dynamic>? | Subscription data. |
Nested subscription structure:
| Key | Type | Description |
|---|---|---|
subscription_id | String? | Subscription identifier at the provider. |
hash_id | String? | Subscription hash. |
provider | String? | Subscription provider. |
status | String? | Subscription status (subscribed, suspended, unsubscribed). |
fields | Map<String, dynamic>? | System and custom fields. |
cats | List<dynamic>? | Subscription categories. |
CategoryData
class CategoryData {
final String? name;
final String? title;
final bool? steady;
final bool? active;
}
Subscription category. For sending to pushSubscribe, pushSuspend, or pushUnSubscribe, pass CategoryData(...).toMap() or a regular Map with the required fields.
| Field | Type | Description |
|---|---|---|
name | String? | Category name. |
title | String? | Category title. Usually populated in SDK responses. |
steady | bool? | Stability flag. Usually populated in SDK responses. |
active | bool? | Category active status. |
Subscription
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 model for mobileEvent(). toMap() adds both type and channel keys; the native bridge reads channel as the primary discriminator and type as fallback.
Factory constructors:
Subscription.email({
required int resourceId,
required String email,
String? status,
int? priority,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
})
Subscription.sms({
required int resourceId,
required String phone,
String? status,
int? priority,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
})
Subscription.push({
required int resourceId,
required String provider,
required String subscriptionId,
String? status,
int? priority,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
})
Subscription.ccData({
required int resourceId,
required String channel,
required Map<String, dynamic> ccData,
String? status,
int? priority,
Map<String, dynamic>? customFields,
List<dynamic>? cats,
})
For mobileEvent(subscription: ...), pass subscription.toMap(). If the required fields for the subscription are missing, the native bridge cannot assemble the subscription model and will send the event without it.
UTM
class UTM {
final String? source;
final String? medium;
final String? campaign;
final String? content;
final String? keyword;
final String? temp;
}
UTM parameter container for mobile events. Passed to mobileEvent() as UTM(...).toMap().
ActionFieldBuilder
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);
Builder for structured profile field management. Produces a map compatible with the native SDK.
| Method | Description |
|---|---|
set(value) | Set the field to the given value. |
unset(value) | Remove the field value. |
incr(value) | Increment a numeric field by the given value. |
add(value) | Add a value to a set/array field. |
delete(value) | Remove a value from a set/array field. |
upsert(value) | Set if the field is missing; update if it exists. |
import 'package:altcraft_sdk/altcraft_sdk.dart';
final profileFields = <String, dynamic>{
...actionField('_fname').set('Ivan'),
...actionField('login_count').incr(1),
...actionField('visited_pages').add('/settings'),
};
await AltcraftSDK.updateProfileFields(profileFields: profileFields);
Exceptions
AltcraftException
class AltcraftException implements Exception {
final String code;
final String message;
final Object? details;
}
Exception thrown by the Dart wrapper on MethodChannel errors. Check code and message.
| Field | Type | Description |
|---|---|---|
code | String | Error code (ERR, SDK_ERROR, UNAVAILABLE_ON_IOS, ALTCRAFT_INIT_INVALID_CONFIG, etc.). |
message | String | Error message. |
details | Object? | Additional data, if the native bridge passed it. |
try {
await AltcraftSDK.takePush(const {'_uid': 'push-message-uid-0001'});
} on AltcraftException catch (e) {
if (e.code == 'UNAVAILABLE_ON_IOS') {
print('This method is Android-only');
return;
}
print('SDK error (${e.code}): ${e.message}');
}
SdkNotInitializedException
class SdkNotInitializedException extends AltcraftException
The class is exported by the package and may be used by custom/test implementations of the platform interface. In the standard MethodChannel implementation, native-side errors are converted to a regular AltcraftException, so in the application it is more reliable to check e.code.
Constants
Push notification providers:
| Provider | Value |
|---|---|
| FCM (Android) | android-firebase |
| HMS (Android) | android-huawei |
| RuStore (Android) | android-rustore |
| APNS (iOS) | ios-apns |
| FCM (iOS) | ios-firebase |
| HMS (iOS) | ios-huawei |
Subscription statuses:
| Status | Value |
|---|---|
| Subscribed | subscribed |
| Unsubscribed | unsubscribed |
| Suspended | suspended |