Skip to content

CleverTap/clevertap-unreal-sdk

Repository files navigation

Plugin Integration

Clone and Copy

Clone the sample application repository into a temporary folder to get access to the CleverTap Unreal plugin.

git clone --depth 1 https://github.com/CleverTap/clevertap-unreal-sdk.git

Copy the clevertap-unreal-sdk\Plugins\CleverTap folder to your Unreal project's Plugin folder.

Integration

Generic Integration

Add the following to the Plugins section of your Unreal project's .uproject file.

{
	"Plugins": [
		{
			"Name": "CleverTap",
			"Enabled": true
		}
	]
}

C++ Integration

Add the following to the C++ gameplay module's PrivateDependencyModuleNames property in each *.Target.cs file's class constructor.

PrivateDependencyModuleNames.Add("CleverTap");

If you use any of the public CleverTap types in your module's public types then you should add it to the PublicDependencyModuleNames property instead.

Configuration

In your project's Config\DefaultEngine.ini file add the following block at the end.

[/Script/CleverTap.CleverTapConfig]
ProjectId= ;Add your project Id here. This is found on your project's CleverTap dashboard
ProjectToken= ;Add your project token here. This is found on your project's CleverTap dashboard
RegionCode= ;Reference https://developer.clevertap.com/docs/idc#ios to determine what region code string to put here

Alternatively you can edit the Plugin's settings in the UE4Editor.

Initialization

By default, with bAutoInitializeSharedInstance set to true in Config\DefaultEngine.ini, the UCleverTapSubsystem will automatically initialize the CleverTap SDK and the default shared instance. It is recommended not to set this to false as it is only currently partially supported on iOS.

Encryption of PII Data

PII data is stored across the SDK and could be sensitive information. You can enable encryption for PII data such as Email, Identity, Name, and Phone. Currently, two levels of encryption are supported:

  • None: All stored data is in plaintext (the default)
  • Medium: PII data is encrypted completely

The only way to set the encryption level for the default instance is from Config/DefaultEngine.ini:

[/Script/CleverTap.CleverTapConfig]
EncryptionLevel=Medium

Different instances can have different encryption levels. To set an encryption level for an additional instance, set the EncryptionLevel field in the FCleverTapInstanceConfig used to create it.

Push Notification Configuration

CleverTap allows you to send push notifications to your applications from our dashboard, once the user has granted permission in response to a call to PromptForPushPermission().

Each platform requires slightly different setup.

Android - Configure Firebase Cloud Messaging (FCM)

To use the default CleverTap notification implementation with Firebase:

  1. Follow these instructions to create and register your firebase credentials in the CleverTap dashboard.

  2. Copy the generated google-services.json to somewhere in your project directory (e.g. Config).

  3. In your project's Config/DefaultEngine.ini ensure bAndroidIntegrateFirebase is True and AndroidGoogleServicesJsonPath is the project-relative path to where you copied google-services.json.

[/Script/CleverTap.CleverTapConfig]
bAndroidIntegrateFirebase=True
AndroidGoogleServicesJsonPath=Config/Android/google-services.json

Android - Configure Push Notification Channels

Android requires push notifications to be delivered via pre-defined notification channels. These channels let users customize how different types of notifications behave (e.g., sound, vibration, visibility).

Because channels must be registered during Java's GameApplication.onCreate() - before Unreal Engine has initialized - they cannot be created dynamically from C++. Instead, they must be preconfigured in your project’s Config/DefaultEngine.ini.

Basic Setup

Define up to 100 channels in your DefaultEngine.ini. Only the ID field is required - this is the unique identifier for the channel.

[/Script/CleverTap.CleverTapConfig]
AndroidNotificationChannelSlot1=ID="general" | Name="General" | Description="General Notifications" | Importance=IMPORTANCE_DEFAULT | bShowBadge=True
AndroidNotificationChannelSlot2=ID="news" | Name="News Updates" | Description="Important news and alerts" | Importance=IMPORTANCE_HIGH | bShowBadge=True | Sound="news_alert.wav"

Valid Importance values: IMPORTANCE_NONE, IMPORTANCE_MIN, IMPORTANCE_LOW, IMPORTANCE_DEFAULT, IMPORTANCE_HIGH, IMPORTANCE_MAX.

The sound files must be included in the APK's res/raw; see the AndroidSoundsDir setting for more information.

Note

  • The plugin’s CleverTap_Android_UPL.xml reads these entries and injects the required Java into GameApplication.onCreate(). Errors in the ini syntax will cause the compilation of GameApplication.java to fail.
  • The AndroidNotificationChannelSlot settings can only be edited directly in your project’s Config/DefaultEngine.ini; they are not available in the Project Settings GUI.

Channel Localization

You can set the channel’s display name and description at runtime using Unreal's localization system. If you use runtime localization, there's no need to specify Name or Description in the .ini.

[/Script/CleverTap.CleverTapConfig]
AndroidNotificationChannelSlot1=ID="general" | Importance=IMPORTANCE_DEFAULT | bShowBadge=True
AndroidNotificationChannelSlot2=ID="news" | Importance=IMPORTANCE_HIGH | bShowBadge=True
C++
CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.LocalizeAndroidNotificationChannel(TEXT("general"),
        NSLOCTEXT("CleverTapSample", "ChannelName_general", "General"),
        NSLOCTEXT("CleverTapSample", "ChannelDesc_general", "General Notifications"));
Blueprint

Calling LocalizeAndroidNotificationChannel in Blueprint

Channel Grouping

You can define up to 10 notification channel groups to categorize related channels. Each group is declared in your .ini, and channels can reference them using Group="group_id".

[/Script/CleverTap.CleverTapConfig]
AndroidNotificationChannelGroupSlot1=ID="general" | Name="General"
AndroidNotificationChannelSlot1=ID="general" | Group="general" | Importance=IMPORTANCE_DEFAULT | bShowBadge=True

Group names can be localized at runtime, just like channels. Call LocalizeAndroidNotificationChannelGroup() early in startup and again after locale changes.

C++
CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.LocalizeAndroidNotificationChannelGroup( TEXT("general"), 
        NSLOCTEXT("CleverTapSample", "ChannelGroupName_general", "General"));
Blueprint

Calling LocalizeAndroidNotificationChannelGroup in Blueprint

Default Android Notification Channel

You can define a specific notification channel that CleverTap will use if the channel provided in the push payload is not registered by your app. This ensures that push notifications are displayed consistently even if the app's notification channels are not set up.

In case the SDK does not find the default channel ID specified in the manifest, it will automatically fall back to using a default channel called Miscellaneous. This ensures that push notifications are still delivered, even if no specific default channel is specified in the manifest.

To specify your app’s preferred default channel:

[/Script/CleverTap.CleverTapConfig]
AndroidDefaultNotificationChannel=general

Android Small Notification Icon

By default, our SDK uses the app's icon for both the notification icon and the notification bar icon; however, since Android 5, all non-alpha channels are ignored while drawing the main notification icon.

You can supply the project-relative path to an alpha-only png to use instead:

[/Script/CleverTap.CleverTapConfig]
AndroidSmallNotificationIconPath=Config/Android/sample_small_notification_icon.png

Note that the base filename must contain only lowercase letters (a-z), digits (0-9), or underscores (_).

For more information about the image requirements, see https://developer.clevertap.com/docs/android-push#set-the-small-notification-icon

Android Sound and Image Resources

Additional Images and Sounds can be included in the APK for direct use by Android & CleverTap.

These are not part of Unreal's regular asset system. They are copied directly into the APK and must follow Android resource rules. Filenames must contain only lowercase letters (a-z), digits (0-9), or underscores (_).

Android supports .mp3, .ogg, and .wav files for playing custom sounds.

[/Script/CleverTap.CleverTapConfig]
AndroidImagesDir=Config/Android/Images
AndroidSoundsDir=Config/Android/Sounds

Custom Android Notification Handling

Due to Android’s restriction of allowing only one FirebaseMessagingService, it cannot coexist cleanly with other Unreal plugins that declare their own FCM service (e.g. the Unreal Firebase plugin).

If you’re already using another Firebase plugin and also require CleverTap push features, you’ll need to disable the CleverTap Firebase integration with bAndroidIntegrateFirebase=False, and replace the other plug-in’s FCM service with a custom multiplexer implemented in Java.

For example:

public class UnifiedMessagingService extends SomeOtherPluginMessagingService {
    @Override
    public void onMessageReceived(RemoteMessage message) {
        if (isCleverTapMessage(message)) {
            new CTFcmMessageHandler().createNotification(getApplicationContext(), message);
        } else {
            // Let the base class handle it
            super.onMessageReceived(message);
        }
    }

    private boolean isCleverTapMessage(RemoteMessage message) {
        Map<String, String> data = message.getData();
        return data != null && data.containsKey("wzrk_pn"); // CleverTap magic key
    }
}

For more information, see Custom Android Push Notification Handling

Android OpenUrl Configuration

To handle incoming app links, enable bIntegrateOpenUrl and define up to four slot-based URL filters in your project’s .ini file.

[/Script/CleverTap.CleverTapConfig]
bIntegrateOpenUrl=True

; Example Slot1 - catches clevertap-unreal-sample://
DeepLinkSchemeFilterSlot1=clevertap-unreal-sample 

; Example Slot2 - catches clevertap://unreal.com/sample
DeepLinkSchemeFilterSlot2=clevertap
AndroidIntentFilterSlot2_Host=unreal.com
AndroidIntentFilterSlot2_PathPrefix=/sample

; Example Slot3 - catches http://clevertap.com/unreal-sample, 
; but requires digital verification that the app is approved for this domain
; See https://developer.android.com/training/app-links/verify-android-applinks
DeepLinkSchemeFilterSlot3=http
AndroidIntentFilterSlot3_Host=clevertap.com
AndroidIntentFilterSlot3_PathPrefix=/unreal-sample
AndroidIntentFilterSlot3_AutoVerify=True

[!NOTE] Http/Https schemes require digital verification via assetlinks.json hosted on the target domain. See: https://developer.android.com/training/app-links/verify-android-applinks

You can simulate clicking on a deep link with adb:

adb shell am start -a android.intent.action.VIEW -d "clevertap-unreal-sample://test/path"

Disable OpenUrlActivity integration if you need full control over your app’s deep link handling, and plan to define your own activity with complex intent filters via custom UPL rules. If your custom activity forwards the intent to the GameActivity, it will still be routed to the OnOpenURL delegate.

iOS OpenUrl Configuration

To handle incoming app links, enable bIntegrateOpenUrl and define up to four slot-based URL scheme filters in your project’s .ini file.

[/Script/CleverTap.CleverTapConfig]
bIntegrateOpenUrl=True

; Example Slot1 - catches clevertap-unreal-sample://
DeepLinkSchemeFilterSlot1=clevertap-unreal-sample 

; Example Slot2 - catches clevertap://
DeepLinkSchemeFilterSlot2=clevertap

; Example Slot3 - catches http://
DeepLinkSchemeFilterSlot3=http

To further filter the allowed links use the RegisterCleverTapUrlHandler() method to register a filter or do custom URL handling.

iOS - Configuring Apple Push Notifications (APNs)

  1. Follow the CleverTap guide to set up APNs for your app.
  2. In your project's Config/DefaultEngine.ini ensure bEnableRemoteNotificationsSupport is True in the [/Script/IOSRuntimeSettings.IOSRuntimeSettings] section.
  3. If you would like push notifications to appear when your app is in the foreground make sure that bIOSPresentPushNotificationsInForeground is set to True in the [/Script/CleverTap.CleverTapConfig] section of your project's Config/DefaultEngine.ini

Note

The CleverTap Unreal plugin currently does not support Push Impressions, Push Primers, or Rich Push Notifications.

iOS - Optional Engine changes for Push Notifications that launch the App

On Windows, a patch program equivalent can be installed using winget.

winget install GnuWin32.Patch
iOS Engine Patch - Push Notification Callback Invocation When App is Closed

If you're App isn't in the foreground or background then Unreal will not forward the push notification to CleverTap unless you make engine changes to Engine/Source/Runtime/ApplicationCore/Private/IOS/IOSAppDelegate.cpp. An example of such changes can be found in the EnginePatches/iOSSavedRemoteNotifications.patch patch file. This can be applied in the Unreal root directory using the linux patch command.

UnrealEngine % patch -p1 -u -i /path/to/CleverTapSample/EnginePatches/iOSSavedRemoteNotifications.patch
iOS Engine Patch - Rich Push Notification Support

Rich Push Notifications require a Notification Service Extension. Unfortunately Unreal Engine doesn't support app extensions without modification to its build process. An example patch that adds support for app extensions can be found in the EnginePatches/UE4.27_ExtensionSupport.patch patch file. This can be applied in the Unreal root directory using the linux patch command.

UnrealEngine % patch -p1 -u -i /path/to/CleverTapSample/EnginePatches/UE4.27_ExtensionSupport.patch

Once patched, the extension located at Plugins/CleverTap/Source/ThirdParty/IOS/Extensions/CTNotificationService will be included in the build. A custom signing provision can be specified for the extension via changes to the Config/DefaultEngine.ini file.

[/Script/IOSRuntimeSettings.IOSRuntimeSettings]
MobileProvision_CTNotificationService=YourProvisioning.mobileprovision

Please make sure the specified .mobileprovision file is installed before building.

Note

This engine patch adds support for arbitrary app extensions located in {ProjectFolder}/Build/IOS/Extensions or any {ProjectFolder}/Plugins/{PluginNameHere}/Source/ThirdParty/IOS/Extensions folders. It only supports UE4.27 and has only been tested against the CTNotificationService extension provided here.

Enabling OnPushNotificationClicked

After setting up your shared CleverTap instance the OnPushNotificationClicked delegate can be enabled by calling EnableOnPushNotificationClicked(). On iOS, if the engine patch has been applied for push notifications that launch the app then this can trigger attempting to broadcast the push notification that launched the app. Therefore a delegate listener should be added before calling EnableOnPushNotificationClicked().

C++

CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.OnPushNotificationClicked.AddLambda([](const FCleverTapProperties& NotificationPayload)
	{
		UE_LOG(LogTemp, Log, TEXT("Push notification was tapped"));
	});
CleverTap.EnableOnPushNotificationClicked();

Blueprint

Binding OnPushNotificationClicked in Blueprint

In-App Notifications

In-app notifications are initially suspended. When your callbacks are set up then call ICleverTapInstance::ResumeInAppNotifications() to begin receiving in-app notifications.

The payload parameters for all in-app notifications callbacks have their nested objects flattened as dot separated keys in the property map so that the object {"a": { "b": 3.14 }} would have a single entry of Payload[FString{TEXT("a.b")}] == FCleverTapPropertyValue{ 3.14 }.

Callbacks

OnInAppNotificationShown

When an in-app notification is displayed this callback will be invoked with and the notification payload is passed as a parameter.

C++
CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.OnInAppNotificationShown.AddLambda([](const FCleverTapProperties& Payload)
    {
		UE_LOG(LogTemp, Log, TEXT("An in-app notification was shown: %s"), *ToDebugString(Payload));
    });
Blueprint

Binding OnInAppNotificationShown in Blueprint

OnInAppNotificationButtonClicked

When the user clicks on an in-app notification button this callback will be invoked with the key/value pairs associated with that button.

C++
CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.OnInAppNotificationButtonClicked.AddLambda([](const FCleverTapProperties& Payload)
    {
		UE_LOG(LogTemp, Log, TEXT("An in-app notification button clicked: %s"), *ToDebugString(Payload));
    });
Blueprint

Binding OnInAppNotificationButtonClicked in Blueprint

OnInAppNotificationDismissed

When an in-app notification is dismissed by the user this callback will be invoked with the notification payload and any extra key/value pairs specified for the in-app notification in the CleverTap dashboard.

CleverTapSys = GEngine->GetEngineSubsystem<UCleverTapSubsystem>();
ICleverTapInstance& CleverTap = CleverTapSys->SharedInstance();
CleverTap.OnInAppNotificationDismissed.AddLambda([](const FCleverTapProperties& Extras, const FCleverTapProperties& ActionExtras)
    {
		UE_LOG(LogTemp, Log, TEXT("An in-app notification was dismissed. Extras: %s, ActionExtras: %s"),
            *ToDebugString(Extras), *ToDebugString(ActionExtras));
    });
Blueprint

Binding OnInAppNotificationDismissed in Blueprint

Suspend, Resume, and Discard In-App Notifications

In-app notifications initially start suspended. If you like to discard any notifications that were queued while they were suspended then you can invoke ICleverTapInstance::DiscardInAppNotifications() to do so. Notifications can be resumed by calling ICleverTapInstance::ResumeInAppNotifications(). Any queued notification that happened while suspended, and which has not been explicitly discarded, will be presented to the user. If you would like to suspend notifications again then call ICleverTapInstance::SuspendInAppNotifications().

Blueprint

Calling SuspendInAppNotifications -> DiscardInAppNotifications -> ResumeInAppNotifications in Blueprint

User Profiles

On User Login

The OnUserLogin() method can be used when a user is identifier and logs into the app. Upon first login this enriches the initial "Anonymous" user profile with additional properties such as name, age, and email. See Updating the User Profile for a list of predefined properties.

C++

FCleverTapProperties Profile;
Profile.Add(TEXT("Name"), TEXT("Jack Montana"));    // String
Profile.Add(TEXT("Identity"), 61026032);            // String or Number
Profile.Add(TEXT("Email"), TEXT("[email protected]")); // Email string
Profile.Add(TEXT("Phone"), TEXT("+14155551234"));   // with country code, starting with +
Profile.Add(TEXT("Gender"), TEXT("M"));             // Can be either M or F
Profile.Add(TEXT("DOB"), FCleverTapDate(1953, 3, 13));

Profile.Add(TEXT("MSG-email"), false);   // Disable email notifications
Profile.Add(TEXT("MSG-push"), true);     // Enable push notifications
Profile.Add(TEXT("MSG-sms"), false);     // Disable SMS notifications
Profile.Add(TEXT("MSG-whatsapp"), true); // Enable WhatsApp notifications

TArray<FString> Stuff;
Stuff.Add(TEXT("bag"));
Stuff.Add(TEXT("shoes"));
Profile.Add(TEXT("MyStuff"), Stuff); // Multi-Value array of string support

ICleverTapInstance& CleverTap = GEngine->GetEngineSubsystem<UCleverTapSubsystem>()->SharedInstance();
CleverTap.OnUserLogin(Profile);

Blueprint

Calling OnUserLogin in Blueprint

Updating a User Profile with PushProfile()

The user's profile can be enriched with additional properties at any time using the PushProfile() method. This supports arbitrary single value and multi-value properties like OnUserLogin().

C++

FCleverTapProperties Profile;
// Update an existing property
Profile.Add(TEXT("MSG-push"), false);

// Add new properties
Profile.Add(TEXT("Tz"), TEXT("Asia/Kolkata"));
Profile.Add(TEXT("Plan Type"), TEXT("Silver"));
Profile.Add(TEXT("Score"), 100);

ICleverTapInstance& CleverTap = GEngine->GetEngineSubsystem<UCleverTapSubsystem>()->SharedInstance();
CleverTap.PushProfile(Profile);

Blueprint

Calling PushProfile in Blueprint

Increment or Decrement Scalar Properties

If a given profile property is a int32, int64, float, or double then it can be incremented or decremented by an arbitrary positive value.

C++

ICleverTapInstance& CleverTap = GEngine->GetEngineSubsystem<UCleverTapSubsystem>()->SharedInstance();
CleverTap.IncrementValue(TEXT("Score"), 50);
CleverTap.DecrementValue(TEXT("Score"), 100);
CleverTap.IncrementValue(TEXT("Score"), 5.5);
CleverTap.DecrementValue(TEXT("Score"), 3.14);

Blueprint

Calling IncrementValue or DecrementValue in Blueprint

Event Recording

User Events

User Events can be recorded any time after initialization.

C++

ICleverTapInstance& CleverTap = GEngine->GetEngineSubsystem<UCleverTapSubsystem>()->SharedInstance();

// event without properties
CleverTap.PushEvent(TEXT("Event No Props"));

// event with properties
FCleverTapProperties Actions;
Actions.Add("Product Name", "Casio Chronograph Watch");
Actions.Add("Category", "Mens Accessories");
Actions.Add("Price", 59.99);
CleverTap.PushEvent(TEXT("Product viewed"), Actions);

Event values can be any type that the FCleverTapPropertyValue variant type supports (int32, int64, double, float, bool, const ANSICHAR*, FString, or FCleverTapDate).

Blueprint

Calling PushEvent in Blueprint Calling PushEventWithProperties in Blueprint

Charged Events

Charged events are a special user event to record transaction details of a purchase. Each item in the purchase can be recorded and enriched with custom properties.

C++

// charge event
FCleverTapProperties ChargeDetails;
ChargeDetails.Add("Amount", 300);
ChargeDetails.Add("Payment Mode", "Credit card");
ChargeDetails.Add("Charged ID", 24052014);

FCleverTapProperties Item1;
Item1.Add("Product category", "books");
Item1.Add("Book name", "The Millionaire next door");
Item1.Add("Quantity", 1);

FCleverTapProperties Item2;
Item2.Add("Product category", "books");
Item2.Add("Book name", "Achieving inner zen");
Item2.Add("Quantity", 1);

FCleverTapProperties Item3;
Item3.Add("Product category", "books");
Item3.Add("Book name", "Chuck it, let's do it");
Item3.Add("Quantity", 5);

TArray<FCleverTapProperties> Items;
Items.Add(Item1);
Items.Add(Item2);
Items.Add(Item3);

ICleverTapInstance& CleverTap = GEngine->GetEngineSubsystem<UCleverTapSubsystem>()->SharedInstance();
CleverTap.PushChargedEvent(ChargeDetails, Items);

Blueprint

Calling PushChargedEvent in Blueprint

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published

Contributors 2

  •  
  •