Skip to content
Mihály Hunyady edited this page Sep 25, 2023 · 67 revisions

Contents

Note

This product is under development and currently it doesn't support all of the native Emarsys SDK features. At the moment it is capable of setting up the Emarsys SDK, handling push messages, displaying in-app messages and supports the interface for getting the current configuration. If you'd like to use this plugin, please start by contacting your Emarsys CSM.

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

Note

The currently supported platforms are iOS and Android.

The Flutter plug-in for SAP Emarsys Customer Engagement is the official plug-in to help 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 won't go into details about how the underlying Emarsys SDK works and how the supported features can be used. For more detailed information about the different features, please visit the documentation for the iOS SDK or the Android SDK.

As this plug-in uses the respective Emarsys iOS and Emarsys Android SDK, their requirements apply (iOS SDK Requirements, Android SDK Requirements)

Requirements

Android

  • The minimum Android version should be at least API level 24.
  • Requires compileSdkVersion 33 or higher.
  • Emarsys SDK is using AndroidX.
  • Emarsys SDK is using Android Gradle Plugin 8.1.1

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).

1. First steps

1.1 Install the Emarsys SDK

To make the Emarsys SDK available for your project, you have to open the project's pubspec.yaml file and add this into the dependencies section:

emarsys_sdk: ^<latest version>

After our SDK as dependency has been added to the pubspec.yaml, you have to call flutter pub get in the terminal to download the library.

The official pub.dev page of the plug-in is available here.

1.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 Plugin-in uses AGP 8.1+ please remove your package from the AndroidManifest and define the namespace property in the build.gradle as stated in the AGP 8.0 (release notes)[https://developer.android.com/build/releases/past-releases/agp-8-0-0-release-notes#namespace-dsl] instead.

android {
    namespace 'com.example.yourapp'
}

It is also necessary to set the JVM version to 17 in the build.gradle please 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 it 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'

Then specify your google-services version in your android/build.gradle, under buildscript/dependencies

classpath 'com.google.gms:google-services:<LATEST_VERSION>'

Copy your google-services.json to the android/app directory of your Flutter application.

Open the AndroidManifest.xml and add the following part in the application 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

Important Note: Push sending for Huawei is unavailable for devices below API level 22!

Emarsys SDK checks if the device has Google Play Services available and if not, it is considered as a Huawei device. Please note that as Google Play Services is not available with Huawei only integrations, 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

Known Xcode 15 compatibility issue

In case you are facing a Cycle inside Runner issue during building the iOS version, try to resolve it by moving the Embed Foundation Extensions under Link Binary With Libraries build phase under the Runner’s Build Phases tab.

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. So 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 plugin like in the following example

import 'package:emarsys_sdk/emarsys_sdk.dart';

Then in the main method after the WidgetsFlutterBinding.ensureInitialized(); line you have to setup the Emarsys SDK with config:

IMPORTANT

Please make sure that WidgetsFlutterBinding.ensureInitialized(); has been added to the first line of the main method.

void main() {
  WidgetsFlutterBinding.ensureInitialized();
  Emarsys.setup(
      EmarsysConfig(<applicationCode: String>));

  runApp(MyApp());
}

1.3 setContact

After application setup is finished, you can use setContact method to identify the user with a contactFieldId and a contactFieldValue. Calling this method will create a link between Emarsys and the user identified by the contactFieldId and contactFieldValue through the SDK, changing this contact from anonymous to identified.

Note

Without calling setContact all SDK related events will be linked to an anonymous contact.

Emarsys.setContact(<contactFieldId: int>, <contactFieldValue: String>);

1.4 clearContact

Calling this method will end the connection between the currently set contact and Emarsys through the SDK. Calling this method will not remove the contact from Emarsys systems. It will only change the current identified contact to an anonymous one.

Emarsys.clearContact();

1.5 trackCustomEvent

If you want to track custom events, the trackCustomEvent method should be used, where the eventName parameter is required, but the attributes are optional.

Emarsys.trackCustomEvent(<eventName: String>, <attributes: Map<String, Object>?>);

2. Config

Config can be used to access information about the values set in the Emarsys SDK.

2.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>);

Note

Please keep in mind, if any error occurs 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.

Use cases of applicationCode change can be found on the native SDK wiki pages.

2.2 applicationCode

Provides what is the actual applicationCode set in the SDK.

Emarsys.config.applicationCode();

2.3 contactFieldId

Provides what is the actual contactFieldId set in the SDK.

Emarsys.config.contactFieldId();

2.4 hardwareId

Provides what is the actual hardwareId set in the SDK.

Emarsys.config.hardwareId();

2.5 languageCode

Provides what is the actual languageCode set in the SDK.

Emarsys.config.languageCode();

2.6 notificationSettings

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();

2.7 sdkVersion

Note

This isn't the Flutter plug-in version.

Provides what is the actual native sdkVersion set in the SDK.

Emarsys.config.sdkVersion();

2.8 flutterPluginVersion

Note

This isn't the native Emarsys SDK version.

Provides what is the actual flutterPluginVersion.

Emarsys.config.flutterPluginVersion();

3. Push

3.1 pushSendingEnabled

Note

By default the Flutter plug-in will set pushSendingEnabled to true, to ensure that the application will be able to receive remote notifications.

Currently the plug-in doesn't support Huawei Push Kit, only Firebase!

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've 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),
  ]);

3.2 pushEventStream

Unlike the native Emarsys SDK, you can't register eventHandlers, but can react to an event by subscribing to event streams:

Emarsys.push.pushEventStream.listen((event) {
    print(event.name);
    print(event.payload);
});

3.3 silentPushEventStream

Unlike the native Emarsys SDK, you can't register eventHandlers, but can react to an event by subscribing to event streams:

Emarsys.push.silentPushEventStream.listen((event) {
    print(event.name);
    print(event.payload);
})

3.4 setPushToken

The Emarsys SDK automatically handles setPushToken for the device and it is recommended to leave this to the SDK. However if your usecase is different from this, you are able to set the pushToken manually, with the the following command, where the pushToken is the token itself as a String.

Emarsys.setPushToken(pushToken)

4. In-App

4.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.

4.1.1 pause

When a critical activity starts and should not be interrupted by In-App, pause In-App messages.

    Emarsys.inApp.pause();
4.1.2 resume

In order to show In-App messages after being paused, use the resume method.

    Emarsys.inApp.resume();
4.1.3 isPaused
    Emarsys.inApp.isPaused();
4.1.4 inAppEventStream

Unlike the native Emarsys SDK, you can't register eventHandlers, but can react to an event by subscribing to event streams:

Emarsys.inApp.inAppEventStream.listen((event) {
    print(event.name);
    print(event.payload);
  });

4.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.

Note

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;
            });
        },
    ))

5. 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});

5.1 fetchMessages

In order to receive the messageInbox content, you can use the fetchMessages method.

    Future<List<Message>> messages = Emarsys.messageInbox.fetchMessages();

5.2 addTag

To label a message with a tag, you can use addTag method. (for example: "READ", "SEEN" etc)

    Emarsys.messageInbox.addTag(message.id, <MESSAGE_TAG : String>);

5.3 removeTag

To remove a label from a message, you can use removeTag method.

    Emarsys.messageInbox.removeTag(message.id, <MESSAGE_TAG : String>);

6. Geofence

Note The Geofence feature is still in pilot phase, please only use it if you have a pilot service order in place! If you would like to use the feature please contact your CSM @ Emarsys.

Important Note: 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) EmarsysSDK fires a customEvent which can trigger an action, for example, a push notification. This requires permission for background locations from the user.

Note

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 only works well when there are no other geofencing solutions used by the application.

For more instructions on how to turn on Geofencing for different platforms please turn to our native Android and iOS documentation.

6.1 enable

The enable method is responsible for the activation of this feature

    Emarsys.geofence.enable();

6.2 disable

The disable method is responsible for disabling this feature

    Emarsys.geofence.disable();

6.3 isEnabled

The isEnabled method returns if the geofencing is currently enabled or not

Future<bool> isGeofenceEnabled = Emarsys.geofence.isEnabled()

6.4 geofenceEventStream

Unlike the native Emarsys SDK, you can't register eventHandlers, but can react to an event by subscribing to event streams:

  Emarsys.geofence.geofenceEventStream.listen((event) {
    print(event.name);
  });

6.5 iosRequestAlwaysAuthorization

Note: 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();

6.6 initialEnterTriggerEnabled

When initialEnterTriggerEnabled is true, 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>);

7. Predict

We won't go into the details to introduce how Predict works, and what its capabilities are, rather we aim to explain the mapping between the Predict commands and our interface. Please visit Predict's documentation for more information.

7.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.

7.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);

7.3 trackPurchase

To report a purchase event, you should call trackPurchase with the items purchased and with an orderId.

Dart
await Emarsys.predict.trackPurchase(orderId, items);

7.4 trackItemView

If an item was viewed, use the trackItemView method with an itemId as a required parameter.

Dart
await Emarsys.predict.trackItemView(itemId);

7.5 trackCategoryView

When the user navigates between the categories, you should call trackCategoryView in every navigation. Be aware to send categoryPath in the required format. Please visit Predict's documentation for more information .

Dart
await Emarsys.predict.trackCategoryView(categoryPath);

7.6 trackSearchTerm

To report search terms entered by the contact, use trackSearchTerm method.

Dart
await Emarsys.predict.trackSearchTerm(searchTerm);

7.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);

7.8 recommendProducts

With the Emarsys SDK you can ask for product recommendations based on different recommendation logics.

Note

recommendProducts is also going to track the value attached to the logic on the backend, so no additional tracking needed when using recommendations!

7.8.1 logic

This is a required parameter of the recommendProducts method.

The currently supported logics are:

  • SEARCH - based on searchTerm
  • CART - based on cartItems
  • RELATED - based on itemViewId
  • CATEGORY - based on categoryPath
  • ALSO_BOUGHT - based on itemViewId
  • POPULAR - based on categoryPath
  • PERSONAL - based on current browsing and activity
  • HOME - based on most recent browsing behaviour

Note

For more information on the recommender logics, please visit the official documentation.

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.

7.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.

7.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 every case there are four types of comparators you can use to compare your chosen field to expectationValue:

  • isValue - checking if the field is matching the value
  • inValues - any of the values has a match with the field
  • hasValue - One of the field values is equal to expectation value (applicable only to fields containing multiple values)
  • overlapsValues - One or more of the field values are found in expectation values (applicable only to fields containing multiple values)

For further information please check the predict documentation.

7.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, by default its value is 5.

7.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 please check the Emarsys Predict documentation

7.8.6 usage

The SDK is going to retrieve recommended products as result of the recommendProducts method

Dart
var products = await Emarsys.predict.recommendProducts(
        logic: recommendationLogic,
        filters: [recommendationFilter],
        limit: 5,
        availabilityZone: "HU");

7.9 trackRecommendationClick

The Emarsys SDK doesn't track automatically recommendationClicks, so you have to call manually trackRecommendationClick when an interaction happens with any of the recommended products.

Dart
Emarsys.getPredict().trackRecommendationClick(Product clickedProduct);

8. Data flows in the plugin

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.