reteno_plugin 1.9.0
reteno_plugin: ^1.9.0 copied to clipboard
The Reteno Flutter Plugin for Mobile Customer Engagement and Analytics solutions
reteno_plugin #
Reteno Flutter SDK
Documentation #
Official documentation Migration guide
Installation #
1. Add package #
flutter pub add reteno_plugin
2. Initialize SDK in Flutter #
import 'package:reteno_plugin/reteno.dart';
await Reteno().initialize(
accessKey: '<your_access_key>',
options: RetenoInitOptions(
lifecycleTrackingOptions: LifecycleTrackingOptions.all(),
isDebug: false,
deviceTokenHandlingMode: RetenoDeviceTokenHandlingMode.automatic,
),
);
3. Request push permission #
final granted = await Reteno().requestPushPermission();
4. Verify integration diagnostics #
final issues = await Reteno().diagnose();
// [] means integration checks passed
iOS requirements #
- Add
NotificationServiceExtensionand follow iOS guide Step 1: https://docs.reteno.com/reference/ios#step-1-add-the-notification-service-extension - Add
pod 'Reteno', '2.6.2'to app target and all Reteno notification extensions. - Configure App Group for app + extension.
- Do not initialize Reteno manually from
AppDelegatewhen using this Flutter plugin. Initialization should be done viaReteno().initialize(...). - For push image carousel/GIF UI on iOS, add
NotificationContentExtensionwithRetenoCarouselNotificationViewControllerand categoriesImageCarousel/ImageGif.
NotificationServiceExtension + App Group are required for full iOS Reteno push functionality.
Android requirements #
- Enable AndroidX and complete Firebase setup from Android guide: https://docs.reteno.com/reference/android-sdk-setup
minSdkVersionmust be at least21.- Do not add custom
FirebaseMessagingServiceonly for Reteno. The plugin handles Reteno push service wiring internally.
Android advanced setup (if your app already has custom FirebaseMessagingService) #
Use this only when you already have app-specific FCM logic and need to keep it.
Rules:
- Your app must have exactly one app-level
MESSAGING_EVENTservice. - That service should inherit from
RetenoFirebaseMessagingService. onNewTokenandonMessageReceivedmust callsuper.- Remove plugin bridge service from manifest merge in the app module.
Manifest example:
<application xmlns:tools="http://schemas.android.com/tools">
<service
android:name="com.reteno.reteno_plugin.RetenoFirebaseMessagingServiceBridge"
tools:node="remove" />
<service
android:name=".MyMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
Service example:
import com.google.firebase.messaging.RemoteMessage
import com.reteno.fcm.RetenoFirebaseMessagingService
class MyMessagingService : RetenoFirebaseMessagingService() {
override fun onNewToken(token: String) {
super.onNewToken(token)
// your token logic
}
override fun onMessageReceived(message: RemoteMessage) {
super.onMessageReceived(message)
if (!isRetenoMessage(message)) {
// your non-Reteno message logic
}
}
}
Diagnose codes #
Reteno().diagnose() may return:
| Code | Meaning |
|---|---|
SDK_NOT_INITIALIZED |
Reteno SDK has not been initialized yet |
NOTIFICATIONS_DISABLED |
Notifications are disabled in OS settings |
PUSH_PERMISSION_DENIED |
Notification runtime permission denied |
PUSH_PERMISSION_NOT_DETERMINED |
iOS permission dialog not shown yet |
REMOTE_NOTIFICATIONS_NOT_REGISTERED |
iOS permission granted but APNs registration not completed |
FCM_MESSAGING_SERVICE_MISSING |
Android has no active MESSAGING_EVENT handler |
RETENO_MESSAGING_SERVICE_MISSING |
Android has no Reteno push handler among MESSAGING_EVENT services |
FCM_MESSAGING_SERVICE_CONFLICT |
Multiple app-level MESSAGING_EVENT services detected on Android |
FCM_TOKEN_MISSING |
Android SDK cannot get current FCM token |
FCM_TOKEN_FETCH_FAILED |
Android failed to fetch FCM token from Firebase SDK |
Push troubleshooting (Android) #
If Reteno Console says contact has no app token:
- Ensure
Reteno().initialize(...)is called on app startup before user update calls. - Request push permission (
Reteno().requestPushPermission()). - Call
Reteno().setUserAttributes(userExternalId: ...)for the same contact you target in Console. - Run
Reteno().diagnose()and resolve all returned codes. - Verify app has only one effective app-level
MESSAGING_EVENTservice (or bridge + proper merge setup).
Push notifications #
Getting initial notification #
When you instantiate the app by clicking on a push notification, you may need to get its payload.
To do it, use the getInitialNotification method:
import 'package:reteno_plugin/reteno.dart';
final Reteno reteno = Reteno();
reteno.getInitialNotification().then((Map<String, dynamic>? payload) {
// Process payload...
});
Listening for new push notifications in an open app #
When the app is open, you may need to track for new push notifications.
For that, the plugin provides the onRetenoNotificationReceived stream you can listen to:
import 'package:reteno_plugin/reteno.dart';
Reteno.onRetenoNotificationReceived.listen((Map<String, dynamic> payload) {
// Process payload...
});
Getting notification data when interacting with push #
When you want to handle interaction with received notification you can use onRetenoNotificationClicked stream, so you can listen to it and receive notification data:
import 'package:reteno_plugin/reteno.dart';
Reteno.onRetenoNotificationClicked.listen((Map<String, dynamic> payload) {
// Process payload...
});
Push notification actions #
When you want to handle push notification actions you can use onUserNotificationAction stream, so you can listen to it and receive notification action data:
import 'package:reteno_plugin/reteno.dart';
Reteno.onUserNotificationAction.listen((event) {
print('$_retenoPluginLogTag: onUserNotificationAction: ${event.toString()}');
});
Tracking user behaviour #
Track Custom Events #
Reteno SDK provides ability to track custom events.
Reteno().logEvent({required RetenoCustomEvent event});
Custom Event model:
class RetenoCustomEvent {
RetenoCustomEvent({
required this.eventTypeKey,
required this.dateOccurred,
this.forcePush = false,
required this.parameters,
});
final String eventTypeKey;
final DateTime dateOccurred;
final List<RetenoCustomEventParameter> parameters;
final bool forcePush;
}
-
eventTypeKey - key qualifier of the event (provided by appDeveloper, confirmed by marketing team).
-
dateOccurred - time when event occurred (Date should be in ISO8601 format)
-
parameters - list of parameters, which describe the event
-
forcePush -
iOS-only feature; Please read more about it here
Parameter model containt key/value fields to describe the parameter:
class RetenoCustomEventParameter {
RetenoCustomEventParameter(this.name, this.value);
final String name;
final String? value;
}
Example of usage:
final dateOccured = DateTime.now();
final event = RetenoCustomEvent(
eventTypeKey: eventTypeName,
dateOccurred: dateOccured,
parameters: [
RetenoCustomEventParameter(<parameter_name>, <parameter_value>)
],
forcePush: true|false,
);
await Reteno().logEvent(event: event);
Tracking user information #
You can track the user related information using external user ID and/or user attributes. For that, you have to add userExternalId and setUserAttributes to Reteno Flutter.
Adding External User ID #
External user ID is an ID you have assigned to a user in your system (external for 'Reteno').
You can add these in Reteno Flutter using the following method:
import 'package:reteno_plugin/reteno.dart';
final reteno = Reteno();
reteno.setUserAttributes(
userExternalId: 'USER_ID',
user: userInfo,
);
Adding User Attributes #
User attributes define the information you collect about contacts in your user base. For example, phone number, email address, language preference, geographic location.
You can add user attributes using the following method:
import 'package:reteno_plugin/reteno.dart';
final reteno = Reteno();
reteno.setUserAttributes(
userExternalId: 'USER_ID',
user: userInfo,
);
Structure of the RetenoUser object:
class RetenoUser {
RetenoUser({
this.subscriptionKeys,
this.userAttributes,
this.groupNamesExclude,
this.groupNamesInclude,
});
final UserAttributes? userAttributes;
final List<String>? subscriptionKeys;
final List<String>? groupNamesInclude;
final List<String>? groupNamesExclude;
}
class UserAttributes {
UserAttributes({
this.lastName,
this.firstName,
this.address,
this.email,
this.fields,
this.languageCode,
this.phone,
this.timeZone,
});
final String? phone;
final String? email;
final String? firstName;
final String? lastName;
final String? languageCode;
final String? timeZone;
final Address? address;
final List<UserCustomField>? fields;
}
class Address {
Address({
this.address,
this.postcode,
this.region,
this.town,
});
final String? region;
final String? town;
final String? address;
final String? postcode;
}
class UserCustomField {
UserCustomField({
required this.key,
this.value,
});
final String key;
final String? value;
}
Anonymous User Attributes #
Available for reteno_plugin starting from version 1.1.0
Retenoplugin allows tracking anonymous user attributes(no externalUserId required). To set user attributes without externalUserId use methodsetAnonymousUserAttributes():
Reteno.setAnonymousUserAttributes(AnonymousUserAttributes attributes);
**AnonymousUserAttributes** model:
```dart
class AnonymousUserAttributes {
AnonymousUserAttributes({
this.lastName,
this.firstName,
this.address,
this.fields,
this.languageCode,
this.timeZone,
});
final String? firstName;
final String? lastName;
final String? languageCode;
final String? timeZone;
final Address? address;
final List<UserCustomField>? fields;
}
Note: you can't provide anonymous user attributes with phone or/and email. For that purpose use
setUserAttributes()method with externalUserId
Note
LanguageCode
The tags for identifying language must be in compliance with RFC 5646. The primary language subtag must comply with the ISO 639-1 format. Example: de-AT.
TimeZone
The time zone format must comply with TZ database. Example: Europe/Kyiv.
Note
In versions before 1.2.2 you can not use sentry_fltter due to sentry iOS versions mismatch. If you want to use sentry_flutter in your application. Please use flutter_plugin : 1.2.2 and sentry_flutter: 7.8.0
In-App Messages #
Pausing and Resuming In-App Messages #
You can pause and resume in-app messages using the following methods:
// Pause in-app messages
Reteno.pauseInAppMessages(true);
// Resume in-app messages
Reteno.pauseInAppMessages(false);
Listening for In-App Message Status Changes #
Reteno.onInAppMessageStatusChanged.listen((status) {
switch (status) {
case InAppShouldBeDisplayed():
print('In-app should be displayed');
case InAppIsDisplayed():
print('In-app is displayed');
case InAppShouldBeClosed(:final action):
print('In-app should be closed $action');
case InAppIsClosed(:final action):
print('In-app is closed $action');
case InAppReceivedError(:final errorMessage):
print('In-app error: $errorMessage');
}
});
Get recommended products #
You can personalize the user experience and increase sales by adding recommendations of your goods and services to an app.
final recommendations = await Reteno.getRecommendations(
recomenedationVariantId: 'r1107v1482',
productIds: ['240-LV09', '24-WG080'],
categoryId: 'Default Category/Training/Video Download',
filters: [RetenoRecomendationFilter(name: 'filter_name', values: ['filter_value'])],
fields: ['productId', 'name', 'descr', 'imageUrl', 'price'],
);
Reteno App Inbox #
Downloading new messages #
final messages = await Reteno.appInbox.getAppInboxMessages();
Marking message as opened #
Reteno.appInbox.markAsOpened(message.id);
Marking all messages as opened #
Reteno.appInbox.markAllMessagesAsOpened();
Obtaining messages count #
final count = await Reteno.appInbox.getAppInboxMessagesCount();
Subscribing to messages count changes #
Reteno.appInbox.onMessagesCountChanged.listen((count) {
print(count);
});
License #
MIT