What is the Emarsys SDK?
The Emarsys SDK enables you to use Mobile Engage and Predict in a very straightforward way. By incorporating the SDK in your app, we, among others, support you in handling credentials, API calls, tracking of opens and events as well as logins and logouts in the app.
The Flutter plug-in for SAP Emarsys Customer Engagement
The currently supported platforms are iOS and Android.
The Flutter plug-in for SAP Emarsys Customer Engagement is the official plug-in to help you to integrate Emarsys into your Flutter application. We have created a sample application to help in the integration and to give an example. The Flutter sample application is published here.
On this page, we will not go into details about how the SDK works, and what the supported features can be used for.
For more detailed information about the different features, please visit the documentation for the iOS SDK or Android SDK.
As this Flutter plug-in uses the respective iOS SDK or Android SDK, make sure to fulfill the requirements of those SDKs.
Requirements
Android
- The minimum Android version should be at least API level 24.
- Requires compileSdkVersion 28 or higher.
- Emarsys SDK is using AndroidX.
iOS
- The iOS target should be iOS 11 or higher.
- In order to be able to send push messages to your app, you need to have certifications from Apple Push Notification service (APNs).
Flutter Plug-in installation
1. Install the Emarsys SDK
- To make available the Emarsys SDK for your project, you have to open the project's
pubspec.yaml
file and add this into the dependencies section:
emarsys_sdk: ^1.3.0
- After our SDK as dependency has been added to the
pubspec.yaml
, you have to callflutter pub get
in the terminal to download the library.
The official pub.dev page of the plug-in is available here.
2. Setup the Emarsys SDK
To make the SDK usable in your project, you have to do a few initial steps in the native part.
Android
Since the Plug-in uses AGP 8.1+ remove your package from the AndroidManifest
and define the namespace
property in the build.gradle
as stated in the AGP 8.0 instead. For more information, see AGP Release Notes.
android {
namespace 'com.example.yourapp'
}
It is also necessary to set the JVM version to 17 in the build.gradle
. Add the following lines inside the Android block.
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
kotlin {
jvmToolchain(17)
}
}
Extend from FlutterFragmentActivity
instead of FlutterActivity
in the android/app/.../MainActivity
. This is necessary for the SDK, to be able to show in-app and Push to In-app messages.
To be able to receive push messages, please see the following sections to enable support for Firebase and/or Huawei services.
Firebase
- Add google-services to your
android/app/build.gradle apply plugin: 'com.google.gms.google-services'
- Specify your google-services version in your
android/build.gradle, under buildscript/dependencies
.classpath 'com.google.gms:google-services:4.3.8'
- Copy your
google-services.json
file to theandroid/app
directory of your Flutter application. - Open the
AndroidManifest.xml
and add the following part in theapplication
section:
<service android:name="com.emarsys.emarsys_sdk.api.EmarsysFirebaseMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
Extend from FlutterFragmentActivity
instead of FlutterActivity
in the android/app/.../MainActivity
; it is necessary for the SDK, to be able to show In-App and Push to In-App messages.
Huawei
Push sending for Huawei is unavailable for devices below API level 22.
Emarsys SDK checks if the device has Google Play Services available; if not, it is considered as a Huawei device. Please note that as Google Play Services are NOT available with Huawei-only integration, Geofencing will not work.
Copy your agconnect-services.json
to the android/app
directory of your Flutter application. Open the AndroidManifest.xml
and add the following parts in the application section:
<meta-data
android:name="com.huawei.hms.client.channel.androidMarket"
android:value="false" />
<meta-data
android:name="push_kit_auto_init_enabled"
android:value="true" />
<service android:name="com.emarsys.emarsys_sdk.api.EmarsysHuaweiMessagingService">
<intent-filter>
<action android:name="com.google.huawei.MESSAGING_EVENT" />
</intent-filter>
</service>
iOS
Open the iOS app in XCode
and add the following capabilities to the applications target:
- Push Notifications
- Background Modes, with
Background fetch
,Remote Notifications
,Background processing
enabled
Then add a Notification Extension Service
target to your project.
Extend your Podfile
with:
target '<Your Notification Extension Service Name>' do
use_frameworks!
use_modular_headers!
pod 'EmarsysNotificationService'
end
After a pod deintegrate
and pod install
extend your Notification Extension Service from EMSNotificationService
.
import UserNotifications
import EmarsysNotificationService
class NotificationService: EMSNotificationService {
}
You have to extend your AppDelegate
from our EmarsysAppDelegate
class to make the SDK usable and add this code part: GeneratedPluginRegistrant.register(with: self)
to the first line of your didFinishLaunchingWithOptions
method.
Without any further modifications, your whole class should look like this:
import UIKit
import Flutter
import emarsys_sdk
@UIApplicationMain
@objc class AppDelegate: EmarsysAppDelegate {
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Flutter
- To be able to use the SDK in your project, import the Emarsys plug-in as in the following example:
import 'package:emarsys_sdk/emarsys_sdk.dart';
- Then in the main method after the
WidgetsFlutterBinding.ensureInitialized();
line, you have to set up the Emarsys SDK with the following config:
Please make sure that WidgetsFlutterBinding.ensureInitialized();
has been added to the first line of the main method.
void main() {
WidgetsFlutterBinding.ensureInitialized();
Emarsys.setup(
EmarsysConfig(<contactFieldId: int>, <applicationCode: String>));
runApp(MyApp());
}
3. Contact management
The setContactFieldId
should not be set to 3 (email). In order to prevent your customers' personal data (PII) being stored in our cloud infrastructure, we require the use of unique, non-guessable and immutable contact identifiers. Customer ID's are considered secure. Salted email hash is no longer supported for new Mobile Engage implementations. To make sure the behavioural tracking is cross devices (i.e. mobile and web), the Web Extend contact ID should also use Customer ID and match that used on mobile.
3.1. setContact
After application setup is finished, you can use setContact
method to identify the user with contactFieldValue
.
Emarsys.setContact(<contactFieldId: int>, <contactFieldValue: String>);
3.2. clearContact
When the user signs out, the clearContact
method should be used:
You only need to call clearContact
when you explicitly want to sign out the contact from Emarsys, even if the user is not logged in into your application.
Emarsys.clearContact();
4. Push
4.1. pushSendingEnabled
By default, the Emarsys SDK plug-in will set pushSendingEnabled
to true, to ensure that the application will be able to receive remote notifications.
Emarsys.push.pushSendingEnabled(true);
To be able to show push notifications, the Android notification channels have to be set since API level 26 (Oreo). To make integration easier with the SDK, we have created a wrapper around the Notification Channels API.
Emarsys.push.registerAndroidNotificationChannels([
NotificationChannel(
id: "ems_sample_news",
name: "News",
description: "News and updates go into this channel",
importance: NotificationChannel.IMPORTANCE_HIGH),
NotificationChannel(
id: "ems_sample_messages",
name: "Messages",
description: "Important messages go into this channel",
importance: NotificationChannel.IMPORTANCE_HIGH),
]);
4.2. pushEventStream
Unlike the native Emarsys SDK, you cannot register eventHandlers
, but can react to an event by subscribing to event streams
:
Emarsys.push.pushEventStream.listen((event) {
print(event.name);
print(event.payload);
});
4.3. silentPushEventStream
Unlike the native Emarsys SDK, you cannot register eventHandlers
, but can react to an event by subscribing to event streams
:
Emarsys.push.silentPushEventStream.listen((event) {
print(event.name);
print(event.payload);
});
4.4. setPushToken
The Emarsys SDK automatically handles setPushToken
for the device and it is Emarsys' official recommendation to leave this to the SDK. If you need your own implementation you can set the pushToken
manually with the the following command, where the pushToken
is the token itself as a String.
Emarsys.setPushToken(pushToken)
5. In-app
5.1. Overlay In-App
A full screen In-App dialog that hovers in front of the application. Only one can be displayed at a time.
5.1.1. pause
When a critical activity starts and should not be interrupted by In-App, pause In-App messages.
Emarsys.inApp.pause();
5.1.2. resume
In order to show In-App messages after being paused, use the resume method.
Emarsys.inApp.resume();
5.1.3. isPaused
Emarsys.inApp.isPaused();
5.1.4. inAppEventStream
Unlike the native Emarsys SDK, you cannot register eventHandlers
, but can react to an event by subscribing to event streams
:
Emarsys.inApp.inAppEventStream.listen((event) {
print(event.name);
print(event.payload);
});
5.2. Inline In-App
In-App message that takes place in the application's view hierarchy. Multiple inline In-App components are allowed in one screen.
There are 2 possible ways to create InlineInAppViews
on Android: a hybrid composition or a virtual display. This can be toggled with the androidUseVirtualDisplay
flag while creating the InlineInAppView
, by default we use the Hybrid composition.
In case of iOS, only hybrid composition is available, so there are no additional flags there.
Our InlineInAppView
solution uses Flutter Platform views, which allows to embed native views. This Platform view by default has infinite size, which causes the application to crash if it is not wrapped in a sized container. The current recommendation is to wrap these views in a SizedBox or a Container like we do it in this example:
SizedBox(
height: 100,
child: InlineInAppView(
viewId: <String: viewId>,
androidUseVirtualDisplay: true,
onAppEvent: (event) {
print("eventName: ${event.name}, payload:${event.payload}");
},
onCompleted: () {
print("in-app view has been loaded.");
},
onClose: () {
setState(() {
showInlineInApp = false;
});
},
))
6. Inbox
User centric inbox solution. Emarsys SDK provides a Message
named model class to make Inbox information easily accessible.
class Message extends Equatable {
final String id;
final String campaignId;
final String? collapseId;
final String title;
final String body;
final String? imageUrl;
final int receivedAt;
final int? updatedAt;
final int? expiresAt;
final List<String>? tags;
final Map<String, String>? properties;
final List<ActionModel>? actions;
}
The following action types are supported:
- App event action
AppEventActionModel(
{required this.id,
required this.title,
required this.type,
required this.name,
this.payload});
- Custom event action
AppEventActionModel(
{required this.id,
required this.title,
required this.type,
required this.name,
this.payload});
- Open External URL event action
AppEventActionModel(
{required this.id,
required this.title,
required this.type,
required this.name,
this.payload});
6.1. fetchMessages
In order to receive the messageInbox content, you can use the fetchMessages method.
Future<List<Message>> messages = Emarsys.messageInbox.fetchMessages();
6.2. addTag
To label a message with a tag, you can use the addTag method (for example: "READ", "SEEN" etc).
Emarsys.messageInbox.addTag(message.id, <MESSAGE_TAG : String>);
6.3. removeTag
To remove a label from a message, you can use removeTag method.
Emarsys.messageInbox.removeTag(message.id, <MESSAGE_TAG : String>);
7. Tracking custom events
7.1. trackCustomEvent
If you want to track custom events, use the trackCustomEvent
method, where the eventName
parameter is required, but the attributes are optional.
Emarsys.trackCustomEvent(<eventName: String>, <attributes: Map<String, Object>?>);
8. Geofence
Geofencing is disabled on Android devices that do not have Google Play Services!
Geofence makes it available to trigger certain actions, based on the user's location. When the user enters a predefined region, (represented by latitude, longitude, and radius) the EmarsysSDK fires a customEvent, which can trigger an action (for example a push notification). This requires permission for background locations from the user.
Currently supported triggers
The geofence feature has two different trigger types: ENTER
and EXIT
.
-
ENTER
triggers when the user reaches the bounds of the geofence and enters it. -
EXIT
triggers when the user reaches the bounds of the geofence and exits it.
Based on our experiences so far, the accuracy of geofencing is inconsistent and can be different based on device types and the environment of usage. We recommend adding at least 100m of radius to your geofences, to ensure that the triggers happen. Based on the Android documentation, only 100 geofences/app can be used, so please be aware that our current geofencing solution works well only, if there are no other geofencing solutions used by the application.
8.1. enable
The enable
method is responsible for the activation of this feature.
Emarsys.geofence.enable();
8.2. disable
The disable
method is responsible for disabling this feature.
Emarsys.geofence.disable();
8.3. isEnabled
The isEnabled
method returns if the geofencing is currently enabled or not.
Future<bool> isGeofenceEnabled = Emarsys.geofence.isEnabled()
8.4. geofenceEventStream
Unlike the native Emarsys SDK, you cannot register eventHandlers
, but can react to an event by subscribing to event streams
:
Emarsys.geofence.geofenceEventStream.listen((event) {
print(event.name);
});
8.5. iosRequestAlwaysAuthorization
Only available on iOS
The requestAlwaysAuthorization
method is responsible for asking the required permissions from the user. Calling this method is not necessary if your app already asked the user for the permissions.
Emarsys.geofence.iOSRequestAlwaysAuthorization();
8.6. initialEnterTriggerEnabled
When initialEnterTriggerEnabled
is true
, the Emarsys SDK will trigger all the affected geofences with Enter type triggers at the moment when the geofence is enabled, if the device is already inside that geofence. By default, this value is set to false
.
Emarsys.geofence.setInitialEnterTriggerEnabled(<enabled: Boolean>);
8.7. registeredGeofences
You can access the registered geofences from the device using the registeredGeofences
method.
Future<List<GeofenceModel>> registeredGeofences = Emarsys.geofence.registeredGeofences();
9. Predict
The Flutter plug-in supports Predict functionalities, the following sections explain the mapping between the Predict commands and the interface.
For more information, see the Predict documentation.
9.1. Initialization
To use the Predict functionality, you have to set up your merchantId
during the initialization of the SDK. In order to track Predict events, you can use the methods available on our Predict interface.
9.2. trackCart
When you want to track the cart items in the basket, you can call the trackCart
method with a list of CartItems. CartItem
is an interface that can be used in your application for your own CartItems and then simply use the same items with the SDK.
Dart
await Emarsys.predict.trackCart(cartItems);
9.3. trackPurchase
To report a purchase event, call trackPurchase
with the items purchased and with an orderId
.
Dart
await Emarsys.predict.trackPurchase(orderId, items);
9.4. trackItemView
If an item was viewed, use the trackItemView
method with an itemId
as a required parameter.
Dart
await Emarsys.predict.trackItemView(itemId);
9.5. trackCategoryView
When the user navigates between the categories, call trackCategoryView
in every navigation. Be aware to send categoryPath
in the required format. See Predict documentation for more information .
Dart
await Emarsys.predict.trackCategoryView(categoryPath);
9.6. trackSearchTerm
To report search terms entered by the contact, use trackSearchTerm
method.
Dart
await Emarsys.predict.trackSearchTerm(searchTerm);
9.7. trackTag
To track custom tags, use the trackTag
method, where the eventName
parameter is required, but the attributes
is optional.
Dart
await Emarsys.predict.trackTag(eventName, attributes);
9.8. recommendProducts
With the Emarsys SDK you can ask for product recommendations
based on different recommendation logics
.
recommendProducts
will also track the value
attached to the logic
on the backend; therefore, no additional tracking is needed when using recommendations.
9.8.1. logic
This is a required parameter of the recommendProducts
method.
The currently supported logics are:
-
SEARCH
- based onsearchTerm
-
CART
- based oncartItems
-
RELATED
- based onitemViewId
-
CATEGORY
- based oncategoryPath
-
ALSO_BOUGHT
- based onitemViewId
-
POPULAR
- based oncategoryPath
-
PERSONAL
- based on current browsing and activity -
HOME
- based on most recent browsing behaviour
For more information on the recommender logics, see Web Recommender logics.
You can pass the values to the chosen recommendation logic, but if you leave it empty, the SDK handles it and uses the last tracked values.
9.8.2. variants
Variants are used by the HOME
and PERSONAL
logic types. By adding a list of Strings used as suffixes to logic names, recommendations are grouped by the variants provided.
9.8.3. filters
This is an optional parameter of the recommendProducts
method.
You can filter product recommendations
with the SDK by building RecommendationFilters
. There are two types of filters: Exclude
or Include
.
In each case there are four types of comparators you can use to compare your chosen field to expectation Value
:
-
isValue
- checking if thefield
is matching thevalue
-
inValues
- any of thevalues
has a match with thefield
-
hasValue
- One of thefield
values is equal toexpectation value
(applicable only to fields containing multiple values) -
overlapsValues
- One or more of thefield
values are found inexpectation values
(applicable only to fields containing multiple values)
For more information, see API documentation.
9.8.4. limit
This is an optional parameter of the recommendProducts
method.
You can limit the number of recommended products
received by defining a limit. This is an optional parameter with the default value 5
.
9.8.5. availabilityZones
This is an optional parameter of the recommendProducts
method.
You can personalize the recommendation further by setting the availabilityZones
parameter of the recommendation, to only recommend the locally available products.
For more information, see Using availability zones.
9.8.6. usage
The SDK is going to retrieve recommended products
as a result of the recommendProducts
method.
Dart
var products = await Emarsys.predict.recommendProducts(
logic: recommendationLogic,
filters: [recommendationFilter],
limit: 5,
availabilityZone: "HU");
9.9. trackRecommendationClick
The Emarsys SDK does not track recommendationClicks automatically, so you have to call manually trackRecommendationClick
when an interaction happens with any of the recommended products.
Emarsys.predict.trackRecommendationClick(Product clickedProduct);
10. Config
Config
can be used to access information about the values set in the Emarsys SDK.
10.1. changeApplicationCode
The Plugin provides a way, to change the applicationCode
set in the setup. For this, use the changeApplicationCode
method defined in the Emarsys.config
Emarsys.config.changeApplicationCode(<newAppCode : String>);
Please note that in case of any errors occuring during the change process, the involved feature will be turned OFF.
When changeApplicationCode
has been called, the SDK will log out the user and a setContact
(contactFieldId
, contactFieldValue
) must be called again with the correct contactFieldValue
and contactFieldId
.
For use cases of applicationCode
change, see the native SDK wiki pages.
10.2. applicationCode
This line provides what is the actual applicationCode
set in the SDK.
Emarsys.config.applicationCode();
10.3. changeMerchantId
The Plugin provides a way, to change the merchantId
set in the setup. For this, use the changeMerchantId
method defined in the Emarsys.config
Emarsys.config.changeMerchantId(<newMerchantId : String>)
10.4. merchantId
Provides what is the actual merchantId
set in the SDK.
Emarsys.config.merchantId();
10.5. contactFieldId
This line provides what is the actual contactFieldId
set in the SDK.
Emarsys.config.contactFieldId();
10.6. hardwareId
This line provides what is the actual hardwareId
set in the SDK.
Emarsys.config.hardwareId();
10.7. languageCode
This line provides what is the actual languageCode
set in the SDK.
Emarsys.config.languageCode();
10.8. notificationSettings
This line provides what is the actual notificationSettings
set in the SDK.
This method will return with a NotificationSettings
object, which contains the current notification settings, based on which platform your application runs at the moment.
Emarsys.config.notificationSettings();
10.9. sdkVersion
This is not the Flutter plug-in version.
This line provides what is the actual native sdkVersion
set in the SDK.
Emarsys.config.sdkVersion();
10.10. flutterPluginVersion
This is not the native Emarsys SDK version.
This line provides what is the actual flutterPluginVersion
.
Emarsys.config.flutterPluginVersion();
11. Data flows in the plug-in
Using this Flutter plug-in means that the automated tracking of the respective Android and iOS Emarsys SDK features will also be active. Details of this are documented for Android and iOS. In addition, when the Emarsys.setup
method is called, the Flutter plug-in will submit an Emarsys custom event reporting that the setup was called from Flutter.