iOS Integration

Why use EMMA SDK in your APP?

Download and basic integration

Acquisition Integration

Behavior Integration

Push Notifications Integration

Messaging Integration

Add Rate Alert

Debugging your code

Deploying your App to Appstore


Why use EMMA SDK in your App?

EMMA SDK offers an unique functionality with the whole user tracking of your App. We have developed a robust, secure and light SDK with more than 2.000 Millions of installs until the day. And, of course, easy to be integrated.

EMMA can track the install origin (including Facebook, Twitter & Google), sessions, user events, location, ... with a powerful segmentation unit to evaluate the ROI and your user retention engaging them thanks to our communication tools, Push and In-app Messaging.

EMMA iOS SDK is compatible with all devices (iPhone, iPod, iPad) with iOS 8 or over.


Download and basic integration 

Download EMMA iOS SDK 

See Changelog

Download through CocoaPods.

You can get the last EMMA version through CocoaPods. For that:

  1. Install CocoaPods using
    gem install cocoapods
  2. If it is the first time using you can optionally execute
    pod setup
    to download the repository with all “specs" and check them in a local environment. This will directly create a copy of the repository in GitHub.
  3. Create a file in your Xcode project called
    Just next add the line
    pod 'eMMa'
  4. Finally, run
    pod install
    in your Xcode project directory.

    One it is done, CocoaPods should download and install the EMMA library and create a new file .xcworkspace. Finally, open this workspace in Xcode.

Manually download

You can get latest EMMA version here. Once download you need add it to your Xcode project.

In Xcode, go to General >> Embedded Binaries >> Click + to add a new binary.

Click Add Other and add EMMA_iOS.framework to your project.

In Xcode, go to General >> Linked Frameworks and Libraries >> Click + to add a new library.

Click Add Other and add the EMMA_iOS.framework

Select Status of EMMA_iOS.framework as Optional.



Including SDK in your App (Mandatory)

  • SDK & Install (Minimum requirement to track) 

This guide allows you to track organic and non-organic installs of your App.

Add following files and parameters to your app:

  • Add the following frameworks to your project:
    • CoreLocation.framework
    • AdSupport.framework
    • iAd.framework

If you are having problems executing this lib you should delete all weak-links from your libraries. Also in Other Linker Flags, set up these options -ObjC - all_load:




Running the SDK & Install Event (Minimum Requirement)

NOTE: This is the minimum requirement to start tracking your App installs.

Add EMMA to your Application Delegate.

#import <EMMA_iOS/EMMA.h>

In your Application Delegate add the following code to the theapplicationdidFinishLaunchingWithOptions:

[EMMA startSession:@"YOURSESSIONKEY"];

You can obtain your SessionKey by adding your app in My Account following these instructions.


In some cases, It is necessary to change the API EMMA URL (e.g proxies), this requires add the next method before startSession:

[EMMA setWebServiceURL:@""];


Update to version 4.5

The previous versions updated to version 4.5 must take into account the following changes.

Changes in Events

The following methods are deprecated in version 4.4 and removed in 4.5:

+(void) trackEvent:(NSString*)token 
+(void) trackEvent:(NSString *)token withAttributes: (NSDictionary*) attributtes
+(void) trackEventWithRequest:(EMMAEventRequest *) request

Both are replaced by the following method:

+(void) trackEvent:(EMMAEventRequest *) request

Example of use:

EMMAEventRequest *eventRequest = [[EMMAEventRequest alloc] initWithToken:@"<token>"];
//Optional: custom attributes
[eventRequest setAttributes: attributes];
//Optional: request status delegate
[eventRequest setRequestDelegate: requestDelegate];
//Optional: custom id for request delegate
[eventRequest setCustomId: customId];

[EMMA trackEvent:eventRequest];

Changes in InApp

The following methods are deprecated:

+(void) inAppMessage:(InAppType)type andRequest:(EMMAInAppRequest*) request
+(void) inAppMessage:(InAppType)type andRequest:(EMMAInAppRequest*) request withDelegate:(id) delegate

Both are replaced by the following methods:

+(void) inAppMessage:(EMMAInAppRequest*) request
+(void) inAppMessage:(EMMAInAppRequest*) request withDelegate (id) delegate

Example of use:

EMMAInAppRequest * inAppRequest = 
[[EMMAInAppRequest alloc] initWithType:Startview];
//Optional: custom attributes
[inAppRequest setAttributes: attributes];
//Optional: request status delegate
[inAppRequest setRequestDelegate: requestDelegate];
//Optional: cumtom id for request delegate
[inAppRequest setCustomId: customId];

[EMMA inAppMessage:inAppRequest];


If the message is to request a Native Ad it is mandatory to use EMMANativeAdRequest (subclass of EMMAInAppRequest) to add the templateId and its specific delegate.

Changes in Push

In this new version, improvements have been made in the notifications.

The following methods are deprecated:

+(void) startPushSystem: (NSDictionary*) launchOptions
+(void) startSession:(NSString*)appKey withOptions:(NSDictionary*)launchOptions 

Due to improvements in the SDK by simply adding delegates Push as explained in section Push Notifications you need not notify the launchOptions the SDK.


Acquisition Integration

In the Acquisition section you can have the data of all the campaigns managed with EMMA.

Here is the specific documentation so you can manage your Twitter campaigns and also the documentation about how to integrate the functionality of Powlink.


Tracking Twitter App Promotion

EMMA is 100% integrated with Twitter for tracking via AppsFlyer. You will be able to track all the App Installs sources in our Dashboard with no need to integrate Facebook or Twitter SDKs.

Add the following: (available here)

  • AppsFlyerTracker.h
  • libAppsFlyerLib.a

If your project includes CocoaPods you can integrate AppsFlyer in the following way:

pod ‘AppsFlyerFramework’ 

To initialize on the application please add the following code to yourdidFinishLaunchingWithOptions function:

[AppsFlyerTracker sharedTracker].appsFlyerDevKey = @"EMMASOCIALKEY";
[AppsFlyerTracker sharedTracker].appleAppID = @"Your_iTunes_APP_ID";

Add the following code to your AppDelegate.m file atapplicationDidBecomeActive function:

[[AppsFlyerTracker sharedTracker] trackAppLaunch];

The EMMA Social Key you have to introduce is the ID to follow the Twitter campaigns.

To get the EMMA Social Key you have to follow these steps:

1.  LoginEMMA website and go to My Account > Configuration > Edit app.


2.  Go to Media Source Settings and fill the App information:



To get the App Store ID you can copy the ID of the AppStore link, like this example:


To get Google Play ID you can copy the ID of the GooglePlay link, like this example:


3.  Select the Submit option to keep the changes.

4.  Send us an email to and we will send you the EMMA Social Key. You will receive an e-mail with your key.

5.  If everything is set up correctly, you will find the Twitter campaigns in the Acquisition > AppTracker. Once you start to run the campaigns, the data will automatically enter in EMMA.



Powlink Integration

To support the Powlink in iOS, first of all, it is necessary to set up in the EMMA Dashboard the subdomain in that your App will use, and you have to fill the Apple Store Bundle ID and the Apple Team ID. You can configure this in My Account, in the option of the Media Source Settings.


Next, you have to create a Provisioning Profile to your App, in your Apple's Developer Center. You must activate the Associated Domains for your App, download the Provisioning Profile and install it in Xcode.

Once you know your Powlinks subdomain, in the Xcode proyect of your App, you have to select the target and in the Capabilities section you have to activate the Associated Domains option.


When you activate this option, Xcode will let you choose an Apple Team ID, and when you choose it, you will can add the domains that your app will run. You must add the subdomain that you configure in the EMMA dashboard, preceded of "applinks:"


Now you only have to manage the Powlink inside your App, and to do that you have to implement the method application:continueUserActivity:restorationHandler: in your AppDelegate. If you process the paths of the received Powlinks, you can launch several sections of your App.

-(BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * restorableObjects))restorationHandler{
    if ([userActivity.activityType isEqualToString: NSUserActivityTypeBrowsingWeb]) {
        NSURL *url = userActivity.webpageURL;
[EMMA handleLink: url];
        //Process url. Manage Powlink path
    return YES;


If you are using a AppTracker with a custom domain (not EMMA default domain: or, it's necessary add the domain at start the library:

 EMMAConfiguration *configuration = [EMMAConfiguration new];
configuration.customPowlinkDomains = [NSArray arrayWithObjects: @"<custom_domain>"];
configuration.customShortPowlinkDomains = [NSArray arrayWithObjects: @"<custom_domain>"];
[EMMA startSession:configuration];


[EMMA startSession:@"<session_key>"];
[EMMA setPowlinkDomains:[NSArray arrayWithObjects: @"<custom_domain>"]]
[EMMA setShortPowlinkDomains:[NSArray arrayWithObjects: @"<custom_domain>"]]


Behavior Integration

With EMMA you can do a complete integration of the SDK that allows you to know the location of your users, how they register in your App, how many transactions they do and even their own characteristics. This is all the information of your users that you will get in the Behavior section.

The following articles specify the integration of the measurement of each of these aspects:


Tracking Events

In the EMMA platform you have the option to measure between two types of events. Those that the platform includes by default and the Custom events that you want to integrate according to the structure of your application.

Default events

The EMMA default events allow you to know the Leads (registered users outside the app, old registers and any tags that you want to link to a user in order to be able to create custom segments) and the Login (users that have logged in the App through an existing mail or through some social platform).

Follow these steps to do this integration:

Sign Up/Register/Leads

[EMMA registerUser:USER_ID forMail:MAIL]

RegisterUser measure a complete register of a device in the EMMA data base to an user_id (NSString) and an email (NSString)


[EMMA loginUser:USER_ID forMail:MAIL]

LoginUser collects the user data in the EMMA database to an user_id (NSString) and an email (NSString). When the user logs in, you can use [eMMa loginDefault] to collect another user Sign In with the same data.

Custom events

With EMMA you can measure every user action like a custom event:

EMMAEventRequest *eventRequest = [[EMMAEventRequest alloc] initWithToken:@"<token>"];
//Optional: custom attributes
[eventRequest setAttributes: attributes];
//Optional: request status delegate
[eventRequest setRequestDelegate: requestDelegate];
//Optional: cumtom id for request delegate
[eventRequest setCustomId: customId];

[EMMA trackEventWithRequest:eventRequest];

Use trackEvent to count the number of times that certain events happen during an App session.

This information can be useful for measuring how often users perform different actions, for example. Your application is currently limited to counting occurrences for 30 different event ids.

You can obtain the event tokens in the EMMA platform. If an non-existing token is sent, EMMA will return an error.

For event requests a delegate can be added to show the status of the request and if it returns data (eg a rule) or not. To add the delegate:

@interface CustomViewController : UIViewController<EMMARequestDelegate>
@implementation CustomViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    EMMAEventRequest * eventRequest = [[EMMAEventRequest alloc] initWithToken:@"<token>"];
    //Optional [eventRequest setCustomId:@"custom Id"];
    [eventRequest setRequestDelegate: self];
    [EMMA trackEventWithRequest: eventRequest];

-(void) onStarted(NSString* id) {

-(void)  onSuccess(NSString* id, BOOL containsData) {

-(void) onFailed(NSString* id) {

Tracking purchases

EMMA allows you to track every purchase of your App.

Start Order

[EMMA startOrder:YOUR_ORDER_ID customerId:CUSTOMER_ID totalPrice:TOTAL_PRICE coupon:COUPON extras:EXTRAS currencyCode:CURRENCY_CODE]

Starts an order for adding products. You can pass the following parameters:


: NSString with your order id


: NSString with your Customer ID. If not passed, EMMA will use the logged one (if exists).


: Float with your total price.


: NSString with your coupon if needed.


: NSDictionary with until 20 extra parameters, category… Each extra parameter can be used later to filter in EMMA.


: NSString of a valid Currency Code (EUR,USD,..) If the currency code is not valid EUR currency will be taken

You can use abbreviated methods if you don’t need all parameters, you can find them at the end of the document or in EMMA.h.


Add Products to the order


Adds products to your current started order. Always startOrder should be called before. You can pass the following parameters: You can pass the following parameters:


: NSString with your product id.


: NSString with your product name.


: Float with your product qty.


: Float with product price.


: NSDictionary with until 20 extra parameters, like currendy, category, …


Track Order

[EMMA trackOrder]

Track the current order. It should be called after startOrder and after being all cart products added.

The sequence of tracking order in EMMA is always startOrder>addProduct(*distinct products)>trackOrder


Cancel Order

[EMMA cancelOrder:ORDER_ID]

Cancel the order referenced by an order id. If your e-commerce allows canceling orders this method updates the purchases data with the cancelled orders.


Tracking User Tags


This method updated or includes extra parameters in order to obtain a better segmentation to the Users with tag filter. It can be used in the register, in the login or in any app section where is the user information.

If you want to use the EMMA RULE On his Birthday you have to send the birthday date with the tag method in this format:




Remember to check the SDK logs to see the list of TAGS that can't be used because they are reserved for the EMMA system.


Tracking location

If your app has the permission required you can track the location of each device using the next code:

[EMMA trackLocation];


Get User Info

Get User ID

[EMMA getUserID:^(id result) {
NSLog(@"ID:%@",result); // Your code

This method gives back the EMMA ID like a NSString. This ID is unique for each user and it can be used to do the segmentation to send communications.

Get User Info

[EMMA getUserInfo:^(id result) {
NSLog(@"Info:%@",result); // Your code


The data that the call returns is obtained from the information that the SDK collects. On a first boot it may take a few seconds to gather the information, if the call is made right after the startSession it could return nil

This method returns all the user information in a JSON format. The JSON includes the following parameters, all of them in NSDictionary format with all the NSString values:

id  The same unique ID that appears in the method (getUserID)
udid  Unique ID for app install (usually IDFA/AAID)
emma_build  Identify the EMMA SDK version used
email  User email if the register or the login are integrated
customerid ID assigned tho the user after he does the register or the login
device  Device of the user
app_version  Version of app.
os_version  Version of the operating system
os_build  Operating system build
token  Push token
latitude Latitude of the user in case the geolocation is allowed and measured.
longitude Longitude of the user in case the geolocation is allowed and measured.
emma_carrier  Telephone operator.
emma_connection  Conexion type (wifi or 3g)
emma_city City of the user in case the geolocation is allowed and measured
emma_country Country of the user in case the geolocation is allowed and measured
emma_state State of the user in case the geolocation is allowed and measured
emma_accept_language   Lenguaje establecido en la app
emma_timezone_name  Device timezone
{tagX....tagY} User tags that are tracked in the trackExtraUserInfo request

If you want to use this method, it is necessary to contract the Raw Export feature.


Installation attribution information

Through the method explained below, we will be able to obtain the data of the attribution of the install of each user, being able to obtain the following information:

  • Status {String}: It returns the state of the attribution. This can have a few types:
    • pending: The install is still pending attribution. This is due to the attribution window, maximum 2 days).
    • campaign: Means that the install has been assigned to a specific campaign, source and provider.
    • organic: The install has been organic. If the attribution is organic, it means that the install will not be linked to a campaign and therefore the campaign will be null.
  • Id of the campaign {Number}
  • Name of the campaign {String}
  • Source ID {Number}
  • Name of the font {String}
  • Provider ID {Number}
  • Provider name {String}

In order to obtain this information about the attribution of the install, it is necessary to add the following method:

@interface CustomViewController: UIViewController<EMMAInstallAttributionDelegate>
@implementation CustomViewController

- (void)viewDidLoad { [super viewDidLoad]; [EMMA installAttributionInfo:self]; } -(void) onAttributionReceived:(EMMAInstallAttribution*) attribution { EMMAInstallAttribution attr = attribution;
if (attribution) { // process attribution } }


Push Notifications Integration

NOTE: To differentiate a notification from our push system to other systems, the payload sent by EMMA contains a flag called "eMMa".

EMMA allows you to add a very powerful Push system easy to integrate. The platform also allows you to send info through Push Notifications and do whatever you want inside your app with it.

In order the Push Notifications work correctly in your app, you must integrate the following steps:


Push Auth Key

The Apple APNs Auth Key is a certificate type (.p8) that replaced its predecessors, the production APNs certificate and the development APNs certificate. From EMMA we recommend the use of this certificate for the following reasons:

  • Unify the development and production certificate in a single certificate.
  • It is a certificate that does not have to be renewed every year.
  • A single certificate is valid for all apps in the Apple account.

For the use of this certificate it is necessary:

  • The .p8 certificate downloaded from the Apple Developers panel.
  • The ID bundle of the application that has to receive the notifications..
  • The team ID of the Apple account.

o obtain the certificate you have to visit the account of Apple Developers


We click on the section of Certificates, IDs and Profiles.


Once in Apple, we click on the Keys section and add a key.


We add the name, we select the APNs check and we give to continue.


We confirm and download the .p8 file that generates.


We add the file (.p8), the team ID and the bundle ID in EMMA -> My Account


When adding the certificate it is necessary to enter the team ID to make the validation with Apple of the same. Below in the "Media source settings" section we will add the bundle ID and the team ID to be used in sending the notifications.

To obtain the ID and team ID bundle, it can be done in the following way. The ID is equivalent to the bundle ID and the prefix is ​​equivalent to the team ID.



Using EMMA Push Notifications

Once you upload your iOS Certificates, you can start to integrate the Push Notifications:

[EMMA startPushSystem]

Starts push system from


: NSDictionary received from DidFinishLaunching

You can set the Push options with the following methods:

[EMMA setPushSystemDelegate:YOUR_DELEGATE]

: NSObject that will obtain push info sent through EMMA dashboard. It's mandatory only if you want to do extra stuff in your app depending on the Push received.

[EMMA setPushSystemOptions:(eMMaPushSystemOptions)options]

: eMMaPushSystemDisableAlert -> Disables showing alert messages for new Push Notifications received.

To add notification methods (iOS 10 only) we have to implement the UserNotifications framework delegate:


import UserNotifications 

class AppDelegate: UIResponder, UIApplicationDelegate,UNUserNotificationCenterDelegate {


#import <UserNotifications/UserNotifications.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate,UNUserNotificationCenterDelegate>

To add the delegate to the SDK:




 [EMMA setPushNotificationsDelegate:self];

It is also necessary to add this methods in your AppDelegate:


func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
func application(_ application: UIApplication, didRegister notificationSettings: UIUserNotificationSettings) {
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
	NSLog("Error registering notifications " + error.localizedDescription);
@available(iOS 10.0, *)
func userNotificationCenter(_ center: UNUserNotificationCenter,  willPresent notification: UNNotification, withCompletionHandler   completionHandler: @escaping (_ options:   UNNotificationPresentationOptions) -> Void) {
completionHandler([.badge, .sound]) } @available(iOS 10.0, *) func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { EMMA.handlePush(response.notification.request.content.userInfo)
completionHandler() }


 -(void) application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    [EMMA registerToken:deviceToken];

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{
    [EMMA handlePush:userInfo];

- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
    //register to receive notifications
    [application registerForRemoteNotifications];

-(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
    NSLog(@"Error: %@", error);

#ifdef __IPHONE_10_0
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
    [EMMA handlePush:notification.request.content.userInfo];
completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionBadge); } -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{ [EMMA handlePush:response.notification.request.content.userInfo];
completionHandler(); } #endif

iOS 10 changes

For registering token is necessary enable Push Notifications in Capabilities.


Push Tag

[EMMA checkPushTag:(NSString *)pushTag withBlock:(EMMAPushTagBlock)block]

EMMAPushTagBlock definition

typedef void(^EMMAPushTagBlock)(NSString* pushTag, NSString* pushTagID);


[EMMA checkPushTag:@"Account" withBlock:^(NSString *pushTag, NSString *pushTagID) {
//Redirects to Accounts tab
[self performSegueWithIdentifier:@"AccountSegue" sender:self];

By the other hand, you now can keep track of all messages sent by Push and show them in a custom alert or more than once. In order to do so you need to add this method in your delegate specified on eMMaPush Message.

Push Message

//Do whatever you want with pushMessage

You can use abbreviated methods if you don’t need all parameters, you can find them in EMMA.h.

Rich Push, custom sounds in push notifications

To use custom sounds in notifications you send with EMMA, you need to add your custom sounds in .caf format into the main bundle or into Library/Sounds/ of your app. Remember use the same name for sound files in iOS and Android.

Rich Push URL using DeepLinking

You can redirect your push notification openings to a section into your app. For that you can use a structure like this:


In order to make your app available to receive a scheme deep link:

1) Go to Xcode > App Target > Info > URL Types and put your custom scheme.


 2) Add this method to your AppDelegate.m file:

-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation: (id)annotation{ 
[EMMA handleLink:url];
//Manage by url
return YES;


Add the handleLink method for internal EMMA managements. For example to run Re-Engagement campaigns.


iOS Rich Push Notification

iOS 10 has introduced Rich Push Notifications, which allow you to add image, video, audio or gif attachments to your push notifications.

Rich Push Notifications are enabled via a Notification Service Extension, a separate and distinct binary embedded in your app bundle. Prior to displaying a new push notification, the system will call your Notification Service Extension to allow you to modify the payload as well as add media attachments to be displayed.

Create Notification Service Extension

To create a Notification Service Extension in your project, in Xcode, select File -> New -> Target and choose the Notification Service Extension template.



You can name the extension as you wish: we will name it RichPushExtension for this tutorial. Make sure you embed your new extension in your app!



When you press Finish you will be asked to activate the extension, click Activate to finish.



At the end of this step, three new files will be created under the extension name directory (RichPushExtension in our case): NotificationService.h, NotificationService.m and Info.plist.


Then make sure that the Push Notifications Capability is enabled for the Notification Service Extension created. Select your new extension (RichPushExtension), select Capabilities and turn on Push Notifications.



Code Changes

Open NotificationService.m. Remove all code from the editor and copy-paste the code below:

Objective C

#import "NotificationService.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;


@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    // Check for rich attachment
    NSDictionary *userInfo = [self.bestAttemptContent userInfo];
    if (userInfo == nil) {
        [self taskComplete];
    NSString *urlImagePush = [userInfo objectForKey:@"media-attachment"];
    if (urlImagePush == nil) {
        [self taskComplete];
    NSString *typeImage = [self fileExtensionForMediaUrl:urlImagePush];
    if (typeImage == nil) {
        [self taskComplete];
    // load the attachment
    [self loadAttachmentForUrlString:urlImagePush
                   completionHandler:^(UNNotificationAttachment *attachment) {
                       if (attachment) {
                           self.bestAttemptContent.attachments = [NSArray arrayWithObject:attachment];
                       [self taskComplete];

- (void)serviceExtensionTimeWillExpire {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    [self taskComplete];

- (void)taskComplete {

- (void)loadAttachmentForUrlString:(NSString *)urlString withType:(NSString *)type
                 completionHandler:(void(^)(UNNotificationAttachment *))completionHandler  {

    __block UNNotificationAttachment *attachment = nil;
    NSURL *attachmentURL = [NSURL URLWithString:urlString];
    NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
    [[session downloadTaskWithURL:attachmentURL
                completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
                    if (error != nil) {
                        NSLog(@"NSE ERROR. %@", error.localizedDescription);
                    } else {
                        NSFileManager *fileManager = [NSFileManager defaultManager];
                        NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:type]];
                        [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];
                        NSError *attachmentError = nil;
                        attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
                        if (attachmentError) {
                            NSLog(@"NSE ERROR. %@", attachmentError.localizedDescription);
                }] resume];

- (NSString *)fileExtensionForMediaUrl:(NSString *)url {
    NSString *ext = nil;
    //EMMA always send pngs without extension in filename
    if ([url rangeOfString:@""].location != NSNotFound) {
        ext = @"png";
    } else if ([url rangeOfString:@"jpg"].location != NSNotFound) {
        ext = @"jpg";
    } else if ([url rangeOfString:@"jpeg"].location != NSNotFound) {
        ext = @"jpg";
    } else if ([url rangeOfString:@"png"].location != NSNotFound) {
        ext = @"png";
    } else if ([url rangeOfString:@"gif"].location != NSNotFound) {
        ext = @"gif";
    if (ext != nil) {
        ext = [@"." stringByAppendingString:ext];
    return ext;



import UIKit
import UserNotifications

private func fileExtensionForMediaUrl(url: String) -> String? {
    var ext:String? = nil
    if url.contains("") || url.contains("png") {
        ext = "png"
    } else if url.contains("jpg") || url.contains("jpeg") {
        ext = "jpg"
    } else if url.contains("gif") {
        ext = "gif"
    if let ext = ext {
        return ("." + ext)
    return ext

private func resourceURL(forUrlString urlString: String) -> URL? {
    return URL(string: urlString)

fileprivate func loadAttachment(forMediaType mediaType: String, withUrlString urlString: String, completionHandler: @escaping ((UNNotificationAttachment?) -> Void)) {
    guard let url = resourceURL(forUrlString: urlString) else {

    let session = URLSession(configuration: URLSessionConfiguration.default)
    session.downloadTask(with: url) { (temporaryFileLocation, response, error) in
        if error == nil {
            let fileManager = FileManager.default
            guard let temporaryFileLocation = temporaryFileLocation else {
            let localURL = URL(fileURLWithPath: temporaryFileLocation.path + mediaType)
            do {
                try fileManager.moveItem(at: temporaryFileLocation, to: localURL)
                let attachment:UNNotificationAttachment = try UNNotificationAttachment.init(identifier: "", url: localURL, options: nil)
            } catch {
    } .resume()

class NotificationService: UNNotificationServiceExtension {
    var contentHandler: ((UNNotificationContent) -> Void)?
    var bestAttemptContent: UNMutableNotificationContent?
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.contentHandler = contentHandler
        bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        if let bestAttemptContent = bestAttemptContent {
            let userInfo = bestAttemptContent.userInfo
            guard let url = userInfo["media-attachment"] as? String
                else {
            var type: String? = nil
            if let _type = userInfo["media-type"]  as? String {
                type = _type
            } else {
                type = fileExtensionForMediaUrl(url: url)
            if type == nil {
            loadAttachment(forMediaType: type! , withUrlString: url, completionHandler: { attachment in
                if let attachment = attachment {
                    bestAttemptContent.attachments = [attachment]
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {


Messaging Integration

Messaging includes seven different communicative formats that you can integrate to impact your users:

In many of these communicative formats you can delete the redirection url's that you want to introduce. With the EMMA Whitelist functionality you can define what content you want to be displayed in the scheduled webviews.

Review Campaign

[EMMA inAppMessage: (InAppType) type andRequest:(EMMAInAppRequest *) request];

Use inAppMessage to confirm whether the Campaign created on the EMMA platform corresponding to the specified Type is displayed.

The following attributes can be defined in EMMAInAppRequest:

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.nateiveAdTemplateId = @"nativeAdTemplateId";
request.label = @"label";
request.inAppMessageId = @"inAppMessageId";

*The following steps will specify the attributes to be used for each type of campaign

Campaign with tag

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.label = @"label";
[EMMA inAppMessage: AdBall andRequest: request];

If you wish you can pass a custom String that will tag the Campaign in case you use more than one Campaign of the same type in your app and you need to distinguish them.

Add interface

[EMMA addInAppDelegate:(id<EMMAInAppMessageDeletage>) delegate];
EMMAInAppRequest* request = [EMMAInAppRequest new];
request.label = @"label";
[EMMA inAppMessage: AdBall andRequest: request];

If you wish you can add an interface (or several) to receive the different events related to the Campaigns of your app.

Using EMMA Banner

EMMA Banner lets you show a banner on your app with promotional info. The banner will be shown and hidden depending on your dashboard configuration. It is a communication that allows the user to display an external webview with HTML content or redirect to another application tab (via deeplink)


To display the Banners in your app you need at least to integrate the first method described below:

IMPORTANT: It is recommended to be called inside.


Check Banner

[EMMA inAppMessage: Banner andRequest: nil];

Use checkForBanner in order to check if show Banners added on EMMA dashboard. YOUR_VIEWCONTROLLER is your top view controller where you decide how you want to show your ViewController.

Banner auto Creation

[EMMA setBannerAutoCreation:(BOOL) autoCreation];

Sets the parameter to autocreate the Banner when coming from background, if YES, it will create the Banner when coming from background automatically.

Banner with label

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.label = @"label";
[EMMA inAppMessage: Banner andRequest: request];

Use checkForBanner in order to check if the shown Banner was added on EMMA dashboard. YOUR_VIEWCONTROLLER is your top view controller where do you want to show your ViewController. If you want you can pass a custom NSString that labels the Banner in case you use more than one Banner on your app and you need to distinguish between them. The block is invoked when the banner is displayed or when no banners available.

NOTE: You cannot use autocreation parameter using label because labeled Banner are attached to a specific part of the app, not at the startup.


Using EMMA Startview

EMMA StartView lets you show HTML info on your app startup via a webview.


In order to allow them in your app you need at least to implement the first method.

StartView will be presented in a:


By default, EMMA will use:

[[[UIApplication sharedApplication] keyWindow] rootViewController]

but you can set your own EMMA RootViewController using:


If both are nil, StartView won’t be shown.

Now StartView is implemented by default when starting EMMA Session, but it can be configured with the following methods:

StartView Options


List of options:


Sets the startView in manual mode. Useful for using StartViews with labels. Also disables check for StartView returning from background


Sets the Startview redirection in a browser independently. 

Use this structure in case you want to use the ManualCall and the OpenLinksInSafari at the same time:

[eMMa setStartViewOptions:eMMaStartViewOpenLinksInSafari|eMMaStartViewManualCall]; 



Using EMMA Adball

EMMA AdBall lets you show an AdBall Icon on your app that you can move freely around the app view and also hide it. If you press the AdBall a popup with HTML content will be shown.


In order to allow them in your app you need at least implement the first method. It can be configured with the following methods.

Check AdBall

[EMMA inAppMessage: AdBall andRequest: nil];

Use checkForAdBall in order to check if show AdBalls added on EMMA dashboard.

Check if Adball is showing

[EMMA isAdBallShowing];

Use for check if AdBall is showing on device screen. Return BOOL true if is on screen.


Using EMMA Dynamic Tab

EMMA tabBar View (DynamicTab) allows you to show HTML information in a new section of your app (only in case that you have a TabBar in the app). The new TabBar Item can be created locally or in the EMMA platform.


If it is done in both ways, the dynamic TabBar Item created directly in EMMA will prevail.

To enable this feature in your app you will need to implement at least the first method. It can be configured following this indications:

[EMMA inAppMessage: PromoTab andRequest: nil];

DynamicTab TabController

[EMMA setPromoTabBarController:(UITabBarController*)tabBarController];

Set the UITabBarController where you will find the DynamicTab. If you don't define any UITabBarController, the DynamicTab will not be executed.

Dynamic Tab Index

[EMMA setPromoTabBarIndex:(NSInteger) index];

Set the índex where the DynamicTab will be displayed if it is not defined in EMMA platform.

Dynamic Tab TabBarltem

[EMMA setPromoTabBarItem:(UITabBarItem*) tabBarItem];

Set the UITabBarItem to display it if it is not defined in EMMA platform.

Dynamic Tab AutoCreation

[EMMA setPromoTabBarAutoCreation:(BOOL) autoCreation];

Set the auto-creation parameter of the TabBar when the app is opened from the background. If so, it will automatically create a DynamicTab when the user comes from the background.

New and important

The TabBar ítem index and the item itself can be specified on the EMMA platform. As we indicated before, the configuration in EMMA will always prevail over the local configuration.


Using EMMA Strip

EMMA Strip lets you show a Strip above the status bar with a message for your customers. It can be placed on any screen of the app.


Check Strip

[EMMA inAppMessage: Strip andRequest: nil];

Use checkForStrip in order to check if the shown Strip were added on the EMMA dashboard.

Strip with AutoCreation

[EMMA setStripAutoCreation:(BOOL) autoCreation];

If you want to check Strip automatically in every startup or coming for background you need to pass a TRUE Boolean. By default it is set to no, so you need to decide where and when show Strip.

Strip with label

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.label = @"label";
[EMMA inAppMessage: Strip andRequest: request];

If you want you can pass a custom NSString that labels the Strip in case you use more than one Strip on your app and you need to distinguish between them. NOTE: You cannot use autocreation parameter using label because labeled Strip are attached to a specific part of the app, not at the startup.


You can use a mixture of this methods in order to pass more parameters. See appendix with all EMMA header options.


Using EMMA Coupons

EMMA Coupons allows you to obtain, verify, redeem coupons that are defined and configured in EMMA platform.


Get Coupons

[EMMA addCouponDelegate:(id<EMMACouponDelegate>) delegate]
[EMMA inAppMessage: Coupons andRequest: nil];

With this call, we will get all the information of the coupons available to the user, depending on the conditions that have been set on the EMMA platform.

A list of the existent coupons it will return, listing the automatic coupons first, from newer to older, and then, listing the classic coupons from newer to older too.

In the response block, we will get a dictionary with information about each coupon available to the users. The following information is available for each coupon: id (EMMA internal identifier), code, maximum number of redemptions, number of times traded, title, description, picture …

[EMMA sendImpression: EMMACampaignType.kCampaignCoupon withId: id];
[EMMA sendClick:EMMACampaignType.kCampaignCoupon withId: id];

Details of a Coupon

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.inAppMessageId = @"couponId";
[EMMA inAppMessage: Coupons andRequest: request];

With this call, we will get information of a particular coupon.

The couponId parameter must be the internal coupon identifier of EMMA, ID that can be obtained from a call to checkForCoupons made ​​earlier.

In the response block, we will get a dictionary with the information about the consulted coupon: id (EMMA internal identifier), code, maximum number of redemptions, number of times traded, title, description, picture ...

Check the Coupon validity

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.inAppMessageId = @"couponId";
[EMMA inAppMessage: CouponValidRedeems andRequest: request];

With this call we can check if the user can redeem the coupon indicated.

The couponId parameter must be the EMMA internal identifier of a coupon, ID that can be obtained from a call to checkForCoupons made ​​earlier.

In the response block, we will indicate the number of times that the user can still redeem the coupon.

Redeem a coupon

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.inAppMessageId = @"couponId";
[EMMA inAppMessage: RedeemCoupon andRequest: request];

With this call, the user redeems the coupon indicated.

The couponId parameter must be the EMMA internal identifier of a coupon, ID that can be obtained from a call to Coupons made ​​earlier .

To send the impression and the click on the coupon the following methods must be added in the app, where both actions are performed

Cancel a coupon

EMMAInAppRequest* request = [EMMAInAppRequest new];
request.inAppMessageId = @"couponId";
[EMMA inAppMessage: CancelCoupon andRequest: request];

This call can cancel the redemption of a coupon done before.

The couponId parameter must be the EMMA internal identifier of an identifier coupon that can be obtained from a call to checkForCoupons made ​​earlier.

Optionally, you can specify a count parameter if you want to cancel more than redemption done before. It it's not indicated, the coupon will be canceled.


511 error reports that the redeem could not be completed for some reason. Some possible causes could be the interruption of the connection with the DB or multiple redemptions affected by a capping. In these cases, we recommend to treat this error and warn the end user.


Using EMMA NativeAd

EMMA NativeAd allows you to obtain the information of a NativeAd corresponding to a template that has been defined and configured on the EMMA platform.


Get NativeAd

[EMMA addInAppDelegate:(id<EMMAInAppMessageDelegate>) delegate]
EMMAInAppRequest* request = [EMMAInAppRequest new];
request.nativeAdTemplateId = @"templateId";
[EMMA inAppMessage: NativeAd andRequest: request];

With this call, we will get all the NativeAd information available to the user regarding the templateId, depending on the conditions that have been configured in the EMMA platform.

onReceived:EMMANativeAd* is called if there is a nativeAd that corresponds to the template identifier "templateId".

EMMANativeAd contains all fields configured in EMMA for this NativeAd template, to obtain them the following method will be used:


NSString* title = [nativeAd getField:@"Title"];

Once you have obtained all the required fields, you can already create the view to paint this NativeAd on the screen depending on the design that you want to apply. Once the NativeAd is displayed it is necessary to call this method:

[EMMA sendImpression: NativeAd withId: [NSString stringWithFormat: @"%d", campaign.idpromo]];

Open a NativeAd

[EMMA openNativeAd: [NSString stringWithFormat: @"%d", campaign.idpromo]];

With this call, the content of the link configured in the NativeAd from the EMMA platform will be displayed.

Alternatively, if this method is not used, you can send the click calling the method:

[EMMA sendClick: NativeAd withId: [NSString stringWithFormat: @"%d", campaign.idpromo]];

A new optional method has been added to the EMMAInAppMessageDelegate protocol. The method is the following:

@protocol EMMAInAppMessageDelegate

-(void) onNativeAdBatchReceived:(NSArray<EMMANativeAd*>*) nativeAds;

The protocol has an optional new method appart form the required and optional already established.

For a multiple Native Ad it will be used a subclass from EMMAInAppRequest, EMMANativeAdRequests. At this moment, this template ID parameter was in the EMMAInAppRequest class, now, it will be deprecated in this and it will become a parameter of the EMMANativeAdRequest subclass. It can be used both ways, but the correct way to use it will be in the subclass.

Multiple NativeAd (returns all the available Native Ad for a Template) [Since 4.2.5 iOS SDK version onwoards]

let requestParams = EMMANativeAdRequest()
requestParams.templateId = BATCH_NATIVE_AD_TEMPLATE_1
requestParams.isBatch = true
EMMA.inAppMessage(InAppType.NativeAd, andRequest: requestParams, andDelegate: self)

Unique NativeAd (deprecated)

let requestParams = EMMAInAppRequest()
requestParams.nativeAdTemplateId = NATIVE_AD_TEMPLATE_1 EMMA.addInAppDelegate(self) EMMA.inAppMessage(InAppType.NativeAd, andRequest: requestParams)

Unique NativeAd (returns the most recent Native Ad available from the template)

let requestParams = EMMANativeAdRequest()
EMMA.inAppMessage(InAppType.NativeAd, andRequest: requestParams, andDelegate: self)

Now, you an use the method "inAppMessage" in iOS with delegate:

EMMA.inAppMessage(InAppType.NativeAd, andRequest: requestParams, andDelegate: self)

The difference is that the parameter batch it will have to be set to true in case you want a multiple reception of Native Ad. By default, this value will be false.

Once you have the Native Ad, the EMMANativeAd class will have a new tag field of type string that can be nil or contain the string with tag

 if let tag = nativeAd.tag {...}


EMMA Whitelist

Minim SDK version: 3.1.7 or higher

With this functionality we can limit the urls that will open the EMMA SDK. So, only the content that starts with any of the urls we have indicated in the whitelist will be displayed in the In-App communications webview.  

If we don't indicate any url in the whitelist, any url is allowed. 

This functionality would affect the Push (Rich URL), Banners, StartViews, AdBalls and DynamicTabs.

Communications (Banners, StartViews, AdBalls y DynamicTabs) can load external content to the app through a Webview and for Banners, AdBalls and DynamicTabs could load external images that would also be controlled by the whitelist. 

For a Push with Rich URL, if the url is not in the whitelist, the webview would not open, but the app will equally receive the push. If you use a deeplink instead of a url, the deeplink scheme must be added to the whitelist in order to open it.  

How to use it

Call this method after the starteMMaSession and before you call any method relating to In-App communications. 

[EMMA setWhitelist:(NSArray*)urls];


If my whitelist is

[EMMA setWhitelist:@[@""]; 

Example 1:

We upload to the EMMA dashboard a Banner with Target URL

The Banner will not be displayed, we must add to the wihitelist

Example 2:

We set up in the EMMA dashboard a StartView with StartView URL

The StartView will not be displayed, we must add to the whitelist

Example 3:

We set up in the EMMA dashboard a Banner with Target URL and SmartPhone Banner URL

The Banner will not be displayed, the image url is not in the whitelist, so we must add to the whitelist

Example 4:

We configure in the EMMA dashboard a Banner with Target URL

The Banner will be displayed because the url that we configure in the  Target URL section starts with the same protocol and domain as the url of the whitelist. 

Ejemplo 5:

We configure in the EMMA dashboard a StartView with StartView URL

The StartView will be displayed because the url that we configure in the StartView URL section starts with the same protocol and domain as the url of the whitelist. 


Add Rate Alert

EMMA makes easier to add a Rate alert in order to achieve more positive reviews in an app.

Create Rate Alert

[EMMA addRateAlertForAppStoreURL:APP_STORE_URL]

You can set the following options using the following methods:


: Int specifying hours between alert shows. By default 72 hours.

[EMMA setRateAlertTitle:TITLE]

: NSString that specifies rate alert title. By default “Rate this app”.

[EMMA setRateAlertMessage:MESSAGE]

: NSString that specifies rate alert message. By default: “If you like our app, please rate it on App Store!”

[EMMA setRateAlertCancelButton:CANCEL]

: NSString that specifies rate cancel button title. If pressed the alert will never show again. By default: “No, thanks”

[EMMA setRateAlertLaterButton:LATER]

: NSString that specifies rate later button title. Each time user press Later alert will delay its shown multiplying time frequency per alert seen times. By default: “Later”

[EMMA setRateAlertRateItButton:RATE_IT]

: NSString that specifies rate button. If pressed the alert will never show again. By default: “Rate it now!”

[EMMA setRateAlertShowAfterUpdate:APP_UPDATE]

: Bool that allows Rate alert to show again in case of app update if the user previously has rated the app. (Multiple rates for the same user)

You can use abbreviated methods if you don’t need all parameters, you can find them in EMMA.h.


Debugging your code

This step is optional. If you need to see the EMMA log, enable it (before starteMMaSession) by calling:

[EMMA setDebuggerOutput:TRUE]


Deploying your App to AppStore

Apple has changed its tracking policies on 2014. The new policy affects directly the use of the IDFA tracking (Identifier for advertisers). Apple has stated that IDFA tracking is allowed for the following purposes: frequency capping, conversion events, estimating the number of unique users, security and fraud detection, and debugging.

EMMA gets this identifier in order to know conversion events and unique users estimation, so our IDFA collection is aligned with Apple policy.

In order to follow all Apple rules you need to tick the following boxes on iTunes Connect once uploading your app:


Having checked the previous boxes EMMA will be fully working and allowing you to use POWLINK without breaking any Apple policy.

If you desire to disable the use of IDFA tracking you should check the same boxes in order to prevent Apple complaints. In that case you need to call the following method disabling it the use of the IDFA.

IDFA tracking is enabled by default on EMMA . If you don’t want to track with IDFA please use method [eMMa setUseIDFA:BOOL]; in order to disable. Anyway you need to check the speciefied box on iTunnes Connect question regarding IDFA tracking.


BOOL tells to EMMA when to use IDFA tracking. If NO VendorID will be used. It can be enabled/disabled for future app releases.

Have more questions? Submit a request


Please sign in to leave a comment.