Initial SDK setup

Minimum setup

To get started, you need to perform the following tasks:

This document will cover app setup and the component installation process, as well as basic integration steps for iOS and Android.

SDK Versions

The FollowAnalytics PhoneGap/Cordova SDK was tested on Cordova v6.+ and it includes versions 5.0.2 (iOS) and 5.0.8 (Android) of the FollowAnalytics SDK.

For an example, check out our PhoneGap sample integration code on Github.

Install the SDK

  1. Download the FollowAnalytics SDK from the developer portal.

Windows CI Workflows

If you're using a Microsoft Azure CI server please use the version inside the ci-version folder of the downloaded .zip. This version fixes a problem related to iOS Framework symlinks.

  1. Use the cordova CLI to add the plugin to your app:
    cordova plugin add /path/to/fa-sdk-phonegap-plugin/standard-version

Initialize the SDK

Add the following to your index.js:

onDeviceReady: function() {
    FollowAnalytics.initialize(YOUR_API_KEY);
}

Debug mode

If you want the SDK to be initialized in Debug mode hence being more verbose about the methods called and actions performed, please initialize it as follows:

onDeviceReady: function() {
    FollowAnalytics.initialize(YOUR_API_KEY, true);
}

Remove Debug mode before releasing

Don't forget to remove the debug flag when compiling to the stores in order to reduce logging whithin clients applications.

Register for notifications

iOS

If your app code is already registered to send push notifications, nothing to do here. Otherwise, simply add a call to registerForPush, either from your HTML code whenever you think the moment has come to ask the user for it.

HTML

<a href="#" onclick="FollowAnalytics.registerForPush()">register for push</a>

Android

Build in release mode

The app must be built in release mode in order to receive push notifications

Logging

Data sent in debug mode will not appear on dashboards

When your app runs in DEBUG mode or in a simulator, the data is automatically sent as development logs, and is therefore not processed to be shown on the main UI page. DEBUG logs can be checked using the method given in the FAQ section.

See related entry in FAQ for more information on debug & release modes.

Logging best practices

To ensure your tags are relevant and will end up empowering your team through FollowAnalytics, please read the Logging best practices entry in the FAQ section.

Events vs Attributes

The FollowAnalytics SDK allows you to tag both events and attributes. If you are unsure about the difference, please refer to the corresponding FAQ entry.

Tag events

The SDK allows you to log events happening in your code. These are the two methods you can call on the SDK:

<a href="#" onclick="FollowAnalytics.logEvent('My event', 'My event details')">Log an event</a>
<a href="#" onclick="FollowAnalytics.logError('My error', 'My error details')">Log an error</a>

Use the name as the unique identifier of your tag, use the details section to add specific details, context. Events can be renamed later: the name that you give to your event here can be overridden in the FollowAnalytics UI.

The details field can either be a String or a Hash, so that you can associate multiple key-values for additional context.

For instance, logging the appearance of a view could be done the following way:

FollowAnalytics.logEvent('Product view', Product reference);

FollowAnalytics.logEvent('Add product to cart', {'product_id': 'ABCD123',
                                              'product_category': 'Jeans'});

User ID and attributes

You don't need a user ID to set attributes

Attributes are tied to the device when no user ID is provided. If a user ID is set, a profile is created and can be shared across apps.

In both cases, attributes can be used in segments and campaigns to target users.

User ID

If users can sign in somewhere in your app, you can specify their identifier to the SDK. This way, you will be able to relate crashes to specific users, link your users between FollowAnalytics and your CRM, and more.

This identifier is usually an e-mail address, client identifier, phone number, or anything else that uniquely ties your customers to you.

To register the user identifier, use:

FollowAnalytics.setUserId("user_id@email.com");

If you want to remove the user identifier (in case of a sign out for instance) use the following method:

FollowAnalytics.unsetUserID();

Predefined attributes

The SDK allows to set values for both custom and predefined attributes.

For predefined attributes, the SDK has the following properties:

FollowAnalytics.UserAttributes.setFirstName("Peter");
FollowAnalytics.UserAttributes.setLastName("Jackson");
FollowAnalytics.UserAttributes.setCity("San Francisco");
FollowAnalytics.UserAttributes.setRegion("California");
FollowAnalytics.UserAttributes.setCountry("USA");
FollowAnalytics.UserAttributes.setGender(FollowAnalytics.Gender.Male);
FollowAnalytics.UserAttributes.setEmail("mail@mail.com");
FollowAnalytics.UserAttributes.setBirthDate("2001-02-22");
FollowAnalytics.UserAttributes.setProfilePicture("https://picture/picture");

They are "predefined" in the sense that they will be attached to default fields on your user profiles.

Custom attributes

Double check your custom attribute types

When a value for an unknown attribute is received by the server, the attribute is declared with the type of that first value.

If you change the type of an attribute in the SDK, values might be refused server-side. Please ensure the types match by visiting the profile data section of the product.

Set a custom attribute

To set your custom attributes, you can use methods that are adapted for each type:

FollowAnalytics.UserAttributes.setNumber('key', "1");
FollowAnalytics.UserAttributes.setString('key', "A custom string attribute");
FollowAnalytics.UserAttributes.setBoolean('key', "true");
FollowAnalytics.UserAttributes.setDate('key', "2016-10-26");
FollowAnalytics.UserAttributes.setDateTime('key', "2016-10-26T11:22:33+01:00");

For example, to set the user's job:

FollowAnalytics.setString("job", "Taxi driver");
Delete a custom attribute value

You can clear the value of an attribute using its key. For example, to delete the user's job:

FollowAnalytics.clear("job");
Set of Attributes

You can add or remove an item to or from a set of attributes.

To add an item:

FollowAnalytics.addToSet("fruits", "apple");
FollowAnalytics.addToSet("fruits", "banana");

To remove an item:

FollowAnalytics.removeFromSet("fruits", "apple");

And to clear a set:

FollowAnalytics.clearSet("fruits");

Advanced Use Cases

Deep-linking: URL, Parameters

Campaigns created through FollowAnalytics allow to deep link to content in your app. You can either use an App Link, or use key-value parameters that are forwarded to your code.

Version 4.1.0 of the SDK introduced the possibility to use direct App Links like twitter://messages, which will send you to the corresponding screen inside the Twitter application.

You're able to access the functionality by enabling the Deep Linking switch in our UI, when creating a campaign. There you'll find the field App Link that expects you to enter these type of url schemas. It can either be an URL Schema to an external application or for your own application.

Deep-linking parameters

In FollowAnalytics campaigns, you can specify deep-linking parameters, e.g. in your push messages or for in-app button actions.

These parameters are given to the developer's code by the SDK. It is then up to the developer to implement the deep-linking in the app (specific path of screens, format of the arguments, etc.).

iOS: Incoming notification

In order to be able to receive the custom parameters sent within a Push Notification or an In App message payload, you'll need to implement the followAppsShouldHandleParameters:actionIdentifier:actionTitle:completionHandler:method. Inside your javascript files you'll have to implement a method that will be called from this Objective-C method. If you implement, or instance, a method called doAmazingThings() as follows:

function doAmazingThings(args) {
    console.log(args);
    var currentdate = new Date();
    var datetime = "Last Sync: " + currentdate.getDate() + "/"
    + (currentdate.getMonth()+1)  + "/"
    + currentdate.getFullYear() + " @ "
    + currentdate.getHours() + ":"
    + currentdate.getMinutes() + ":"
    + currentdate.getSeconds();
    document.getElementById('some_element').innerHTML = (datetime);
    console.log('done');
}

You'll be able to call the doAmazingThings() method using the following Objective-C code:

- (void)followAppsShouldHandleParameters:(NSDictionary *)openingParameters
                        actionIdentifier:(NSString *)actionIdentifier
                             actionTitle:(NSString *)actionTitle
                       completionHandler:(void (^)())completionHandler
{
    if (actionIdentifier)
    {
      // here you'll have the identifier for custom push notification actions
    }
    if (completionHandler != nil) {
      // always call the completionHandler, if any
        completionHandler();
    }
    NSData *data = [NSJSONSerialization dataWithJSONObject:openingParameters
                                                   options:NSJSONWritingPrettyPrinted
                                                     error:nil];
    NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    NSString *functionCall = [NSString stringWithFormat:@"doAmazingThings(%@)", jsonString];
    [YOUR_WEBVIEW_INSTANCE stringByEvaluatingJavaScriptFromString:functionCall];
}
iOS: Last notification

Some applications might not be able to receive the notification custom parameters. Although unlikely, you can call lastPushCampaignParams form the native code to get the latest JSON containing the custom parameters passed by the Notification.

If you need to fetch this data from your javascript, use FALastPushMessageContent, in response to the deviceready event from Cordova/PhoneGap.

Please note that this is a one shot call, as a second call to this method will return an empty JSON.

iOS: Deep-linking parameters

In order to get the custom parameters sent with the Push Notification you'll need to implement the following method calls inside your index.js file:

    FollowAnalytics.deepLinkHandling = function(args) {
        alert(JSON.stringify(args));
    };
    FollowAnalytics.retrieveLastMessage(function(args){
        alert(JSON.stringify(args));
    });

Since the Push Notification workflow differs when the application is on the background and when it's killed, you'll need to implement both method calls in order to be able to respond to each of those situations. The args content will be an object containing the keys and values you've defined in your Push Notification.

Android: Default behavior

By default, when the user clicks on a Push notification shown by the FollowAnalytics SDK, an Intent starting a new instance of your main activity is launched. You can retreive any custom parameter in the Java code by adding the following lines in your onCreate method.

@Override
protected void onCreate(Bundle savedInstanceState) {
    Bundle extras = getIntent().getExtras();
    if (extras != null) {
        String value1 = extras.getString("a_custom_param_key");
        String value2 = extras.getString("another_key");
        // or retrieve all the pairs
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
              // …
          }

        // Do what you want with the custom values
      }
}
Android: Handle deeplinking from Java

If you want more control, you can implement in your Java code the MessageHandler interface, and declare it in your application class, like in the following example.

public class MyAwesomePushMessageHandler implements MessageHandler {

    @Override
    public void onPushMessageClicked(Context context, Map<String, String> data) {
        String value1 = data.get("a_custom_param_key");
        String value2 = data.get("another_key");

        // Silently do stuff ...
        // .. or start an activity

        Intent intent = new Intent(context, SpecificActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    @Override
    public void onInAppMessageClicked(Context context, String buttonText, Map<String, String> data) {
        // Same as the above method, but from a in-app message !
    }
}

If you define a custom MessageHandler, you must declare it in your Application, after the FollowAnalytics.init(this) line:

FollowAnalytics.setMessageHandler(new MyAwesomePushMessageHandler());
Android: Handle deeplinking from javascript

To handle the deeplinking from your javascript code, have this run when the device is ready:

    onDeviceReady: function() {
            ...
            FollowAnalytics.handleDeeplink();
            FollowAnalytics.on("onPushMessageClicked", function(data){
                alert(JSON.stringify(data));
            });
            FollowAnalytics.on("onPushDeeplinkingClicked", function(data){
                alert(JSON.stringify(data));
            });
            FollowAnalytics.on("onInAppMessageClicked", function(data){
                alert(JSON.stringify(data));
            });
            ...
    },

As you can notice here, the plugin provides the following events : onPushMessageClicked , onPushDeeplinkingClicked and onInAppMessageClicked.

Control over campaigns

Custom handling of rich campaigns

Rich campaigns can be handled directly by the application code, instead of being showed automatically by the SDK. The behavior is defined when creating the campaign, using the "automatically display content" switch.

iOS

For campaigns where the content is not handled by FollowAnalytics, implement the following FAFollowAppsDelegate method in your AppDelegate:

- (void)followAppsShouldHandleWebViewUrl:(NSURL *)url withTitle:(NSString *)webviewTitle;
Android

For campaigns where the content is not handled by FollowAnalytics, you will need to extend com.followapps.android.CustomRichCampaignBaseReceiver and declare it in your AndroidManifest.xml. You'll need to use an intent-filter on BROADCAST_RICH_CAMPAIGNS_ACTION. For instance:

<receiver android:name=".RichCampaignDataReceiver" >
    <intent-filter>
        <action android:name="%YOUR_APP_PACKAGE_NAME%.BROADCAST_RICH_CAMPAIGNS_ACTION" />
    </intent-filter>
</receiver>

Where %YOUR_APP_PACKAGE_NAME% is your application package name.

The method onRichCampaignDataReceived must be overridden. Rich campaign parameters are provided as method arguments:

Pausing in-app campaigns

You can prevent in-app campaigns from being displayed on certain views of your app. This can be useful when you are displaying a media content, or if the topmost screen is only shown for a few seconds, for instance.

Any campaign supposed to be displayed when the mechanism is paused is stacked and shown as soon as it is resumed.

To tell the SDK to prevent the display of rich campaigns, and then to activate it back, use the following methods:

FollowAnalytics.pauseCampaignDisplay();
FollowAnalytics.resumeCampaignDisplay();

Tip: use view lifecycle methods

If you want to prevent the display on a given page, you can call the pause method when a view appears, and the resume one when it disappears.

Tip: only allow display in some places of the app

You can use these methods the other way round, by pausing all campaigns when the app starts, right after the SDK is initialized, and then resuming where the messages can be shown. Just pause again when the user leaves that "safe" area of your app.

Opening an external webview

The plugin allows you to launch a native web view with a given url and be able to performs logs from that external resource. In order to do so, if you want to open url https://s3-eu-west-1.amazonaws.com/fa-sdk-files/index.html in a native web view launched from your html code, call the following method from your PhoneGap HTML:

FollowAnalytics.openWebView(URL, TITLE, CLOSE_BUTTON_TEXT);

Somethign like:

<a href="#" onclick="FollowAnalytics.openWebView('https://s3-eu-west-1.amazonaws.com/fa-sdk-files/index.html', 'Test Log', 'Close'); return false;">Open WebView with title</a>

The URL argument will contain the url of the page to display (required), the TITLE argument will be shown as the title for the NavigationBar (optional, iOS only), and the CLOSE_BUTTON_TEXT will contain the text for the close button (optional, iOS only, defaults to “close”).

Please check the html at https://s3-eu-west-1.amazonaws.com/fa-sdk-files/index.html to see how to tag your external pages.

Current available methods are:

NOTE: if you're tagging from a link and the link has a real href set, the sdk will handle that for you, performing the onclick action and redirecting you right after.

Migration and Troubleshooting

Migration from 4.x

Although previous versions of the FollowAnalytics plugin respected Cordova guidelines of integration they still required developers to perform modifications to the native code for each supported platform.

This new version changes things as it can be used without having to modify nothing but the config.xml and the html/js code. If you plan to update from older versions, the shortest path would be to: - remove the FollowAnalytics plugin - remove both platforms (iOS and Android) - add back the platforms (iOS and Android) - add back the FollowAnalytics plugin - follow this installation guide from the top

If you plan to keep the current code you'll need to remove all the code needed to integrate previous plugin versions (please check older plugin documentation to know exactly what to remove).

Troubleshooting

If you eventually run into an error like:

Refused to execute inline event handler because it violates the following Content Security Policy directive: "default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'". Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.

Be sure to replace the line

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">

on your index.html by

<meta http-equiv="Content-Security-Policy" content="default-src *; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'" >

This will enable the logging of events.