Skip to content
Track & Trigger - Unity SDK Integration Guide
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
Example-Game
.gitignore
README.md

README.md


Introduction

Marketers use the Optimove Relationship Marketing Hub to automate the execution of highly-personalized customer communications. Optimove offers its clients an efficient way to track data from their websites and trigger campaigns accordingly.

This guide will show you how to setup the Unity SDK in order to:

  • Track visitor and customer actions and events
  • Trigger Realtime campaigns

Basic Setup

Request a Mobile SDK from Optimove

Before implementing the Optimove Track & Trigger to track visitor / customer activities or perform other functions (Optipush), you will need to contact your Optimove Customer Success Manager (CSM) or Optimove point of contact.

To get started, please follow the below instructions:

1. Pre-Requisites:

  1. The app's minimum Android SDK version is 19
  2. The app's Deployment Target is at least iOS 10.0
  3. You have a paid development account for your iOS app, and valid certificates for remote notifications or APN Auth key.
  4. Your Cocoapods version is 1.5 or above
  5. The Optimove SDK for Unity is dependent upon the Firebase Native SDK. If your application already uses Firebase Native SDK or has a dependency with Firebase Native SDK, a build conflict might occur, and even Runtime Exception, due to backwards compatibility issues.
    Therefore, it is highly recommended to match the application's Firebase Native SDK version to Optimove's Firebase Native SDK version as detailed in the following table.

Android Dependencies

Optimove SDK for Unity Version Firebase Core SDK Version Firebase Database SDK Version Firebase Messaging SDK Version Firebase Invites SDK Version Firebase Job Dispatcher SDK Version
1.0.0 16.0.6 16.0.5 17.3.4 16.0.6 0.8.5

iOS Dependencies

Optimove SDK for Unity Version FirebaseCore FirebaseMessaging FirebaseDynamicLinks
1.0.0 5.15.0 3.2.2 3.3.0

Optimove's Android SDK is written in Java 8. Hosting apps that are written in Java 7 or use Jack may encounter build errors. In these cases migrate the app to Java 8.
For most of Unity's use cases this is handled by the mainTemplate.gradle file bundled with the SDK so this should be handled by the client developer only on very specific use-cases.
For more information about Android Official Java 8 Support checkout this Developer's Guide article

2. Provide your app's details:

Send the following information to your CSM or Optimove POC with your request for your Mobile SDK configuration details in order to incorporate into your Unity app :

Details for the Android build:

  1. App's package(s) (If you are using multiple apps for development/testing purposes, please provide a list of all package names being used for all environments.)
  2. SHA256 cert fingerprint (can be retrieved using: keytool -list -v -keystore my-release-key.keystore)

Details for the iOS build:

  1. Auth key (with its key id) P8 format
  2. Bundle ID (If you are using multiple apps for development/testing purposes, please provide a list of all bundle IDs being used for all environments.)
  3. Team ID (from apple developer dashboard)
  4. App Store ID (from App Store Connect)

3. Retrieve tenant_information_suite details:

After providing the info above, you will receive a tenant_information_suite from the Optimove Product Integration Team that contains:

  1. End-point URL – The URL where the tenant configurations reside
  2. Unique Optimove token – The actual token, unique per tenant
  3. Configuration name – The version of the desired configuration

For a demo application containing the Unity SDK, please use our Example Game.

Setting Up the Unity SDK

1. Install the SDK

  1. Download the OptimoveUnitySdk.unitypackage from here.
  2. In the Unity Editor, click Assets -> Import Package -> Custom package to import the package into your app
  3. Locate the OptimoveUnitySdk.unitypackage and click import

2. Integrate the SDK

In the Unity Editor

The OptimoveUnitySdk comes with a Prefab called OptimoveNativeMessageReceiver. Make sure to add this Prefab to every scene of your Unity app.

For the Android build

The Android Native SDK is integrated automatically during the installation process. However, if your app uses a custom Gradle Build Script (in the Assets/Plugins/Android/ folder) make sure to add/override the following sections from Optimove's mainTemplate.gradle to your script:

// Optimove SDK Integration: The exact order here is important to prevent build collisions
allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url  "https://mobiussolutionsltd.bintray.com/optimove-sdk"
        }
        flatDir {
            dirs 'libs'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    // Optimove SDK Integration: Use API and not implementation as the SDK's dependencies must be transparent to the app module
    api 'com.optimove.sdk:unity-native-plugin:1.0.0'
**DEPS**}

android {
    
    // Optimove SDK Integration: The Native SDK is written in Java 8 - Not adding this section will prevent the project from building
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

For the iOS build

  1. The native iOS SDK can only be imported once the Unity project has been built and converted to an XCode project. So click Build and not Build and Run the first time integrating the Optimove.
  2. The native iOS SDK is imported using Cocoapods so if you haven't already integrated Cocoapods into your XCode project, open your Terminal, move to the folder containing the XCode project and run pod init.

If you don't have Cocoapods installed on your machine run sudo gem install cocoapods

  1. Open the Podfile that is located in the same folder as the XCode project and make paste/merge the following:
platform :ios, '10.0'
use_modular_headers!

# This target is automatically generated by Optimove's Unity SDK as part of the build process
target 'OptimoveNotificationServiceExtension' do
  pod 'OptimoveNotificationServiceExtension'
end

# 'Unity-iPhone' is the name Unity generates by default. If your App target has a different name, place use that instead of the 'Unity-iPhone'
target 'Unity-iPhone' do
  pod 'OptimoveSDK'

  # Don't include this section if your app doesn't have 'Unity-iPhone Tests' target
  target 'Unity-iPhone Tests' do 
    inherit! :search_paths
    # Pods for testing
  end
end
  1. Run pod install to download the SDK and its depenedencies from Cocoapods.

  2. The Optimove native SDK is written in Swift. To allow the linker to discover it you must add a Swift file to both the App ('Unity-iPhone') target and the Notification Extension ('OptimoveNotificationServiceExtension'):

    1. In XCode, right click the Classes folder and choose New File....
    2. Select a Swift File and click Next.
    3. Give the file a name (for convenience we call it dummy.swift) and choose Next.
    4. XCode now prompts you to add a Bridging-Header file, approve the prompt
    5. Repeat steps 1-4 for the OptimoveNotificationServiceExtension folder.

If the App group capability in App Target or the Optimove Notification Extension shows an error in the Add App Groups to your App ID, try appending a 1 at the end of the app's bundle id, wait for the provisioning profile to update and then remove the trailing 1. Now return to the App Group capability tab and make sure that the error has been resolved. If the error persists, contact Optimove's POC.

If you encounter the following error:

:-1: Cycle in dependencies between targets ‘OptimoveNotificationServiceExtension’ and ‘Pods-OptimoveNotificationServiceExtension’; building could produce unreliable results. This usually can be resolved by moving the target’s Headers build phase before Compile Sources.
Cycle path: OptimoveNotificationServiceExtension → Pods-OptimoveNotificationServiceExtension → OptimoveNotificationServiceExtension
Cycle details:
→ Target ‘OptimoveNotificationServiceExtension’
→ Target ‘Pods-OptimoveNotificationServiceExtension’ has target dependency on Target ‘OptimoveNotificationServiceExtension’
→ Target ‘OptimoveNotificationServiceExtension’ has compile command with input ‘/Users/mobiledeveloperoptimove/Development/repos/OptimoveSDK_Unity/OptimoveUnitySdk/Build_iOS/Pods/Target Support Files/OptimoveNotificationServiceExtension/OptimoveNotificationServiceExtension-dummy.m’
○ That command depends on command in Target ‘OptimoveNotificationServiceExtension’: script phase “Copy generated compatibility header”

then change the workspace setting build systems to the legacy build system.

3. Initialize the SDK

For the Android build

In the mainTemplate.gradle file (or your custom Gradle build script) add the following BuildConfig properties, based on the tenant_information_suite that was provided by Optimove:

android {
    buildTypes {
        debug {
            minifyEnabled **MINIFY_DEBUG**
            useProguard **PROGUARD_DEBUG**
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD**
            jniDebuggable true

            // Optimove SDK Integration: Don't delete the single nor the double quote - just the value with the enclosing diamond brackets
            buildConfigField "String", "OPTIMOVE_INIT_ENDPOINT_URL", '"<STAGING_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "String", "OPTIMOVE_TOKEN", '"<STAGING_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "String", "OPTIMOVE_CONFIG_NAME", '"<STAGING_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "Boolean", "OPTIMOVE_HAS_DEFAULT_FIREBASE_APP", "<STAGING_VALUE_PROVIDED_BY_OPTIMOVE>" // Set to true if your app uses the Firebase SDK already
        }
        release {
            minifyEnabled **MINIFY_RELEASE**
            useProguard **PROGUARD_RELEASE**
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-unity.txt'**USER_PROGUARD****SIGNCONFIG**

            // Optimove SDK Integration: Don't delete the single nor the double quote - just the value with the enclosing diamond brackets
            buildConfigField "String", "OPTIMOVE_INIT_ENDPOINT_URL", '"<PRODUCTION_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "String", "OPTIMOVE_TOKEN", '"<PRODUCTION_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "String", "OPTIMOVE_CONFIG_NAME", '"<PRODUCTION_VALUE_PROVIDED_BY_OPTIMOVE>"'
            buildConfigField "Boolean", "OPTIMOVE_HAS_DEFAULT_FIREBASE_APP", "<PRODUCTION_VALUE_PROVIDED_BY_OPTIMOVE>" // Set to true if your app uses the Firebase SDK already, false otherwise
        }
    }**PACKAGING_OPTIONS****SPLITS**
**BUILT_APK_LOCATION**
}**SPLITS_VERSION_CODE****SOURCE_BUILD_SETUP**

For the iOS build

Open the C# script of the first scene that is loaded when your app opens. In that script, in the Awake MonoBehaviour callback (override it if you didn't already) paste the following:

public class MyScene : MonoBehaviour {

    private void Awake()
        {
#if UNITY_IOS
        OptimoveUnitySdk.Init("<INIT_ENDPOINT_URL>", // Provided by Optimove
                              "<TOKEN>", // Provided by Optimove
                              "<CONFIG_NAME>", // Provided by Optimove
                              "<HAS_DEFAULT_FIREBASE_APP>", // Set to true if your app uses the Firebase SDK already, false otherwise
                              "<HAS_DEFAULT_FIREBASE_MESSAGING>"); // Set to true if your app uses the Firebase Messaging SDK already, false otherwise
#endif
        }
}

4. Important Installation and Usage Notes

1. Working with multiple Firebase messaging services (Hosting application uses Firebase)

Client uses Firebase's Unity SDK: Forward Firebase Token Event to the SDK

When setting up Firebase Messaging for Unity, you get a callback when a new FCM Token was generated. Forward that token to the Optimove SDK for Unity:

public void OnTokenReceived(object sender, Firebase.Messaging.TokenReceivedEventArgs token) {
    OptimoveUnitySdk.UpdateOptimoveWithFcmToken(token.Token);
}
Client uses Firebase's Native Android SDK: Multiple FirebaseMessagingServices:

When the hosting app also utilizes Firebase Cloud Messaging and implements the FirebaseMessagingService Android's Service Priority kicks in, and Optimove SDK's own FirebaseMessagingService is never called. For that reason, the hosting app must call explicitly Optimove's onMessageReceived and onTokenRefresh callbacks from the Native Android code.
The onMessageReceived method returns true if the push message was intended for the Optimove SDK.

public class MyMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
      super.onMessageReceived(remoteMessage);
      boolean wasOptipushMessage = new OptipushMessagingHandler(this).onMessageReceived(remoteMessage);
      if (wasOptipushMessage) {
        // You should not attempt to present a notification at this point.
        return;
      }
      // The notification was meant for the App, perform your push logic here
    }
    
    @Override
    public void onNewToken(String s) {
      super.onNewToken(s);
      // Forward the call to the Optimove SDK
      new FcmTokenHandler().onTokenRefresh();
      // Continue with the application logic
    }
}
Client uses Firebase's Native iOS SDK: App Uses the FirebaseMessaging module:

When the hosting app use its own FirebaseMessaging it must do 2 things:

  1. Pass true in the hasDefaultFirebaseMessaging property that is passed to the OptimoveUnitySdk.Init method.
  2. Forward the Firebase.Messaging.TokenReceivedEventArgs token to the Optimove SDK via the OptimoveUnitySdk.UpdateOptimoveWithFcmToken method.

FirebaseApp Initialization Order

Android

Usually when using Firebase it takes care of its own initialization. However, if you desire to initialize the default FirebaseApp manually. In these special cases, be advised that the SDK's automatic initialization flow assumes that if you have a default FirebaseApp you've already called FirebaseApp.initializeApp() (manually). The SDK knows to handle the aforementioned failure gracefully, however, for it to properly work, make sure you call Optimove.connectToOptimoveFirebaseApp() as soon as you've called FirebaseApp.initializeApp() manually (automatic initialization is automatically handled by the SDK).

Firebase guidelines require you to initialize the FirebaseApp instance ASAP. That means either a custom ContentProvider or Application subclass. Optimove cannot support the outcomes of initializing the FirebaseApp instance outside of these objects (like in the Activity instance). For more info read this Firebase blog post.

iOS

Usually when using Firebase it takes care of its own initialization. However, if you desire to initialize the default FirebaseApp manually. In these special cases, be advised that the SDK's initialization flow assumes that if you have a default FirebaseApp you've already called [FIRApp configure] (manually).

Firebase guidelines require you to initialize the FIRApp instance ASAP. That means in the AppDelegate's application didFinishLaunchingWithOptions: or application willFinishLaunchingWithOptions: callbacks. Optimove cannot support the outcomes of initializing the FirebaseApp instance outside of these callbacks.

2. State Registration:

The SDK initialization process occurs asynchronously, off the Main UI Thread.
Before calling the Public API methods of the Optimove SDK for Unity, make sure that the SDK has finished initialization by calling the OptimoveUnitySdk.RegisterInitializationSuccessCallback method with an instance of SdkInitializationSuccessCallback. The callback is called once the SDK has finished initialization with an array of missing SdkRequiredPermission (see the next section 3. Missing Optional Permissions for more info).

Make sure to call OptimoveUnitySdk.UnregisterInitializationSuccessCallback with the SdkInitializationSuccessCallback that was sent to the SDK to release implicit references to the captured environment.

public class PlayerController : MonoBehaviour {
    
    private SdkInitializationSuccessCallback optimoveInitializationSuccessCallback;

    private void Start() 
    {    
        optimoveInitializationSuccessCallback = missingPermissions =>
        {
            // Recommended: Handle the missingPermissions here
        };
        OptimoveUnitySdk.RegisterInitializationSuccessCallback(optimoveInitializationSuccessCallback);
    }

    private void OnDestroy() 
    {    
        // Make sure to release the captured optimoveInitializationSuccessCallback when the scene is destroyed
        if (optimoveInitializationSuccessCallback != null) 
        {
            OptimoveUnitySdk.UnregisterInitializationSuccessCallback(optimoveInitializationSuccessCallback);
        }
    }
}

3. Missing Optional Permissions:

Once the SDK has finished initializing successfully, it passes all User Dependent missing permissions through the SdkInitializationSuccessCallback(SdkRequiredPermission[] missingPermissions) delegate. These permissions are important to the user experience but do not block the SDK's proper operation.
These Permission are:

Android and iOS
  • Notifications - Indicates that the user has opted-out from the app's notification.
  • AdvertisingId - Indicates that the user has opted-out from allowing apps from accessing his/her Advertising ID.
Android only
  • DrawNotificationOverlay - Indicates that the app is not allowed to display a "drop down" notification banner when a new notification arrives.
  • GooglePlayServices - Indicates that the Google Play Services app on the user's device is either missing or outdated.

4. The Hosting Application Specifies Rules for Automatic Backup (Android Only)

Starting from API 23 Android offers the Auto Backup for Apps feature as a way to back up and restore the user's data in the app. The Optimove SDK depends on some local files being deleted once the app is uninstalled.
For that reason if the hosting app also defines android:fullBackupContent="@xml/app_backup_rules" in the manifest.xml file, Android will raise a merge conflict.

Follow these steps to resolve the conflict and maintain the data integrity of the Optimove SDK:

  1. Add tools:replace="android:fullBackupContent"> to the application tag
  2. Copy the content of the optimove_backup_rules.xml to your full-backup-content xml.

For more information about Android Automatic Backup checkout this Developer's Guide article

5. Tracking Visitor and Customer activity

You will also need to include the following steps to complete the basic setup:


Advanced Setup

Use the Advanced Setup (optional) in order to track visitor and customer customized actions and events. As described in Tracking Custom Events, this step requires collaboration between you and Optimove’s Integration Team. Please contact your Optimove Customer Success Manager (CSM) or Optimove point of contact to schedule a meeting with the Product Integration team.

Note: You can deploy the basic setup, followed by adding the advanced setup at a later stage. The Basic Setup is a pre-requisite.


Track

Linking App Visitors to Registered User IDs

Once the user has downloaded the application and the Optimove SDK for Unity has run for the first time, the user is considered a visitor, i.e., an unidentified person.

Once the user authenticates and becomes identified by a known PublicCustomerId, then the user is considered a customer. As soon as this happens for each individual user, call the SetUserId function to pass the CustomerId to the OptimoveUnitySdk static class:

public class MyGameObject : MonoBehaviour
{
    void AppAuthFlow()
    {
        // The PublicCustomerId was acquired, pass it to Optimove
        OptimoveUnitySdk.SetUserId("PublicCustomerId");
    }
}
  • The CustomerId is usually provided by the server application that manages customers, and is the same ID provided to Optimove during the daily customer data transfer.
  • Any userId that does not correspond to your Optimove unique identifier (Customer ID) due to faulty / unrecognized userIds will now be excluded from your customer tracked activity. Therefore please make sure that the userId sent via the userId is a recognizable ID.
  • Due to its high importance, SetUserId may be called at any time, regardless of the SDK’s state (See State Registration section)
  • If you will be sending encrypted userId, please follow the steps in Reporting encrypted CustomerIDs

Tracking Screen Visits

To track which screens the user has visited in your app, call the ReportScreenVisit method of the Optimove singleton. It can accept either the current Scene or, for more finely tuned screen hierarchy reporting, a String describing the Scene's hierarchy.

public class PlayerControls : MonoBehaviour
{
    void Start()
    {
        OptimoveUnitySdk.ReportScreenVisit("path/to/active", "screen_name");
    }
}

Tracking/Updating User Email Addresses

To track a user’s email address, such as when a visitor enters the app and submits a register or subscribe form, call the SetUserEmail method to record the address. This is best used when you want to capture realtime email event.

public class MyGameObject : MonoBehaviour
{
    void AppAuthFlow()
    {
        // The user email was acquired, pass it to Optimove
        OptimoveUnitySdk.SetUserEmail("example@demo.com");
    }
}

In instances where you need to set both the visitor's user ID and email address simultaneously, you should use the RegisterUser method instead of SetUserEmail. This applies to all situations in which a single user action requires you to set both the user ID and email address (e.g., registration, newsletter signup).

Registering the User ID and User Email at the Same Time

In all situations where a single user action requires you to set both the customer ID and email address (e.g., registration, newsletter signup) simultaneously, you should use the RegisterUser method (instead of calling both SetUserId and SetUserEmail) to ensure the proper registration of the user in Optimove.

public class MyGameObject : MonoBehaviour
{
    void AppAuthFlow()
    {
        // The PublicCustomerId AND the user's email were acquired simultaneously, pass them both to Optimove
       OptimoveUnitySdk.RegisterUser("PublicCustomerId", "example@demo.com");
    }
}

Tracking Custom Events

Optimove clients may use the Optimove Mobile SDK to track specific customer actions and other custom events to Optimove (beyond the OOTB events such as visits). This data is used for tracking visitor and customer behavior, targeting campaigns to specific visitor and/or customer segments and triggering campaigns based on particular visitor and/or customer actions/events.

To see examples of Custom Events, please visit Defining the Set of Custom Tracking Events that You Will Report for more information.

Note: While you can always add/change the custom events and parameters at a later date (by speaking with the Optimove Product Integration Team), only the particular custom events that you and the Optimove Product Integration Team have already defined together will be supported by your Optimove site.

How to Track a Custom Event from within your app

Once you and the Optimove Integration Team have together defined the custom events supported by your app, the Integration Team will implement your particular functions within your Optimove site, while you will be responsible for passing the information of the individual events within your app using the appropriate function calls.

There are 2 ways to report a Custom Event through the Optimove SDK for Unity:

1. For simple events

Pass the the custom event’s name and parameters directly via the OptimoveUnitySdk.ReportEvent(string eventName, Dictionary<string, object> parameters) function.

public class MyGameObject : MonoBehaviour
{
    void MyEventReportingFunction()
    {
        OptimoveUnitySdk.ReportEvent("my_custom_event", new Dictionary<string, object>
            {
                { "my_param_1", 42 }
            });
    }
}

2. For more complex events

The Optimove SDK for Unity defines an interface called OptimoveEvent. It defines two read-only computed properties:

  1. string Name – Declares the custom event’s name
  2. Dictionary<string, object> Parameters – Specifies the custom event’s parameters.

Use this interface to conform your complex event objects to the Optimove format and pass it to the SDK via the OptimoveUnitySdk.ReportEvent(OptimoveEvent optimoveEvent) function.

public class MyCustomEvent : OptimoveEvent
{
    private readonly string _myParam;

    public MyCustomEvent(string myParam)
    {
        _myParam = myParam;
    }

    public string Name
    {
        get { return "my_custom_event"; }
    }

    public Dictionary<string, object> Parameters
    {
        get
        {
            return new Dictionary<string, object>
            {
                {"my_param_1", _myParam}
            };
        }
    }
}

public class MyGameObject : MonoBehaviour
{
    void MyEventReportingFunction()
    {
        OptimoveUnitySdk.ReportEvent(new MyCustomEvent("a value"));
    }
}
  • As already mentioned, all custom events must be pre-defined in your Tenant configurations by the Optimove Integration Team.
  • Reporting of custom events is only supported if you have the Mobile SDK implemented.
  • Events use snake_case as a naming convention. Separate each word with one underscore character (_) and no spaces. (e.g., checkout_completed)

You can’t perform that action at this time.