-
Notifications
You must be signed in to change notification settings - Fork 20
Home
- Integrate with EMSAppDelegate
- Integrate without EMSAppDelegate
- 1. First steps
- 2. Push
- 3. InApp
- 4. Predict
- 5. DeepLink
- 6. ApplicationCode and merchantId change
- 7. Inbox
- 8. Geofence
- 9. On Event Action
Note
The use of this approach is optional, you can follow the steps below to integrate the SDK.
We created an easier solution to integrate Emarsys SDK by inheriting from our EMSAppDelegate. Find our instructions here
Note
Please complete the required steps before proceeding
A Sample Application using the Emarsys SDK is available here. The Sample Application provides examples of how you can use the various features of the Emarsys SDK in a real application and what steps are needed e.g. to be able to receive push messages.
To configure the SDK, the following has to be done in the AppDelegate
of the application:
Note
ApplicationCode: is needed if you want to use Mobile Engage features
MerchantId: is needed if you want to use Predict features
If you want to share hardware id between applications you use Emarsys SDK in, further steps are requiered. This feature is only available from 2.7.0. For more information please read here
The console logging is only working on DEBUG mode
Our default console logging is only showing logs when you call an unallowed method. You are able to modify the allowed loglevels for console logging, by setting it during the setup.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
EMSConfig *config = [EMSConfig makeWithBuilder:^(EMSConfigBuilder *builder) {
[builder setMobileEngageApplicationCode:<applicationCode: NSString>];
[builder setMerchantId:<merchantId: NSString>];
[builder enableConsoleLogLevels:@[<EMSLogLevel.trace, EMSLogLevel.debug, EMSLogLevel.info, EMSLogLevel.warn, EMSLogLevel.error, EMSLogLevel.basic>]];
}];
[Emarsys setupWithConfig:config];
return YES;
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let config = EMSConfig.make { builder in
builder.setMobileEngageApplicationCode(<applicationCode: String>)
builder.setMerchantId(<merchantId: String>)
builder.enableConsoleLogLevels([<EMSLogLevel.trace, EMSLogLevel.debug, EMSLogLevel.info, EMSLogLevel.warn, EMSLogLevel.error, EMSLogLevel.basic>])
}
Emarsys.setup(config: config)
return true
}
After application setup is finished, you can use setContact
method to identify the user with contactFieldValue
.
Without contact identification all tracked events will be linked to an anonymous contact in Mobile Engage and will rely on visitor cookies in case of Predict.
[Emarsys setContactWithContactFieldId:<contactFieldId: NSNumber>
contactFieldValue:<contactFieldValue: NSString>
completionBlock:^(NSError *error) {
}];
Emarsys.setContact(<contactFieldId:NSNumber>, <contactFieldValue: String>) { error in
}
Note
At the current time Predict does not support authenticating users with Open ID Connect, identifying a contact with
setAuthenticatedContact
will disable the usage of Predict features!
After the application setup is finished, you can use setAuthenticatedContact
method to identify the user with an openIdToken
.
More information about Open ID Connect can be found here.
Without contact identification all tracked events will be linked to an anonymous contact in Mobile Engage and will rely on visitor cookies in case of Predict. Please note that openIdToken
parameter is required, but the CompletionListener is optional.
[Emarsys setAuthenticatedContactWithContactFieldId:<contactFieldId: NSNumber>
openIdToken:<openIdToken: NSString>
completionBlock:^(NSError *error) {
}];
Emarsys.setAuthenticatedContact(<contactFieldId: NSNumber>, <openIdToken: String>) { error in
}
When the user signs out, the clearContact
method should be used:
Note
You only need to call clearContact when you explicitly want to sign out the contact from Emarsys even if the user isn’t logged in into your application.
[Emarsys clearContactWithCompletionBlock:^(NSError *error) {
}];
Emarsys.clearContact { error in
}
If you want to track custom events, the trackCustomEvent
method should be used, where the eventName
parameter is required, but the other attributes are optional.
[Emarsys trackCustomEventWithName:<eventName: NSString>
eventAttributes:<eventAttributes: NSDictionary<NSString, NSString>
completionBlock:^(NSError *error) {
}];
Emarsys.trackCustomEvent(<eventName: String>, eventAttributes: <eventAttributes: NSDictionary<String, String>) { error in
}
The pushToken
has to be set when it arrives:
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
[Emarsys.push setPushToken:deviceToken
completionBlock:^(NSError *error) {
}];
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
Emarsys.push.setPushToken(<pushToken: Data>) { error in
}
}
The pushToken
value can be retreived by this method
[Emarsys.push pushToken];
Emarsys.push.pushToken
If you want to remove pushToken
for the Contact, you can use clearPushToken
.
[Emarsys.push clearPushTokenWithCompletionBlock:^(NSError *error) {
}];
Emarsys.push.clearPushToken { error in
}
If you want to track whether the push messages have been opened, the trackMessageOpen
method should be used.
In the simplest case this call will be in the AppDelegate's didReceiveRemoteNotification:fetchCompletionHandler:
method:
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[Emarsys.push trackMessageOpenWithUserInfo:userInfo
completionBlock:^(NSError *error) {
}];
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
Emarsys.push.trackMessageOpen(userInfo: userInfo) { error in
}
}
In order to react to an event triggered from the push message, you can register for it using the setNotificationEventHandler
method.
The eventHandler is a block/closure for a push message event.
[Emarsys.push setNotificationEventHandler:<notificationEventHandler: EMSEventHandlerBlock>];
Emarsys.push.notificationEventHandler = <notificationEventHandler: EMSEventHandlerBlock>
In order to react to an event triggered from the silent message, you can register for it using the setSilentMessageEventHandler
method.
The eventHandler is a block/closure for silent message event.
[Emarsys.push setSilentMessageEventHandler:<silentMessageEventHandler: EMSEventHandlerBlock>];
Emarsys.push.silentMessageEventHandler = <silentMessageEventHandler: EMSEventHandlerBlock>
Silent messages arrives in application:didReceivedRemoteNotification:fetchCompletionHandler:
, so in order to be able to handle them, call handleMessageWithUserInfo:
method there, or inherit your appDelegate from our EMSAppdelegate so we handle it for you.
- (void) application:(UIApplication *)application
didReceiveRemoteNotification:(NSDictionary *)userInfo
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
[Emarsys.push handleMessageWithUserInfo:userInfo];
completionHandler(UIBackgroundFetchResultNewData);
}
override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
Emarsys.push.handleMessage(userInfo: userInfo)
completionHandler(.newData)
}
In case you need information about the received message, you can set your EMSSilentNotificationInformationBlock
to our Emarsys.push
and we will call it with a NotificationInformation
object.
[Emarsys.push setNotificationInformationBlock:^(EMSNotificationInformation * _Nonnull notificationInformation) {
}];
Emarsys.push.silentNotificationInformationBlock = { notificationInformation in
}
A full screen In-App dialog, that hovers in front of the application. Only one can be displayed at a time.
When a critical activity starts and should not be interrupted by In-App, pause
In-App messages.
[Emarsys.inApp pause];
Emarsys.inApp.pause()
In order to show In-App messages after being paused, use the resume
method.
[Emarsys.inApp resume];
Emarsys.inApp.resume()
BOOL isPaused = [Emarsys.inApp isPaused];
let isPaused = Emarsys.inApp.isPaused()
In order to react to an event triggered from the In-App message, you can register for it using the setEventHandler
method.
The eventHandler is a block/closure for an In-App message event.
[Emarsys.inApp setEventHandler:<eventHandler: <EMSEventHandlerBlock>];
Emarsys.inApp.eventHandler = <eventHandler: EMSEventHandlerBlock>
In-App message, that takes place in the application's view hierarchy. Multiple inline In-App components are allowed in one screen.
Note
The Inline In-App feature is still in pilot phase, please only use it if you have a pilot service order in place! If you need help with piloting, please contact your Client Success Manager @ Emarsys.
There are three ways to implement the inline In-App.
- First way is the Interface Builder, this way eventHandler, completionBlock and closeBlock cannot be set.
- Secondly is fully from code, this way it must be set up with it's init method.
- The last one is the mixed setup, for this the view must be created through interface builder, then the blocks must be set through code.
In order to load the inline In-App, the loadInAppWithViewId
must be called with the corresponding viewId. When the view is created from the UI builder and this value has been set, this call is unnecessary.
EMSInlineInAppView *inappView = [[EMSInlineInAppView alloc] initWithFrame:<frame: CGRect>];
[self.inappView loadInAppWithViewId:@"view-id"];
let inlineInApp = EMSInlineInAppView(<frame: CGRect>)
inlineInApp.loadInApp(<viewId: String>)
In order to react to an event triggered from the In-App message, you can register for it using the setEventHandler
method.
The eventHandler is a block/closure for an In-App message event.
inlineInApp.eventHandler = ^(NSString *eventName, NSDictionary<NSString *, NSObject *> *payload) {
...
};
inlineInApp.eventHandler = { name, payload in
...
}
The completionBlock is triggered when the inline In-App message is loaded.
inlineInApp.completionBlock = ^(NSError *error) {
...
};
inlineInApp.completionBlock = { error in
...
}
The closeBlock is triggered when the close button has been clicked in the inline In-App message.
inlineInApp.closeBlock = ^{
...
};
inlineInApp.closeBlock = {
...
}
We won't go into the details to introduce how Predict works, and what its capabilities are, but here we aim to explain the mapping between the Predict commands and our interface. Please visit Predict's documentation for more details.
To use the Predict functionality, you have to setup your merchantId
during the initialization of the SDK.
In order to track Predict events, you can use the methods available on our Predict interface.
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.
[Emarsys.predict trackCartWithCartItems:<items: NSArray<EMSCartItem *> *>];
Emarsys.predict.trackCart(<items: Array<EMSCartItem>>)
To report a purchase event you should call trackPurchase
with the items purchased and with an orderId
.
[Emarsys.predict trackPurchaseWithOrderId:<orderId: NSString>
items:<items: NSArray<EMSCartItem *> *>];
Emarsys.predict.trackPurchase(<orderId: String>, <items: Array<EMSCartItem>>)
If an item was viewed use the trackItemView
method with an itemId
.
[Emarsys.predict trackItemViewWithItemId:<itemId: NSString>];
Emarsys.predict.trackItemView(itemId: <itemId: String>)
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.
[Emarsys.predict trackCategoryViewWithCategoryPath:<categoryPath: NSString>];
Emarsys.predict.trackCategoryView(<categoryPath: String>)
To report search terms entered by the contact use trackSearchTerm
method.
[Emarsys.predict trackSearchWithSearchTerm:<searchTerm: NSString>];
Emarsys.predict.trackSearch(<searchTerm: String>)
To track custom tags, use the trackTag
method, where the eventName
parameter is required, but the attributes
is optional.
[Emarsys.predict trackTag:<tag: NSString>
withAttributes:<attributes: NSDictionary<NSString, NSString>];
Emarsys.predict.trackTag(<tag: String>, <attributes: [String: String]?>)
With the Emarsys SDK you can ask for product recommendations
based on different recommendation logics
.
Note
recommendProducts
is also going to track thevalue
attached to thelogic
on the backend, so no additional tracking needed when using recommendations!
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
Note
For more information of the recommender logics, please visit [the official documentation].(https://help.emarsys.com/hc/en-us/articles/115004662189-Web-Recommender-logics "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.
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 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 further information please check the Predict documentation
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 it's value is 5
.
This is a required parameter of the recommendProducts
method.
The SDK is going to retrieve recommended products
via it's productsBlock
[Emarsys.predict recommendProductsWithLogic:[EMSLogic searchWithSearchTerm:@"shirt"]
filters:@[[EMSRecommendationFilter excludeFilterWithField:@"category"
isValue:@"women"]]
limit:@10
productsBlock:^(NSArray<EMSProduct *> *products, NSError *error) {
if (products) {
for (EMSProduct *product in products) {
NSLog([product description]);
}
} else {
NSLog(error.localizedDescription);
}
}];
Emarsys.predict.recommendProducts(logic: EMSLogic.search(searchTerm: "shirt"), filters: [EMSRecommendationFilter.excludeFilter(withField: "category", isValue: "women")], limit: 10) { products, error in
if let products = products {
for product in products {
print("\(product)")
}
} else if let error = error {
print("\(error.localizedDescription)")
}
}
This is an optional parameter of the recommendProducts
method.
You can presonalize 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
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
.
[Emarsys.predict trackRecommendationClick:<product: EMSProduct>];
Emarsys.predict.trackRecommendationClick(<product: EMSProduct>)
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.
Note
Please check our DeepLink page for more information.
In order to track email link clicks that open the application directly with the Emarsys SDK, you need to call trackDeepLink
in your AppDelegate's application:continueUserActivity:restorationHandler:
method.
- (BOOL)application:(UIApplication *)application
continueUserActivity:(NSUserActivity *)userActivity
restorationHandler:(void (^)(NSArray *__nullable restorableObjects))restorationHandler {
return [Emarsys trackDeepLinkWith:userActivity sourceHandler:^(NSString *source) {
NSLog([NSString stringWithFormat:@"Source url: %@", source]);
}];
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
return Emarsys.trackDeepLink(userActivity: userActivity, sourceHandler: { url in
if let source = url {
print(source)
}
})
}
The (BOOL) return value of Emarsys.trackDeepLink indicates whether the UserActivity contained a Mobile Engage email deep link and whether it was handled by the SDK.
The first parameter is the UserActivity that comes from the AppDelegate’s application:continueUserActivity:restorationHandler:
method.
The second parameter is optional, it is a closure/block that provides the source Url that was extracted from the UserActivity.
For more information, read the relevant iOS documentation.
Emarsys SDK provides a solution for applicationCode and merchantId change in a convenient way without restarting the SDK. Please check our Config page for more information.
User centric inbox solution. Emarsys SDK provides a Message
named model class to make MessageInbox
information easily accessable.
@property(nonatomic, strong) NSString *id;
@property(nonatomic, strong) NSString *campaignId;
@property(nonatomic, strong, nullable) NSString *collapseId;
@property(nonatomic, strong) NSString *title;
@property(nonatomic, strong) NSString *body;
@property(nonatomic, strong, nullable) NSString *imageUrl;
@property(nonatomic, strong) NSNumber *receivedAt;
@property(nonatomic, strong, nullable) NSNumber *updatedAt;
@property(nonatomic, strong, nullable) NSNumber *expiresAt;
@property(nonatomic, strong, nullable) NSArray<NSString *> *tags;
@property(nonatomic, strong, nullable) NSDictionary<NSString *, NSString *> *properties;
@property(nonatomic, strong, nullable) NSArray<id<EMSActionModelProtocol>> *actions;
The following action types are supported:
- App event action
@interface EMSAppEventActionModel : NSObject <EMSActionModelProtocol>
@property(nonatomic, readonly) NSString *id;
@property(nonatomic, readonly) NSString *title;
@property(nonatomic, readonly) NSString *type;
@property(nonatomic, readonly) NSString *name;
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, id> *payload;
@end
- Custom event action
@interface EMSCustomEventActionModel : NSObject <EMSActionModelProtocol>
@property(nonatomic, readonly) NSString *id;
@property(nonatomic, readonly) NSString *title;
@property(nonatomic, readonly) NSString *type;
@property(nonatomic, readonly) NSString *name;
@property(nonatomic, readonly, nullable) NSDictionary<NSString *, id> *payload;
@end
- Open External URL action
@interface EMSOpenExternalUrlActionModel : NSObject <EMSActionModelProtocol>
@property(nonatomic, readonly) NSString *id;
@property(nonatomic, readonly) NSString *title;
@property(nonatomic, readonly) NSString *type;
@property(nonatomic, readonly) NSURL *url;
@end
The description of the supported actions are available here.
In order to receive the messageInbox content, you can use the fetchMessages
method.
[Emarsys.messageInbox fetchMessagesWithResultBlock:^(EMSInboxResult *inboxResult, NSError *error) {
if (error) {
NSLog(error);
} else {
NSLog(inboxResult.messages);
}
}];
Emarsys.messageInbox.fetchMessages { inboxResult, error in
if let error = error {
print(error as Any)
} else if let inboxResult = inboxResult {
print("Messages: \(inboxResult.messages)")
}
}
To label a message with a tag, you can use addTag
method. (for example: "READ", "SEEN" etc)
[Emarsys.messageInbox addTag:<tag: String>
forMessage:<messageId: String>
completionBlock:^(NSError *error) {
if (error) {
NSLog(error);
}
}];
Emarsys.messageInbox.addTag(<tag: String>, <messageId: String>) { error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
To remove a label from a message, you can use removeTag
method.
[Emarsys.messageInbox removeTag:<tag: String>
fromMessage:<messageId: String>
completionBlock:^(NSError *error) {
if (error) {
NSLog(error);
}
}];
Emarsys.messageInbox.remove(<tag: String>, <messageId: String>) { error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
Note
The Geofence feature is still in pilot phase, please only use it if you have a pilot service order in place! If you need help with piloting, please contact your CSM @ Emarsys.
Geofence makes it available to trigger certain actions based on the users 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.
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.
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 to use at least 50m of radius, to ensure that the triggers happen. Based on the Apple documentation only 20 geofences/app can be used, so please be aware that our current geofencing solution is only works well when there is no other geofencing solution used in the application.
For the location permissions the applications Info.plist must be extended with the following keys:
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>AlwaysUsage is a must have for region monitoring (or some description of your choice)</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>AlwaysUsage is a must have for region monitoring (or some description of your choice)</string>
Make sure that your app is requesting the required permissions from the user. To make it easier, you can call our requestAlwaysAuthorization
method.
The enable
method is responsible for the activation of this feature
[Emarsys.geofence enableWithcompletionBlock:^(NSError *error) {
if (error) {
NSLog(error);
}
}];
Emarsys.geofence.enable { error in
if let error = error {
print("Error: \(error.localizedDescription)")
}
}
The disable
method is responsible for disabling this feature
[Emarsys.geofence disable];
Emarsys.geofence.disable()
The isEnabled
method returns if the geofencing is currently enabled or not
[Emarsys.geofence isEnabled];
Emarsys.geofence.isEnabled()
In order to react to an event triggered by a geofence, you can register for it using the setEventHandler
method.
The eventHandler is a block/closure for a Geofence event.
[Emarsys.geofence setEventHandler:<eventHandler: id<EMSEventHandlerBlock>>];
Emarsys.geofence.eventHandler = <eventHandler: EMSEventHandlerBlock>
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 requestAlwaysAuthorization];
Emarsys.geofence.requestAlwaysAuthorization()
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
Emarsys.geofence.initialEnterTriggerEnabled = YES;
Emarsys.geofence.initialEnterTriggerEnabled = true
You can access the registered geofences from the device with registeredGeofences
.
NSArray<EMSGeofence *> *registeredGeofences = Emarsys.geofence.registeredGeofences;
let registeredGeofences = Emarsys.geofence.registeredGeofences
Emarsys SDK supports a new way of creating actions in the applications by tracking a customEvent, this trigger happens in a silent way
, no in-app or push is needed. All of the action types known from rich push messages are supported.
For this to work an eventHandler should be set up in the SDK.
[Emarsys.onEventAction setEventHandler:id<EMSEventHandlerBlock>];
Emarsys.onEventAction.eventHandler = <eventHandler: EMSEventHandlerBlock>