Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Please do the following to integrate your web application with devtodev:
1. Add the application to the Space using the wizard for adding applications.
2. To integrate SDK, add the following line to the tag of your page:
3. Init the SDK.
In order for SDK for WEB to start working, it is necessary to perform initialization right after the page is loaded and you have a basic user identifier at your disposal.
You can find the App ID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- is an object that is used for specifying additional properties during initialization.
Since there’s no option to get any consistent identifier in web browsers, we recommend using as a User ID either a social network ID with your app or an ID that your server assigns to a user. It’s best to assign a User ID and specify it in the config
object during the SDK initialization instead of using a setUserId
method after the initialization.
If you have a games app, we recommend specifying the current player’s lever either in the config
or at the earliest possible moment after the initialization via the setCurrentLevel
method.
Config
Parameter
Type
Description
userId
string
Unique user identifier. For example, user’s ID in a social network, or a unique account name used for user identification on your server. If at the time of initialization this identifier is not yet available, specify the identifier later using
the setUserId
method.
currentLevel
integer
The player level at the moment of devtodev SDK initialization. Must be greater than 0. It’s optional but we recommend using it for improving data accuracy.
trackingAvailability
boolean
The property allows or disallows devtodev tracking of the user. By default, it is set to true
. SDK stores the previously assigned value. Pass false if the user opted out of tracking in line with GDPR.
logLevel
string
The level of logging the SDK activity. The "No
" value is used by default. For troubleshooting during integration, it is recommended to set it to "Debug
", and either switch it "No
" or use it only for error handling "Error
" in the release version.
applicationVersion
String
The app version. Cannot be empty.
Example:
Find the DevToDev.Analytics.Uwp
package using the package manager search engine and click Install. The latest version of the package is recommended.
Initialize the library using the following code:
You can find the App ID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- is a DTDAnalyticsConfiguration
object instance that is used for specifying additional properties during initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
currentLevel
Integer
The player level at the moment of devtodev SDK initialization. It’s optional but we recommend using it for improving data accuracy.
userId
String
A custom user ID assigned by the developer. In the case of default calculation by device IDs, the identifier can be used for searching users in devtodev. In case the project uses calculation by user IDs, the parameter is mandatory because it becomes the principal calculation ID in devtodev.
trackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.Enable
. SDK stores the previously assigned value. Pass DTDTrackingStatus.Disable
if the user opted out of tracking in line with GDPR.
logLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.no
value is used by default. For troubleshooting during integration it is recommended to set it to DTDLogLevel.Debug
, and either switch it off DTDLogLevel.No
. Use DTDLogLevel.No
in the release version.
Example:
Find the DevToDev.Analytics
package using the package manager search engine and click Install. The latest version of the package is recommended.
Initialize the library using the following code:
You can find the App ID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- is a DTDAnalyticsConfiguration
object instance that is used for specifying additional properties during initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
currentLevel
Integer
The player level at the moment of devtodev SDK initialization. It’s optional but we recommend using it for improving data accuracy.
userId
String
A custom user ID assigned by the developer. In the case of default calculation by device IDs, the identifier can be used for searching users in devtodev. In case the project uses calculation by user IDs, the parameter is mandatory because it becomes the principal calculation ID in devtodev.
trackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.Enabl
e
. SDK stores the previously assigned value. Pass DTDTrackingStatus.Disable
if the user opted out of tracking in line with GDPR.
logLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.No
value is used by default. For troubleshooting during integration, it is recommended to set it to DTDLogLevel.Debug
, and either switch it off DTDLogLevel.No
or use it only for error handling DTDLogLevel.Error
in the release version.
ApplicationVersion
String
The app version during the devtodev SDK initialization. It is recommended that you set the app version before the initialization to make the collection of app version statistics more precise.
Example:
The SDK can’t control app activity hence this responsibility is passed on to the developer. During the SDK initialization, the activity is triggered automatically, and later the activity status will not change automatically. For tracking app activity, the developer can use the DTDAnalytics.StartActivity
and DTDAnalytics.StopActivity
methods. It is recommended that you use the DTDAnalytics.StopActivity
method to stop the activity when the app goes into the background or being closed. If the window is re-opened from the taskbar it is recommended to renew the activity by using the DTDAnalytics.StartActivity
method.
CocoaPods is the easiest way to add devtodev into your iOS project.
1. Firstly, install CocoaPods using:
2. In the project directory execute the command:
3. In the created Podfile add the dependency:
4. Finally, run the command in your Xcode project directory:
CocoaPods should download and install the devtodev library, and create a new Xcode workspace. Open this workspace in Xcode.
1. Download the latest version of devtodev SDK from the repository
2. Add DTDAnalytics.xcframework
to the project
3. Add frameworks:
AppTrackingTransparency.framework
AdSupport.framework
4. Add initialization todidFinishLaunchingWithOptions
method:
An App ID can be found in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- an object instance of DTDAnalyticsConfiguration
, which is used for specifying additional properties during the initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
currentLevel
int
The player level at the moment of devtodev SDK initialization. It is recommended (but optional) to use to improve data precision.
userId
string
A custom user identifier provided by the developer. If you utilize the default calculation by the device ID, this identifier can be used for finding a user in devtodev.
In case your project utilizes the calculation by the user identifier, you must set this parameter because it becomes the main user identifier in devtodev.
trackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.enable
. SDK stores the previously assigned value. Pass DTDTrackingStatus.disable
if the user opted out of tracking in line with GDPR.
logLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.no
value is used by default. For troubleshooting during integration it is recommended to set it to DTDLogLevel.debug
, and either switch it off DTDLogLevel.no
. Use DTDLogLevel.no
in the release version.
Example:
Create Bridging-Header. To do this, you need to add any swift file to the project (don’t delete it later) and choose ‘Create Bridging Header’ in the offered dialog box.
Make sure that the ‘Build Settings’ for ‘Defines Module’ value evaluates to ‘YES’.
While importing, use: #import <DTDAnalytics/DTDAnalytics-Swift.h>
For SDK to function properly, it needs to be integrated at the earliest moment of the app launch. It is recommended that you use the following method of main entry point initialization:
When developing and publishing apps targeted at children under 13 years old, you need to ensure special conditions for data processing. Any mobile app aimed at children or intended for users in a region with strict regulations on child online protection, must comply with current laws.
Please study the following requirements:
If your app has to comply with the legal requirements (COPPA), use the following recommendations:
Implement the coppaControlEnable
method. The method disables collection of ad IDs and vendor IDs (IDFA, IDFV).
To comply with Apple’s guidelines
Remove AppTrackingTransparency.framework
and all the links pointing to it.
Remove AdSupport.framework
all the links pointing to it.
Call the coppaControlEnable
method before SDK initialization. If the method was not called, the SDK will work as before.
The Privacy Manifest is a new way introduced at WWDC23 for third-party SDK developers to provide information about their privacy policies.
The Privacy Manifest describes the methods for ensuring code confidentiality in the application in a unified format. When publishing the application, Xcode will combine the privacy manifests of all third-party SDKs used in your application into a single, convenient report. This report makes it easier to create more accurate privacy labels (Nutrition Labels).
The Privacy Manifest includes the following sections for data entry:
Privacy Tracking Enabled
Privacy Tracking Domains
Privacy Nutrition Label Types
Privacy Accessed API Types
Privacy Tracking Enabled. A Boolean value indicating whether the application or third-party SDK uses data for tracking, as defined within the App Tracking Transparency framework.
Privacy Tracking Domains. An array of strings listing the internet domains that the application or third-party SDK connects to and participates in tracking.
Privacy Nutrition Label Types. An array of dictionaries describing the types of data collected by the application or third-party SDK. Nutrition Labels are needed to let users know what data the application collects before installing it from the App Store.
Privacy Accessed API Types. An array of dictionaries describing the types of APIs accessed by the application or third-party SDK, which are marked as APIs and require verification for access.
Privacy Nutrition Label Types
Product Interaction
No
No
Analytics
Device ID
No
No
Analytics
User ID
No
No
Analytics
Purchase History
No
No
Analytics
Other Data Types
No
No
Analytics
Privacy Accessed API Types
User Defaults
CA92.1: Access info from same app, per documentation
Privacy Nutrition Label Types
Device ID
No
No
Analytics
Other Data Types
No
No
Analytics
Privacy Accessed API Types
User Defaults
CA92.1: Access info from same app, per documentation
Since we distribute our SDKs as binary dependencies, we have implemented a signing practice. Now, when you use a new version of the SDK, Xcode will confirm that it has been signed by us, increasing the integrity of the software supply chain.
The SDK is available in GitHub repository. Download the Source code (zip) of latest release. Unzip the archive and copy DTDAnalytics folder to the Plugins folder of your project.
For a C++ project type, add the DTDAnalytics
name to the list of dependency module names to the <module_name>.Build.cs file of the module in which you plan to use the plugin.
Example:
A class that implements analytic methods.
Header file:
A class that implements user card methods.
The class header:
SDK tracking status.
Header file:
Values:
Unknown = 0
- leave tracking unchanged
Enable = 1
- tracking enabled
Disable = 2
- tracking disabled
Example:
SDK logging level.
Header file:
Values:
Unknown = 0
- leave logging level unchanged
No = 1
- logging disabled
Error = 2
- logging of errors
Warning = 3
- logging of warnings and errors
Info = 4
- logging of information messages, warnings and errors
Debug = 5
- logging of debugging messages, informational messages, warnings and errors
Example:
Types of resource accumulation.
Header file:
Values:
Earned = 0
- earned resources
Bought = 1
- purchased resources
Example:
Predefined social media.
Header file:
Values:
Facebook = 0
Vkontakte = 1
Twitter = 2
Googleplus = 3
Whatsapp = 4
Viber = 5
Evernote = 6
Googlemail = 7
Linkedin = 8
Pinterest = 9
Reddit = 10
Renren = 11
Tumblr = 12
Qzone = 13
Example:
User gender.
Header file:
Values:
Unknown = 0
Male = 1
Female = 2
Example:
Referral properties.
Header file:
Values:
Source = 0
Medium = 1
Content = 2
Campaign = 3
Term = 4
Example:
An optional parameter of int32 type
Header file:
HasValue
bool
Option label
Value
int32
Parameter value
For your convenience, we implemented the conversion constructor:
Example:
An optional parameter of FString type.
Header file:
HasValue
bool
Option label
Value
FString
Parameter value
For your convenience, we implemented the conversion constructor:
Example:
Configuration of the analytics plugin.
Header file:
LogLevel
EDTDLogLevel
Logging level
CurrentLevel
FDTDOptionalInt32
Current level
UserId
FDTDOptionalString
User ID
ApplicationVersion
FDTDOptionalString
Application version (Windows)
TrackingAvailability
EDTDTrackingStatus
Tracking settings
Example:
Custom parameters of a custom event.
Header file:
StringParameters
TMap<FString, FString>
String parameters
IntParameters
TMap<FString, int64>
Integer parameters
FloatParameters
TMap<FString, float>
Real parameters (floating-point numbers)
BoolParameters
TMap<FString, bool>
Boolean parameters
Warning: avoid duplicating keys in parameters of different types, because in native code dictionaries are merged into a single dictionary [string: any].
Example:
Parameters of the progression start event.
Header file:
Difficulty
FDTDOptionalInt32
Difficulty
Source
FDTDOptionalString
Source
Example:
Parameters of the progression completion event.
Header file:
SuccessfulCompletion
bool
Successful completion of the progression (‘false’ by default)
Duration
int32
Duration (if 0, duration is calculated automatically)
Spent
TMap<FString, int64>
Resources spent
Earned
TMap<FString, int64>
Resources earned
Example:
Header file:
Definitions:
appKey
FString
You can find it in the settings of the corresponding application in devtodev (Settings → SDK → Integration → Credentials)
appKey
FString
You can find it in the settings of the corresponding application in devtodev (Settings → SDK → Integration → Credentials)
config
FDTDAnalyticsConfiguration
Initialization parameters
Get response about a completed transaction from the payment system.
Either send data about the received transaction for verification by calling devtodev anti-cheat methods or use your own tools for transaction verification.
If the transaction has successfully passed verification, perform the Payment event.
If the transaction hasn’t passed verification, do not perform the Payment event and mark the user as a cheater.
The devtodev service allows you to validate transactions to prevent fraud from influencing your statistics. For this, you need to integrate DTDAntiCheat
module.
We strongly discourage you from using verification results for deciding on allowing or denying users to receive their purchases! Employ this method exclusively for preventing fraud transaction data from being sent to devtodev!
To validate the transaction you can use the verifyPayment(completionHandler: @escaping (DTDVerifyResponse) -> Void)
method immediately during the transaction processing, e.g.:
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid
or receiptSandbox
as a result of the validation.
To validate the transaction you can use the (void)verifyPaymentCompletion:( void (^ _Nonnull)(DTDVerifyResponse * _Nonnull))completionHandler;
method immediately during the transaction processing, e.g.:
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid
or receiptSandbox
as a result of the validation.
When GooglePlay sends the transaction back to your onActivityResult
, validate it by calling the following method: verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit)
immediately during the transaction processing, e.g.:
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid
as a result of the validation.
When GooglePlay sends the transaction back to your onActivityResult
, validate it by calling the following method: verifyPayment(receipt: String, signature: String, publicKey: String, completionHandler:(DTDVerifyResponse) -> Unit)
immediately during the transaction processing, e.g.:
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid
as a result of the validation.
Example of verification:
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive Invalid
as a result of the validation.
If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string publicKey, string receipt, Action completionHandler)
Example:
To validate data received from Google play, use void VerifyPayment(string publicKey, string receipt, string signature,Action<DTDVerifyResponse> completionHandler)
when handling the transaction.
Here's how to find your app's public key for licensing (for Google Play platform only, for other platforms the publicKey is not used):
Go to the Google Play Console and sign in. Make sure that you sign in to the account from which the app you are licensing is published (or will be published).
In the app details page, locate the Services & APIs link and click it.
In the Services & APIs page, locate the Licensing & In-App Billing section. Your public key for licensing is given in the Your License Key For This Application field.
If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string receipt, Action completionHandler)
If you use Unity IAP for payment validation, call the following method: void VerifyPayment(string receipt, Action completionHandler)
N.B. You can pass a native XML recipe to the receipt argument.
DTDVerifyResponse
The DTDVerifyResponse object returned while validating the transaction has two properties:
DTDReceiptStatus
The enum type returned as a result of validation can receive the following values:
We recommend calling the Real Currency Payment method in all cases except when you receive receiptNotValid
or receiptSandbox
as a result of the validation.
1. Download the latest version of devtodev SDK from the repository
2. Add DTDAnalytics.xcframework
to the project (with Do Not Embed specified)
3. Add frameworks:
AppTrackingTransparency.framework
AdSupport.framework
4. Add initialization todidFinishLaunchingWithOptions
method:
An App ID can be found in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- an object instance of DTDAnalyticsConfiguration
, which is used for specifying additional properties during the initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
currentLevel
int
The player level at the moment of devtodev SDK initialization. It is recommended (but optional) to use to improve data precision.
userId
string
A custom user identifier provided by the developer. If you utilize the default calculation by the device ID, this identifier can be used for finding a user in devtodev.
In case your project utilizes the calculation by the user identifier, you must set this parameter because it becomes the main user identifier in devtodev.
trackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.enable
. SDK stores the previously assigned value. Pass DTDTrackingStatus.disable
if the user opted out of tracking in line with GDPR.
logLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.no
value is used by default. For troubleshooting during integration it is recommended to set it to DTDLogLevel.debug
, and either switch it off DTDLogLevel.no
. Use DTDLogLevel.no
in the release version.
Example:
Create Bridging-Header. To do this, you need to add any swift file to the project (don’t delete it later) and choose ‘Create Bridging Header’ in the offered dialog box.
Make sure that the ‘Build Settings’ for ‘Defines Module’ value evaluates to ‘YES’.
While importing, use: #import <DTDAnalytics/DTDAnalytics-Swift.h>
For SDK to function properly, it needs to be integrated at the earliest moment of the app launch. It is recommended that you use the following method of main entry point initialization:
When developing and publishing apps targeted at children under 13 years old, you need to ensure special conditions for data processing. Any mobile app aimed at children or intended for users in a region with strict regulations on child online protection, must comply with current laws.
Please study the following requirements:
If your app has to comply with the legal requirements (COPPA), use the following recommendations:
Implement the coppaControlEnable
method. The method disables collection of ad IDs and vendor IDs (IDFA, IDFV).
To comply with Apple’s guidelines
Remove AppTrackingTransparency.framework
and all the links pointing to it.
Remove AdSupport.framework
all the links pointing to it.
Call the coppaControlEnable
method before SDK initialization. If the method was not called, the SDK will work as before.
If you have previously used the Unity SDK version 2+, you need to delete the following files and folders in the "Assets" folder of your project:
To integrate devtodev analytics SDK, you can use one of the two methods: by using the Unity Package Manager (recommended) or by manually importing the unitypackage.
If you integrated the devtodev package manually, then you need to delete the Assets/DevToDev and Plugins/DevToDev folders.
Open the Package Manager (Window → Package Manager), click + in the top left corner and select Add package from git URL.
Copy the repository URL https://github.com/devtodev-analytics/package_Analytics.git to the input box and click Add.
Wait for the Unity Package Manager to download the package.
If you work with SDK version 3.5.0 and above, and you want to use Google Ad ID, you need to add devtodev-analytics/package_Google. When developing and publishing apps for kids (COPPA), you do not need devtodev-analytics/package_Google. Read more about working with COPPA in the COPPA section.
If you work with SDK version 3.5.0 and above, and you want to use Huawei Ad ID, you need to add https://github.com/devtodev-analytics/package_Huawei.git. When developing and publishing apps for kids (COPPA), you do not need https://github.com/devtodev-analytics/package_Huawei.git. Read more about working with COPPA in the COPPA section.
You can pick a specific SDK version by adding # and a version number at the end of the URL, for example: https://github.com/devtodev-analytics/package_Analytics.git#v3.3.2
Download DTDAnalytics.unitypackage from http://github.com/devtodev-analytics/Unity-sdk-3.0/releases/latest
In the Unity Editor menu, open Assets → Import Package → Custom Package
Select the DTDAnalytics.unitypackage that you have just downloaded
Click Import
If you work with SDK version 3.5.0 and above, and you want to use Google Ad ID, you need to import the DTDGoogle.unitypackage. When developing and publishing apps for kids (COPPA), you do not need the DTDGoogle.unitypackage. Read more about working with COPPA in the COPPA section.
If you work with SDK version 3.5.0 and above, and you want to use Huawei Ad ID, you need to import the DTDHuawei.unitypackage. When developing and publishing apps for kids (COPPA), you do not need the DTDHuawei.unitypackage. Read more about working with COPPA in the COPPA section.
Create a script with the following code and attach it to the GameObject
that will survive the entire life cycle of the app.
You can find the AppID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- an object instance of DTDAnalyticsConfiguration
, which is used for specifying additional properties during the initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
CurrentLevel
Integer
The player level at the moment of devtodev SDK initialization. It’s optional but we recommend using it for improving data accuracy.
UserId
String
A custom user ID assigned by the developer. In the case of default calculation by device IDs, the identifier can be used for searching users in devtodev. In case the project uses calculation by user IDs, the parameter is mandatory because it becomes the principal calculation ID in devtodev.
TrackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.Enable
. SDK stores the previously assigned value. Pass DTDTrackingStatus.Disable
if the user opted out of tracking in line with GDPR.
LogLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.no
value is used by default. For troubleshooting during integration it is recommended to set it to DTDLogLevel.Debug
, and either switch it off DTDLogLevel.No
. Use DTDLogLevel.No
in the release version.
ApplicationVersion
String
The app version during the devtodev SDK initialization. Use the property on the WinStandalone platform only. For all other platforms, data is collected automatically.
Example:
SDK Activity
The SDK can’t control app activity in case you use Windows Standalone therefore this responsibility is shifted to the developer. While initializing the SDK, the activity starts automatically and after that, the activity status will not auto-change. To track app activity, the developer can use the following methods: DTDAnalytics.StartActivity
and DTDAnalytics.StopActivity
. It is recommended to use the DTDAnalytics.StopActivity
method to stop activity when the app goes into the background or gets closed. You can use the DTDAnalytics.StartActivity
method to resume activity when the app gets reopened from the taskbar.
For other platforms, there is no need to manually call the DTDAnalytics.StartActivity
and DTDAnalytics.StopActivity
methods.
In the version 2019.2, the Executable Only option was added to the Build Type. This option is incompatible with the SDK because the SDK needs access to the project file in order to register the DevToDev.Background
service.
To resolve external android dependencies, you need to use External Dependency Manager for Unity.
Add the following strings to proguard.txt (read more about Unity proguard here):
Select your project in https://developer.huawei.com/consumer/en/service/josp/agc/index.html#/myProject In the “General information” section find “App information” and download the “agconnect-services.json“ file.
If you imported the DTDGoogle package, delete the imported files Assets\Plugins\DevToDev\Android\DTDGoogleAndroid.dll and Assets\DevToDev\Analytics\Editor\GoogleDependencies.xml
Import the DTDHuawei.unitypackage manually from GitHub or use Unity Package Manager with DTDHuawei package.
In the assets/Plugins/Android/ folder create a settingsTemplate.gradle file with the following content:
Open Window → devtodev and select Create android plugin folder
Copy the “agconnect-services.json“ file to the Assets\Plugins\Android\devtodev.plugin folder
Open Assets → External Dependency Manager → Android ResolverAssets → External Dependency Manager → Android Resolver and click Resolve
To proguard add the following rule:
To integrate with Xcode, the SDK uses PostProcessBuild
in the DTDPostProcessAnalytics
and DTDPostProcessMessaging
scripts. If you use custom PostProcessBuild
scripts, add them callbackOrder
of less than 98
to avoid conflicts.
Your app must request tracking authorization before it can get the advertising identifier. See the detailed instruction on how to request it.
If you want to disable tracking of advertising identifiers, you need to open the DTDPostProcesssAnalytics.cs file and comment out the line 39: project.AddFrameworkToProject(targetGuid, "AppTrackingTransparency.framework", true);
At WWDC23 Apple introduced new privacy manifests and xcframework signature. More information about it can be found here.
When developing and publishing apps targeted at children under 13 years old, you need to ensure special conditions for data processing. Any mobile app aimed at children or intended for users in a region with strict regulations on child online protection, must comply with current laws.
Please study the following requirements:
If your app has to comply with the legal requirements (COPPA), use the following recommendations:
Implement the CoppaControlEnable
method. The method disables collection of ad IDs and vendor IDs (IDFA, IDFV).
To comply with Apple’s guidelines, remove from Xcode project:
AppTrackingTransparency.framework
and all the links pointing to it.
AdSupport.framework
and all the links pointing to it.
Set IS_COPPA_ENABLED = true
in DTDPostProcessAnalytics.cs
(Assets/DevToDev/Analytics/Editor
)
Implement the CoppaControlEnable
method. The method disables collection of ad IDs and vendor IDs.
If you are using DTDGoogle or DTDHuawei from Unity Package Manager, disable it.
If you are using DTDGoogle.unitypackage, remove the following files:
If you are using DTDHuawei.unitypackage, remove the following files:
Call the CoppaControlEnable
method before SDK initialization. If the method was not called, the SDK will work as before.
The DevToDev SDK extends the Godot engine in a modular way and supports platforms: MacOS, iOS, Android.
Godot engine 4.0+ ()
.
build system.
SDK module source code ()
The SDK module is available in . Download the Source code of latest release and copy d2d_analytics folder to the modules(/godot/modules/
) folder of Godot engine source code.
To work in the Godot editor, compile the engine source code and the analytics module:
For initialization, add the following code at the start of your application:
You can find the AppID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- an object instance of GDDTDAnalyticsConfiguration
, which is used for specifying additional properties during the initialization
Example:
Open the Export Template Manager to download and install templates:
The next step is to prepare a custom template as a macos.zip archive. Don't forget to add the DTDAnalytics native library, copy libDTDAnalytics.dylib
to macos_template.app/Contents/MacOS/
.
Open the Export menu and specify the path to the prepared custom template:
Open the Export Template Manager to download and install templates:
The next step is to prepare a custom template as an ios.zip archive. Don't forget to add the DTDAnalytics native library, copy DTDAnalytics.xcframework
to ios_xcode/
.
In XCode project:
Add DTDAnalytics.xcframework
to the project (with Do Not Embed specified)
Create Bridging-Header. To do this, add any swift file to the project (don't delete it later) and select 'Create Bridging Header' in the dialogue box that appears.
Add frameworks:
AppTrackingTransparency.framework
AdSupport.framework
Сlick to install android templates:
After installing the template, an android folder will appear in your project.
Move the d2d_analytics/native/androidAnalytics.aar
to the android/plugins/ folder
in your project. You will also need to create an Analytics.gdap
file in android/plugins/
with the following content:
Next, Analytics should appear in the Plugins section, check it out:
After successful compilation execute the following commands:
In the next step in godot-4.0-stable/bin
you will see godot-lib.template_debug.aar
or
godot-lib.template_relaese.aar
.
You need to copy and replace this file to the previously installed template in your project at the path:
appName/android/build/libs/debug
- for debugging
appName/android/build/libs/release
- for release
After these steps, you are ready to export your Android app.
Make sure that Use Gradle Build
(in the Gradle Build section), Analytics
(in the Plugins section) and the previously compiled Architecture
(in the Architectures section) are selected.
The event is used for individual tracking of ad revenue on user devices. The method is used if there are CPI data available on the client device (they can be obtained from the ad network SDK).
Do not apply this method if you use ad networks that utilize the server-server protocol for sending ad revenue data (ironSource, AppLovin MAX, and Fyber networks) and you already set up this method of data collection because if you use both data sources, your revenue data may be duplicated.
The event is used to track connections to social media channels.
Use the following constants to specify a social network:
.facebook, .vkontakte , .twitter, .googleplus, .whatsapp, .viber, .evernote, .googlemail, .linkedin, .pinterest, .qzone, .reddit, .renren, .tumblr
Or create an object with the desired social media name.
Use the following constants to specify a social network:
.facebook, .vkontakte , .twitter, .googleplus, .whatsapp, .viber, .evernote, .googlemail, .linkedin, .pinterest, .qzone, .reddit, .renren, .tumblr
Or create an object with the desired social media name.
Use the following constants to specify a social network:
DTDSocialNetwork.facebook, DTDSocialNetwork.vkontakte , DTDSocialNetwork.twitter, DTDSocialNetwork.googleplus, DTDSocialNetwork.whatsapp, DTDSocialNetwork.viber, DTDSocialNetwork.evernote, DTDSocialNetwork.googlemail, DTDSocialNetwork.linkedin, DTDSocialNetwork.pinterest, DTDSocialNetwork.qzone, DTDSocialNetwork.reddit, DTDSocialNetwork.renren, DTDSocialNetwork.tumblr
Or create an object with the desired social media name.
Use the following constants to specify a social network:
DTDSocialNetwork.Companion.getFacebook(), DTDSocialNetwork.Companion.getVkontakte(), DTDSocialNetwork.Companion.getTwitter(), DTDSocialNetwork.Companion.getGoogleplus(), DTDSocialNetwork.Companion.Whatsapp(), DTDSocialNetwork.Companion.getViber(), DTDSocialNetwork.Companion.getEvernote(), DTDSocialNetwork.Companion.getGooglemail(), DTDSocialNetwork.Companion.getLinkedin(), DTDSocialNetwork.Companion.getPinterest(), DTDSocialNetwork.Companion.getQzone(), DTDSocialNetwork.Companion.getReddit(), DTDSocialNetwork.Companion.getRenren(), DTDSocialNetwork.Companion.getTumblr()
Or create an object with the desired social media name.
Use the following constants to specify a social network:
DTDSocialNetwork.facebook, DTDSocialNetwork.vkontakte , DTDSocialNetwork.twitter, DTDSocialNetwork.googleplus, DTDSocialNetwork.whatsapp, DTDSocialNetwork.viber, DTDSocialNetwork.evernote, DTDSocialNetwork.googlemail, DTDSocialNetwork.linkedin, DTDSocialNetwork.pinterest, DTDSocialNetwork.qzone, DTDSocialNetwork.reddit, DTDSocialNetwork.renren, DTDSocialNetwork.tumblr
Or create an object with the desired social media name:
Use the following constants to specify a social network:
DTDSocialNetwork.facebook, DTDSocialNetwork.vkontakte , DTDSocialNetwork.twitter, DTDSocialNetwork.googleplus, DTDSocialNetwork.whatsapp, DTDSocialNetwork.viber, DTDSocialNetwork.evernote, DTDSocialNetwork.googlemail, DTDSocialNetwork.linkedin, DTDSocialNetwork.pinterest, DTDSocialNetwork.qzone, DTDSocialNetwork.reddit, DTDSocialNetwork.renren, DTDSocialNetwork.tumblr
Or create an object with the desired social media name:
Or use special method for custom social network:
Use the following constants to specify a social network:
.facebook, .vkontakte , .twitter, .googleplus, .whatsapp, .viber, .evernote, .googlemail, .linkedin, .pinterest, .qzone, .reddit, .renren, .tumblr
Or create an object with the desired social media name.
Track social media posts and analyze their effectiveness and virality. Pass the event after the post has been approved by social media.
If you have referral information, you can pass it using the following method:
To send an event packet before it is full (10 events, by default) or before the end of the period of its formation (2 minutes, by default), you can use immediate dispatch.
We don’t recommend using this method unless absolutely necessary! When the Real payment event is created, the forced dispatch of the packet occurs automatically.
When working with getters you should take into account that the new devtodev SDK is completely asynchronous. The execution result must be processed within the completionHandler
.
All set and get methods need to be called only after the initialization of the SDK.
It is also worth remembering that the SDK will call the callback in background queues, so we recommend that you transfer the processing of return values to the queue you need.
For example:
This method denies/allows tracking of user data and also implements the right to be forgotten in accordance with the requirements of the GDPR.
When this method is called with the 'false' value, the SDK sends a command to the server to delete all personal user data that was collected by devtodev in this application, blocking further user data collection.
The user will remain in the devtodev system only as an impersonal unit in the previously aggregated metrics.
If it is set to ‘true', tracking can be enabled again. In this case, the user will be considered new.
To enable/disable user tracking by the devtodev system. Bool type.
Get device ID. String type.
Get the version of the integrated devtodev SDK. String type.
Retrieving the saved state of the user tracking permission by the devtodev system. See “Setting User Tracking Status”. Bool type.
devtodev ID is the primary numeric identifier for the device/user account in the devtodev database. Using devtodev ID, you are sure to find the user in devtodev.
The identifier will be received from the server some time after the initialization of the SDK.
If you have set counting by users, a separate devtodev id will be issued for each device user.
To obtain the devtodev ID, you need to pass the listener to DTDAnalytics
:
The delegate must implement the func didReceiveDevtodevId(with devtodevId: Int)
The didReceiveDevtodevId
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the listener to DTDAnalytics
:
The delegate must implement the (void)didReceiveDevtodevIdWith:(NSInteger)devtodevId;
The didReceiveDevtodevId
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the DTDIdentifiersListener
listener to DTDAnalytics
:
The didReceiveDevtodevId
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the DTDIdentifiersListener
listener to DTDAnalytics
:
The didReceiveDevtodevId
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the DTDIdentifiersListener
listener delegate to DTDAnalytics
:
The delegate
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the DTDIdentifiersListener
listener delegate to DTDAnalytics
:
The delegate
method will be called with every ID change on the server side.
To obtain the devtodev ID, you need to pass the Callable
to DTDAnalytics
:
The didReceiveDevtodevId
method will be called with every ID change on the server side.
To receive a callback when the SDK initialization is complete, you can use a method that will implement the initialization callback. When the SDK completes the initialization, the callback will be called on the main application thread.
We recommend implementing a callback before calling initialization.
devtodev sends a request for transaction verification to the payment platform and then forwards the answer to the app.
To validate the transaction you can use theTask<DTDReceiptStatus> VerifyPayment(string: receipt)
method. As an argument pass the PurchaseResults.ReceiptXml
property. More information about it .
Open a terminal, go to the root directory of the engine source code. Compile a custom template for MacOS (see for MacOS), select Debug or Release build and processor architecture. To support both architectures in a single Universal 2 binary, use lipo:
Open a terminal, go to the root directory of the engine source code. And compile a custom template for iOS (see for iOS). To work with the iOS simulator, compile the sources with the ios_simulator=yes
flag. To support both architectures in a single Universal 2 binary, use lipo:
The next step is to compile the Godot engine for Android (see ), choose debug or release build, and select the processor architecture.
Parameter
Type
Description
CurrentLevel
Integer
The player level at the moment of devtodev SDK initialization. It’s optional but we recommend using it for improving data accuracy.
UserId
String
A custom user ID assigned by the developer. In the case of default calculation by device IDs, the identifier can be used for searching users in devtodev. In case the project uses calculation by user IDs, the parameter is mandatory because it becomes the principal calculation ID in devtodev.
TrackingAvailability
GDDTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to GDDTDTrackingStatus.Enable
. SDK stores the previously assigned value. Pass GDDTDTrackingStatus.Disable
if the user opted out of tracking in line with GDPR.
LogLevel
GDDTDLogLevel (enum)
The level of logging the SDK activity. The GDDTDLogLevel.No
value is used by default. For troubleshooting during integration it is recommended to set it to GDDTDLogLevel.Debug
, and either switch it off GDDTDLogLevel.No
. Use GDDTDLogLevel.No
in the release version.
Property
Description
receiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
verificationResult
Additional information from the validation server.
Value
Description
receiptValid
The payment is valid, the transaction is genuine.
receiptNotValid
The payment is invalid, the transaction may be a duplicate or fraud.
receiptServerError
Server error when validating the payment.
receiptSandbox
Test payment.
receiptInternalError
Internal SDK error.
Property
Description
receiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
verificationResult
Additional information from the validation server.
Value
Description
receiptValid
The payment is valid, the transaction is genuine.
receiptNotValid
The payment is invalid, the transaction may be a duplicate or fraud.
receiptServerError
Server error when validating the payment.
receiptSandbox
Test payment.
receiptInternalError
Internal SDK error.
Property
Description
receiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
verificationResult
Additional information from the validation server.
Value
Description
receiptValid
The payment is valid, the transaction is genuine.
receiptNotValid
The payment is invalid, the transaction may be a duplicate or fraud.
receiptServerError
Server error when validating the payment.
receiptInternalError
Internal SDK error.
Property
Description
receiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
verificationResult
Additional information from the validation server.
Value
Description
receiptValid
The payment is valid, the transaction is genuine.
receiptNotValid
The payment is invalid, the transaction may be a duplicate or fraud.
receiptServerError
Server error when validating the payment.
receiptInternalError
Internal SDK error.
Property
Description
ReceiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
VerificationResult
Additional information from the validation server.
Value
Description
Valid = 0L
The payment is valid, the transaction went through successfully
Invalid = 1L
The payment is invalid, the transaction may be a duplicate or fraud
ServerError = 2L
Server error when validating the payment
InternalError = 4L
Internal SDK error
Property
Description
receiptStatus
Enum type DTDReceiptStatus
that represents the result of the transaction validation.
verificationResult
Additional information from the validation server.
Value
Description
receiptValid
The payment is valid, the transaction is genuine.
receiptNotValid
The payment is invalid, the transaction may be a duplicate or fraud.
receiptServerError
Server error when validating the payment.
receiptSandbox
Test payment.
receiptInternalError
Internal SDK error.
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Double
from 0,0 to Double.max
Reward for banner display in USD
placement
String?
from 1 to 100 symbols, optional
Banner placement
unit
String?
from 1 to 100 symbols, optional
Banner name
network
NSString
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
double
from 0,0 to Double.max
Reward for banner display in USD
placement
NSString _Nullable
from 1 to 100 symbols, optional
Banner placement
unit
NSString _Nullable
from 1 to 100 symbols, optional
Banner name
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Double
from 0,0 to Double.max
Reward for banner display in USD
placement
String?
from 1 to 100 symbols, optional
Banner placement
unit
String?
from 1 to 100 symbols, optional
Banner name
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Double
from 0,0 to Double.max
Reward for banner display in USD
placement
String?
from 1 to 100 symbols, optional
Banner placement
unit
String?
from 1 to 100 symbols, optional
Banner name
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Double
from 0,0 to Double.max
Reward for banner display in USD
placement
String?
from 1 to 100 symbols, optional
Banner placement
unit
String?
from 1 to 100 symbols, optional
Banner name
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Double
from 0,0 to Double.max
Reward for banner display in USD
placement
String?
from 1 to 100 symbols, optional
Banner placement
unit
String?
from 1 to 100 symbols, optional
Banner name
Parameter
Type
Restrictions
Description
socialNetwork
FString
from 1 to 100 symbols
The name of the ad network that delivered the impression.
revenue
float
form 0.0 to float.MaxValue
Reward for displaying a banner in USD.
placement
FString
from 1 to 100 symbols
Placement of the banner.
unit
FString
from 1 to 100 symbols
Banner title.
network
String
from 1 to 100 symbols
Name of the ad network responsible for the impression
revenue
Float
from 0,0 to Double.max
Reward for banner display in USD
placement
String
from 1 to 100 symbols, optional
Banner placement
unit
String
from 1 to 100 symbols, optional
Banner name
Argument
Type
Description
socialNetwork
EDTDSocialNetwork
Predefined social network.
Argument
Type
Description
socialNetwork
FString
Custom social network.
Argument
Type
Description
socialNetwork
EDTDSocialNetwork
Predefined social network.
Argument
Type
Description
socialNetwork
FString
Custom social network.
Argument
Type
Description
utmData
TMap<EDTDReferralProperty, FString>
UTM data.
Argument
Type
Description
onResult
FAnalyticsDynamicGetterStringDelegate
FDTDGetterStringDelegate
Callback.
Argument
Type
Description
onResult
FAnalyticsDynamicGetterStringDelegate
FDTDGetterStringDelegate
Callback.
Argument
Type
Description
onResult
FAnalyticsDynamicGetterStringDelegate
FDTDGetterStringDelegate
Callback.
Argument
Type
Description
onResult
FAnalyticsDynamicGetterBoolDelegate
FDTDGetterBoolDelegate
Callback.
Argument
Type
Description
listener
FAnalyticsDynamicGetterLongDelegate
FDTDGetterLongDelegate
devtodev ID Listener.
Session Measurement and Tracking in Mobile and Web Applications
Session measurement is an important metric for product analysis as it allows us to determine how frequently and for how long users interact with our website or application. However, it is important to note that session tracking methods on mobile and web applications have their own peculiarities. When a user starts a session in the application, the SDK recognizes that the application is active, indicating that it has gained focus (when the app is brought into the foreground). If the last recorded activity was more than 10 minutes ago, a Session Start event is sent.
Application activity refers to the period of time when the application is in focus, meaning the application or web page is open and the device screen is active. The focus is lost if the application goes into the background or if another website is opened in the current tab.
We measure the duration of application activity using a technical event called User Engagement (UE). It starts counting the time as soon as the application receives focus and sends the activity counter data to the server.
If, for any reason, the information about the duration of the activity couldn't be sent, it will be sent the next time the application is initialized and has internet access. However, the activity will only be included in devtodev reports if it has been less than 7 days since the session, as events from a previous period more than 7 days ago are ignored.
Thus, we have information about "Session start" and the duration of activity, but there is no specific "Session end" event. All events performed by the user are marked with the session start date in which they occurred (sessionid field in SQL tables)
For mobile applications, it is difficult to determine the beginning and end of a session because users often switch between screens of different applications. If an application on a mobile device receives focus and the last active time (in focus) was more than 10 minutes ago, a new session will be started and an event will be sent to devtodev.
For example, the user opens the application, spends a minute in it, and then puts the application in the background, a Session Start event will be sent to devtodev in the first second. After a minute, when the application goes into the background or is closed, an event with information about the duration of activity (UE) will be sent to the server as the focus is lost.
For web projects, it is not possible to detect when the user closes the page. Therefore, the UE event (duration of activity) is sent to the server every 2 minutes. To minimize the loss of information about the session duration to no more than two minutes in case of session termination, the SDK additionally saves the duration every 5 seconds and will send the information about the last duration upon the next activity. If there is no next session, the information about the last two minutes may be lost.
Let's consider an example where a user opens a webpage, spends 1.5 minutes on it, then opens another page on the site and spends another 1.5 minutes there. In devtodev, a Session Start event will be sent in the first second, and every 5 seconds, information about the activity will be saved. After 2 minutes from the start of the session, a UE event with 2 minutes of activity will be sent to the server, and after the third minute, the activity of 1 minute will be recorded in the Local Storage. Information about this activity will be sent during the next user session. The metric Average session length is calculated from the data obtained from session starts and user activity time during those sessions. It is defined as the sum of the length of all sessions divided by the number of sessions within a given period
In Basic Metrics, Engagement-> Sessions, and other reports, we encounter the following metrics:
Session duration: Shows the average session time of one user. It is calculated as (Total Sessions Length / Number of sessions) averaged by users Number of sessions: Shows the average number of sessions per user. It is calculated as the Number of sessions divided by the Number of users Total daily time spent: Represents the average total time per day spent in the user application. It is calculated as Total Sessions Length divided by the number of Active Users Sessions: Sessions by user shows the average number of sessions made by one user during the period Sessions by user: It shows the average number of sessions made by one user during the period
For the calculation of the necessary metrics:
In the SQL wizard, there is a parameter called session.Duration, which is tracked by the UE event. The session.Duration parameter represents the duration of the activity, i.e., the time the application is in focus, and it is not equal to the session duration.
sessions.Count is the number of Session Start received from the user
Table .sessions has two types of eventtype field in SQL: ss: represents the Session Start event received from the user ue: represents the time that the application was in focus (active), providing information about time parameters and activity duration.
From this data, you can calculate the average session length by dividing the sum of activity lengths from all rows for the desired period by the sum of all session starts for the same period. We recommend using extended time periods to obtain a more reliable result.
The SDK is available as an AAR (recommended) and JAR library. The library is available in the MavenCentral and GitHub repository.
Attention!
From the SDK version com.devtodev:android-analytics:'2.2.3'
and above you need to add com.devtodev:android-google:'1.0.0'.
This framework encapsulates work with Google ads ID. When developing and publishing apps for kids COPPA, you don’t need com.devtodev:android-google
. You can find more information about working with COPPA at the end of this guide.
In the Project build.gradle
file, declare the mavenCentral
repository:
If you use Gradle for building apps specify the following dependencies in the application build.gradle
file.
If you use Gradle for compiling apps, declare the following dependencies in the build.gradle file in the dependency block:
In the Project build.gradle
file declare the agconnect plugin
In the application build.gradle file declare the following dependencies:
And add a plugin:
For more information see huawei official documents.
The com.devtodev.android-huawei
framework works with OAID and ODID IDs. In case the OAID is undefined, we use the ODID. For both IDs to work correctly, take the following steps:
Create a project and an app in AppGallery. Open AppGalleryConnect → Project Settings.
Sign your app using a certificate (see here).
Enter SHA-256 certificate in the App information section. Read more about certificate creation here.
After taking all the steps described above, open the ‘App information’ section and download agconnect-services.json. You need to place this file in the app folder (read more).
Use the following way to initialize the library in the first Activity onCreate()
method:
You can find the App ID in the settings of the respective app in devtodev (Settings → SDK → Integration → Credentials).
config
- is a DTDAnalyticsConfiguration
object instance that is used for specifying additional properties during initialization.
DTDAnalyticsConfiguration
Parameter
Type
Description
currentLevel
Integer
The player level at the moment of devtodev SDK initialization. It’s optional but we recommend using it for improving data accuracy.
userId
String
A custom user ID assigned by the developer. In the case of default calculation by device IDs, the identifier can be used for searching users in devtodev. In case the project uses calculation by user IDs, the parameter is mandatory because it becomes the principal calculation ID in devtodev.
trackingAvailability
DTDTrackingStatus (enum)
The property allows or disallows devtodev tracking of the user. By default, it is set to DTDTrackingStatus.enable
. SDK stores the previously assigned value. Pass DTDTrackingStatus.disable
if the user opted out of tracking in line with GDPR.
logLevel
DTDLogLevel (enum)
The level of logging the SDK activity. The DTDLogLevel.no
value is used by default. For troubleshooting during integration it is recommended to set it to DTDLogLevel.debug
, and either switch it off DTDLogLevel.no
. Use DTDLogLevel.no
in the release version.
Example:
Add the following strings to the proguard-rules.pro
file of your app
When developing and publishing apps targeted at children under 13 years old, you need to ensure special conditions for data processing. Any mobile app aimed at children or intended for users in a region with strict regulations on child online protection, must comply with current laws.
Please study the following requirements:
If your app has to comply with the legal requirements (COPPA), use the following recommendations:
Implement the coppaControlEnable
method. The method disables collection of ad IDs and vendor IDs.
If your app is using Google services, remove the following dependencies from gradle:
If your app is using Huawei services, remove the following dependencies from gradle:
Call the coppaControlEnable
method before SDK initialization. If the method was not called, the SDK will work as before.
WSA Integration
For the Messaging module to function you need the basic Analytics package. Before the notification initialization, you need to initialize the SDK. More about it you can read here: Unity Integration.
Add the DTDAnalytics
initialization block after the DTDMessaging
initialization block.
Attention! Use the #if UNITY_WSA
define to surround any notification module code on the WSA platform.
Use the following method to check current status:
The current module status will be sent to onGetMessagingEnabling
callback.
You can listen to basic events of the Messaging module: create the class that implements the IDTDPushListener
interface and send it to the DTDMessaging.WSA.SetPushListener
method.
Class example:
A complete example of notification module initialization:
void DTDMessaging.WSA.SetMessagingEnabling(bool value)
The method responsible for enabling or disabling of the push notification module
void DTDMessaging.WSA.GetMessagingEnabling(Action<bool> onGetMessagingEnabling)
The method that returns current state of the push notification module to onGetMessagingEnabling callback
void DTDMessaging.WSA.SetPushListener (IDTDPushListener pushListener)
It sets a listener for push notification event trapping
Build a Windows Store App in Unity. After the app is built, a Visual Studio project will be created. Proceed with the following changes.
There is a difference in the implementation of the elements mentioned below for different types of projects:
Put the following source in your App class (usually it is App.xaml.cpp
file). Add several lines of code in a generated App.xaml.cpp
class. After defining headers:
And at the end of of the App::OnLaunched(LaunchActivatedEventArgs^ e)
and App::OnActivated(IActivatedEventArgs^ args)
functions.
For Example:
Put the following source in your App class (usually it is App.cpp file). Add several lines of code in a generated App.cpp class. After defining headers:
And at the end of of the App::OnActivated(CoreApplicationView^ sender, IActivatedEventArgs^ args
) function.
Besides, in the UI editor of the Package.appxmanifest
file you need to do the following:
Add Background Tasks in the Declarations tab and mark it as System Event
. After that, add DevToDev.Background.ToastNotificationBackgroundTask
to the Entry Point field
.
Add Background Tasks in the Declarations tab and mark it as Push Notification
. After that, add DevToDev.Background.RawNotificationBackgroundTask
to the Entry Point field
.
To disable notifications, call the following method:
CocoaPods is the easiest way to add devtodev into your iOS project.
1. Firstly, install CocoaPods using:
2. In the project directory execute the command:
3. In the created Podfile add the dependency:
4. Finally, run the command in your Xcode project directory:
CocoaPods should download and install the devtodev library, and create a new Xcode workspace. Open this workspace in Xcode.
To connect the module for processing push notifications, you need to:
1. Download the latest devtodev SDK from the repository
2. Add DTDAnalytics.xcframework
to the project (check Do Not Embed)
The DTDMessaging plugin will not work without the DTDAnalytics main analytics plugin.
3.Add DTDMessaging.xcframework to the project (check Do Not Embed)
4. In the Xcode project settings, open the tab, and add: "Push Notifications" and "Background Modes" respectively
5. In the "Background Modes" section, enable "Remote notifications"
6. Add initialization to didFinishLaunchingWithOptions
method:
7. To handle SDK delegate methods, you need to add the implementation of the DTDMessagingDelegate
protocol
The DTDMessaging
module provides support for notifications with attachments. These notifications are available since iOS 10. Attachments support images, animated gifs and videos. To use this function, you will need to create a “Notification Service Extension“, for this create a new target in your application settings:
Open Xcode (File -> New -> Target). Select Notification Service Extension.
The next step is to modify the Notification Extension
class as follows:
Delete all auto-generated code.
Inherit Notification Extension
class from DTDMediaAttachmentExtension
Example:
DTDMessaging
moduleObject
Type
Description
startPushService
Method responsible for activating push notifications:
Requests permission from the user to receive Push Notifications
Sends a pushToken and the current state isAllowed
apnsToken
Data?
Getter giving the current pushToken, represented by a Data
apnsTokenString
String?
Getter giving the current pushToken, represented by a String
delegate
DTDMessagingDelegate?
Property for assigning a delegate to handle events from the SDK
pushNotificationsOptions
DTDNotificationOptions
Configuring the display of Push Notifications, is an OptionSet
, is set by the developer to select the method for notifying the user. May be changed by the end user.
By default it has the following value: [.DTDNotificationOptionBadge, .DTDNotificationOptionSound, .DTDNotificationOptionAlert]
DTDMessagingDelegate
methodsDelegate method
Description
didFailToRegisterForRemoteNotifications
(with error:
Error
)
The method is called when an error occurs at the time of receiving a pushToken, represented by the Error
base class.
didOpenRemoteNotification
(with message:
DTDMessage
, and buttonClicked:
DTDActionButton?
)
The method is called when a remote push notification is opened by an end user. A DTDMessage
object and an optional DTDActionButton
object are passed.
didReceiveForegroundNotification
(with message:
DTDMessage
)
The method is called when a remote push notification is received when the application is in the Foreground state. The DTDMessage
object is passed.
didReceiveInvisibleNotification
(with message:
DTDMessage
)
The method is called when an invisible remote push notification is received. The DTDMessage
object is passed.
didRegisterForRemoteNotifications
(with deviceToken:
Data
)
The method is called in case the pushToken
successfully arrives; represented by a Data.
Property
Type
Description
payload
[AnyHashable:Any]
Full information sent using remote push notification.
actionType
DTDActionType
Property returning the enum DTDActionType value. Possible values:
App
- default value
Url
- open an external link
Share
- share content
Deeplink
- open a link inside the application
actionString
String?
Property returning an optional action identifier.
badge
Int
The value that is passed to display a badge on the application icon.
category
String?
Property returning an optional identifier of a push notification category
Property
Type
Description
actionType
DTDActionType
Property returning the enum DTDActionType value. Possible values:
App
- default value
Url
- open an external link
Share
- share content
Deeplink
- open a link inside the application
actionString
String?
Property returning an optional action identifier.
buttonId
String
Property returning the identifier of the pressed button.
text
String
Property returning the text of the pressed button.
Displaying push notifications in Foreground state is available since iOS 10.0.
By default, according to Apple Push Notification Guidelines, the display of push notification in the Foreground state is disabled. In order to set the display method, you must:
Assign delegate for UNUserNotificationCenter
Or pass a parameter in the push notification constructor (_fg = 1
). In this case, the display method will be formed from the Notification settings.
Or delegate the system method userNotificationCenter willPresent notification
. In this case, the display properties will be taken from the developer.
An example of a delegated method implementation:
It is an OptionSet
that is used to pass push notification authorization and set up interactions with users.
The user can change the allowed parameters at any time in the notification settings.
Possible values:
Value
Description
DTDNotificationOptionBadge
display a badge on the application icon
DTDNotificationOptionSound
play sound
DTDNotificationOptionAlert
display an alert
DTDNotificationOptionCarPlay
display push notification in CarPlay
DTDNotificationOptionCriticalAlert
play sound for critical notifications regardless of the “Do Not Disturb” setting (Critical alerts require special permission from Apple.) Available since iOS 12.0
DTDNotificationOptionProvidesSettings
an option specifying that the system should display a button for notification settings in the application. Available since iOS 12.0
DTDNotificationOptionProvisional
pre-send notifications to the Action Center without interrupting work. Available since iOS 12.0
DTDNotificationOptionAnnouncement
for Siri to automatically read messages through AirPods. Available since iOS 13.0
DTDNotificationOptionProvisional
- Provisional push notifications appear in the user's Notification Center, but not on the lock screen. This type of push notification does not have to be explicitly allowed by the user. Start submitting them as soon as the user installs and runs your application. However, the user can also opt in/opt out of notifications, but they will need to do it explicitly.
This setting is used to prevent receiving push notification permission requests at the start, which is intrusive and most users refuse to receive them.
It is also important that when using the DTDNotificationOptionProvisional
setting, the user will be able to subscribe to explicit notifications only from the notification center settings.
DTDMediaAttachmentExtension
To handle the application attitude to displaying push notifications, you need to add a Notifications service Extension. And inherit NotificationService
from DTDMediaAttachmentExtension
To use custom sounds for push notifications, you need to copy the necessary sound files to the Libraries folder of your Xcode project. You can read more about supported formats here.
When creating a push company, it is important to specify the full name of the sound with file extension (for example, sound.wav).
DTDMessaging automatically swizzles notification tracking and APNS-token usage methods by default. If you want to disable the function, add the flag DTDMessagingSwizzlingEnabled
(boolean) in the app’s Info.plist
file and set it to NO (0). However, if you disable notification swizzling, you will need additional integration for accurate analytics:
For sending APNS-token to DTDMessaging:
For sending information about the application:
Note: If you disable automatic notification swizzling, DTDMessagingDelegate
methods will not be called.
The SDK can be found in the devtodev GitHub repository. Download the latest release of the Source code (zip). Unzip the archive and copy the DTDMessaging
folder to the Plugins folder of your project.
If you have a C++ type project, add DTDMessaging
to the list of dependency names in the <module_name>.Build.cs
file of the module in which you plan to use the plugin.
Example:
Add your google-services.json
file to the project's root directory. It will be used to configure notifications during the project-building process.
In the case your Unreal Engine is built from GitHub source code:
Enable notifications in the settings of your project: Edit → Project Settings → iOS → Enable Remote Notifications Support
In the case your Unreal Engine is not built from GitHub source code:
Add the parameter to the engine configuration file (<proj_dir>/Config/DefaultEngine.ini
):
class UDTDMessagingBPLibrary
A class that implements analytic methods.
Header file:
enum class EDTDNotificationActionType : uint8
Notification action type
Header file:
Values:
App = 0
- default value
Url = 1
- external link opening
Share = 2
- share contentc
DeepLink = 2
- an in-app link opening
struct FDTDNotification
Notification data container.
Header file:
ActionType
EDTDNotificationActionType
Тип действия уведомления
ActionString
FString
Идентификатор действия уведомления
Data
TMap<FString, FString>
Данные уведомления
struct FDTDNotificationAction
Notification action data container.
Header file:
ActionType
EDTDNotificationActionType
Тип действия уведомления
ActionString
FString
Идентификатор действия уведомления
ButtonId
FString
Идентификатор нажатой кнопки
ButtonText
FString
Текст нажатой кнопки
ButtonIcon
FString
Иконка нажатой кнопки
IsBackground
bool
Режим открытия приложения кнопкой
enum class EDTDIOSNotificationOptions : uint8
iOS only
Push Notification display settings are Bitflags
that are managed by the developer and allow for selecting the method of user notification. It can be altered by the end user.
By default, it has the value: Badge|Sound|Alert
Header file:
Values:
None = 0
- nothing
Badge = 1 << 0
- can display a badge on the app icon
Sound = 1 << 1
- can play a sound
Alert = 1 << 2
- can display an alert
CarPlay = 1 << 3
- can display a push notification on CarPlay
CriticalAlert = 1 << 4
- critical alerts can play a sound even if Do Not Disturb is enabled (critical alerts require a special entitlement issued by Apple). Available from iOS 12 onwards.
AppNotificationSettings = 1 << 5
- this option defines that the system should display a notification settings button in the app. Available from iOS 12.0 onwards.
Provisional = 1 << 6
- an option for sending provisional notifications to the Notification Center without interrupting functioning processes. Available from iOS 12.0 onwards.
Provisional - Provisional push notifications are shown in the User Notification Center but not on the lock screen. This type of push notification doesn’t require an explicit opt-in from the user. You can start sending them as soon as the user installs and launches your app. However, the user can also explicitly enable/disable your notifications.
Use this setting to avoid the permission request on app launch because it is seen as intrusive, and most users opt out of it.
It’s also important that when using the Provisional setting, the user needs to go to Notification Center settings to allow explicit notifications.
Delegates
Header file:
Delegates:
Notification module initialization:
SetAvailability
A method responsible for enabling/disabling push notifications. When the state changes, it sends an event that includes the availability status (true or false). The availability status flag is stored in the SDK.
GetAvailability
Get the current availability
status flag (true or false):
onResult
FDTDMessagingDynamicBoolParamsDelegate
FDTDMessagingBoolParamsDelegate
Callback
GetToken
Get a current unique device ID used in the notification system:
onResult
FDTDMessagingDynamicStringParamsDelegate
FDTDMessagingStringParamsDelegate
Callback.
SetTokenListener
Set a token listener. The listener will be executed when the SDK updates a unique device ID in the notification system.
listener
FDTDMessagingDynamicStringParamsDelegate
FDTDMessagingStringParamsDelegate
Listener.
SetTokenErrorListener
Set a listener for errors in token reception. The listener will be executed when an error occurs while the SDK updates a unique device ID in the notification system.
listener
FDTDMessagingDynamicStringParamsDelegate
FDTDMessagingStringParamsDelegate
Listener.
SetNotificationReceiveListener
Set a listener for notification reception. The listener will be executed when the SDK receives a notification.
listener
FDTDMessagingDynamicNotificationParamsDelegate
FDTDMessagingNotificationParamsDelegate
Listener.
SetInvisibleNotificationReceiveListener
Set a listener for invisible notification reception. The listener will be executed when the SDK receives an invisible notification.
listener
FDTDMessagingDynamicNotificationParamsDelegate
FDTDMessagingNotificationParamsDelegate
Listener.
SetNotificationActionListener
Set a listener for notification activation. The listener will be executed when the notification gets activated.
listener
FDTDMessagingDynamicNotificationActionParamsDelegate
FDTDMessagingNotificationActionParamsDelegate
Listener.
IOSSetNotificationOptions
iOS only
Set notification parameters.
options
int32
Options.
An int32 type value is used as an argument of this method. However, this argument should be calculated by using enumerators of EDTDIOSNotificationOptions
and bitwise OR operator.
In order to work with push notifications, you need to integrate the messaging module. You can do it by using one of the two methods: with the help of the Unity Package Manager (recommended) or by manually importing the unitypackage.
If you integrated the devtodev package manually, then you need to delete the Assets/DevToDev and Plugins/DevToDev folders.
In the Package Manager (Window → Package Manager), click + in the top left corner and select Add package from git URL.
Copy the repository URL https://github.com/devtodev-analytics/package_Messaging.git to the input box and click Add.
Wait for the Unity Package Manager to download the package and all the necessary dependencies.
If you use Android, allow dependencies in Assets → External Dependency Manager → Android Resolver → Resolve.
You can pick a specific SDK version by adding # and a version number at the end of the URL, for example: https://github.com/devtodev-analytics/package_Messaging.git#v3.3.2
Download the latest version of devtodev package from the repository: https://github.com/devtodev-analytics/Unity-sdk-3.0/releases/latest
Import DTDAnalytics.unitypackage to your project
Import DTDMessaging.unitypackage to your project
If you use Android, allow dependencies in Assets → External Dependency Manager → Android Resolver → Resolve.
The DevToDev.Messaging
package necessary for notifications is available in the NuGet
package manager.
Package Manager UI
Find the DevToDev.Messaging
package using the package manager search engine and click Install. The latest version of the package is recommended.
To integrate WNS, you need to get the Package SID and Application Secret Key from the Microsoft Partner Center and specify them in the devtodev push notification settings (Project -> Settings-> Push notifications):
For the correct package functioning, add handlers invoke to the Windows.UI.Xaml.Application
class implementation.
Besides, in the UI editor of the Package.appxmanifest file do the following:
Add Background Tasks to the Declarations tab and mark it as System Event. After that enter DevToDev.Background.ToastNotificationBackgroundTask
to the Entry Point field.
Add Background Tasks to the Declarations tab and mark it as Push Notification. After that enter DevToDev.Background.RawNotificationBackgroundTask
to the Entry Point field.
For the DevToDev.Messaging
package functioning you need to have the main DevToDev.Analytics
package installed. Initialize the SDK before initializing messages. You can read about it in more detail in the SDK initialization section.
After the SDK has been initialized you can move to initializing messages. To do this, call the method:
It is possible to listen to events from the DevToDev.Messaging
package:
1. Push Token - a string that allows to identify the client on a remote server for sending him customized notifications. For listening the unique Push Token ID issue event, it is necessary to be subscribed to the event:
2. To track the errors related to the unique Push Token ID issue, it is necessary to be subscribed to the event:
Where error is a string value containing information about the error.
3. To handle incoming message data, it is necessary to be subscribed to the following event:
Where messageData
belongs to the IDictionary<string, string>
type and contains data sent from the server together with the message.
4. To handle notification activation events, it is necessary to be subscribed to the event:
Where messageAction
is DevToDev.Messaging.DTDMessageAction
class instance:
Call the method to turn notifications off:
Android Integration
Push Notifications on Android are sent with the help of the FCM service.
How to create a project in Firebase and integrate Firebase Services into your application, you can find in Firebase documentation.
Next, you need to specify the FCM Server key in the push notifications integration settings panel in the application settings section in devtodev service (App → Settings → Push notifications → Push notifications panel)
To get the FCM Server key, go to the Project Settings of your Android project in the Firebase Console and copy the Server key from the Cloud Messaging tab.
Download google-services.json and put it to Assets folder.
1. For the Messaging module to function you need the basic Analytics package. Before the notification initialization, you need to initialize the SDK. More about it you can read here: Unity Integration.
2. After the DTDAnalytics initialization block add:
3. To activate the Messaging module, call :
Optional:
You can listen to basic notification module events. To do this, create a class that implements the IDTDPushListener
interface and pass it to the DTDMessaging.Android.SetPushListener
method.
Example of the class:
Full example of notification module initialization:
To set a custom sound, icon and its colour in a push notification, copy icons and sounds files in the Assets/Plugins/Android/res/
folder and add the following strings to the manifest file code:
To set a large user icon in the push notification, add:
Delete the \Assets\Plugins\Android\res
folder (together with the .meta
file) - it will cause an error during assembly.
Create a new folder in a separate folder outside of the project.
In the new folder, create AndroidManifest.xml
with the following content (replace company
and package
with you own names)
Create a res folder in the same folder.
Add your resources to the res folder while keeping the folder structure intact (drawable, xml, raw, etc.). An example of the resulting structure:
Run the following code in the in the command line/terminal:
Place the resulting aar file to the \Assets\Plugins\Android\ (edited)
folder
Add the following strings to the project’s Android manifest file ( \Assets\Plugins\Android\AndroidManifest.xml
):
void DTDMessaging.Android.Initialize()
The push notification initialization method
void DTDMessaging.Android.StartPushService()
The push notification activation method. It passes the isAllowed
current state
void DTDMessaging.Android.PushIsAllowed (bool isAllowed)
A property responsible for the activation/deactivation of push notifications.When the state transitions, it sends a pt with isAllowed
(true or false) status to the server.
The isAllowed
flag status is stored in the SDK.
void DTDMessaging.Android.GetPushState(Action<bool?> onGetPushState)
The method that returns the push module state to onGetPushState
callback. If getting the current state is impossible, it returns null
void DTDMessaging.Android.GetToken(Action<string> onGetToken)
The method that returns push registration token to onGetToken callback
void DTDMessaging.Android.ProcessPushNotification (IDictionary<string, string> firebaseMessaging)
Used to pass the push notification to the FirebaseMessagingService
if it was implemented by the client but not by the SDK
void DTDMessaging.SetPushListener (IDTDPushListener pushListener)
It sets a listener for push notification event trapping
DTDPushMessage
). Main class propertiesIDictionary<string,string> GetData():
Complete information passed with the push notification.
DTDActionType ActionType:
The property that returns the value of enum’s DTDActionType
.
Possible values:
App - app open
Url - external link open
Share - share content
Deeplink - an in-app link opening
string ActionString
The property that returns an optional action identifier
IDictionary<string,string> AdditionalData()
Additional data sent to push notification
DTDActionButton
)DTDActionType ActionType
The property that returns the value of enum’s DTDActionType
.
Possible values:
App - app open
Url - external link open
Share - share content
Deeplink - an in-app link opening
string ActionString
Property that returns an optional action identifier
string ButtonId
Property that returns the ID of the clicked button
string ButtonText
Property that returns the text of the clicked button
string ButtonIcon
Property that returns the button icon name
bool IsBackground
The button-click app open mode
Android Push Notifications
Push Notifications on Android are sent with the help of the FCM service.
Register and open the project creation window in Firebase.
Click Add project.
Write the name of your project. At this stage, you can also set your own unique project identifier or use the one that Firebase will generate for you automatically.
After creating the project card, create an Android application by clicking on the Android icon.
Register your android package name.
Download the google-services.json file and use it according to the instructions of firebase.
Add firebase dependencies according to the firebase documentation.
Complete the application registration, you will see the project overview section.
Select your application by clicking on it, you will see a gear on the right side, click on it to go to project settings.
Go to the cloud messages section, make sure that the Firebase Cloud Messaging API (V1) is active (if not, activate it).
Go to the general section and copy the value of the Project ID field and paste it into the devtodev web interface.
The Project ID is also available from the Firebase main screen in the project cards. After setting up the application, the card should look like this:
It should have a Project ID and an android icon.
Next, open the push notifications integration settings panel in the application settings section in devtodev service (App → Settings → Push notifications → Push notifications panel). Push edit button (pencil symbol).
You will need to specify the Firebase Project ID and authorize devtodev to send messages and manage messaging subscriptions for your Firebase application. To authorise the application, you must use Google login and password of a user with sufficient access rights to the project on Firebase. After that click Save button.
The Messaging module is available as an AAR (recommended) and JAR library. The library is available in the MavenCentral and GitHub repository.
1. If you use Gradle for the applications build, add mavenCentral()
into gradle.build file of your application and specify the following relationship in dependencies block:
2. To the app manifest add the following:
3. To add a user icon to your push notification and change its color, add the following strings to the manifest file code:
To add a large user icon to your push notifications, add:
Example:
4. After the DTDAnalytics
initializer, add the DTDMessaging
initializer.
Example:
5. Subscribe a DTDPushListener
to receive information about the DTDMessaging
functioning.
Example:
6. Call the DTDMessaging.startPushService()
method to activate the Messaging module.
When using Android 13 or higher, notifications are disabled by default. The app won’t receive notifications until you request a new permission (POST_NOTIFICATIONS
) and the user grants this permission to your app.
For notifications to work properly, add the following line to the manifest file:
You can check the operation of the POST_NOTIFICATIONS
permission in your app by inserting this example in the code:
If the check results in a negative answer (access is not granted), call this method:
Its execution will call a dialog that in turn will ask the user to opt in:
This code is going to help you get the user’s decision:
Note. In SDK ver. 2.1.5 or higher, if the permission is not granted, you will see this message in the log from DTDMessaging: “Notifications don’t work. Permission android.permission.POST_NOTIFICATIONS is not granted”.
DTDMessaging
moduleObject
Description
DTDMessaging
The main object for push notification initialization.
DTDMessaging.initialize(Context context)
The push notification initialization method.
DTDMessaging.startPushService()
The push notification activation method. It passes the isAllowed
current state.
DTDMessaging.pushNotificationsAllowed
= true or false
A property responsible for the activation/deactivation of push notifications.
Functions as a getter (describes the current state) and a setter (sets the current state).
When the state transitions, it sends a pt with isAllowed
(true or false) status to the server.
The isAllowed
flag status is stored in the SDK.
DTDMessaging.setIntent(Intent intent)
A method of passing a user intent to the SDK using PushMessage.
Written in the manifest file
<meta-data android:name="com.devtodev.push.default_small_icon" android:resource="@drawable/smallIcon" />
Sets a small custom user icon.
Written in the manifest file
<meta-data android:name="com.devtodev.default_small_icon_color" android:resource="@color/colorPrimary" />
Sets a color of the small custom user icon.
Written in the manifest file
<meta-data android:name="com.devtodev.push.default_large_icon" android:resource="@mipmap/largeIcon" />
Sets a large custom user icon.
DTDMessaging.getToken()
Returns a push notification registration token (firebaseToken
).
DTDMessaging.processPushNotification(Context context, RemoteMessage remoteMessage)
Used to pass the push notification to the FirebaseMessagingService if it was implemented by the client but not by the SDK.
DTDMessaging.setPushListener(DTDPushListener pushListener)
(DTDPushListener pushListener
) - sets a listener for push notification event trapping.
DTDPushListener
Interface MethodsDTDPushListener Interface Methods
Description
onPushServiceRegistrationSuccessful(String deviceId)
Returns a push notification registration token (firebaseToken
).
onPushServiceRegistrationFailed(String error)
Returns errors during push notification registration.
onPushNotificationReceived(Map<String, String> message)
Returns a directory with data for improving your push notifications.
onPushNotificationOpened(DTDPushMessage pushMessage, @Nullable DTDActionButton actionButton)
Returns pushMessage
and actionButton
if they were tapped.
DTDPushMessage
).Property
Type
Description
getData()
Map<String, String>
Complete information sent with the use of a remote push notification.
systemId
Int
The notification ID used in the devtodev system.
getTitle(context:Context)
String?
Returns the selected message title or app name if the former is unavailable.
body
String?
The text body.
group
String?
A group of messages.
getSound(context: Context)
Uri?
Returns the storage path of an audio file.
getSoundName()
String?
The notification sound name.
tag
String?
The notification tag.
color
String?
The notification color.
bigPicture
String?
The notification banner if specified.
actionType
DTDActionType
The property that returns an enum’s DTDActionType value.
Possible values:
Url - an external link opening
Share - content sharing
Deeplink - an in-app link opening
actionString
String?
The property that returns an optional action ID.
getIcon(context: Context, userIcon: Int)
Int
The icon resource identifier specified by the user (if specified).
largeIcon
String?
The large notification icon name.
actions
List<DTDActionButton>
The list of action buttons used in the push notification.
isApiSource
Boolean
Specifies whether the push notification was sent using the devtodev API.
DTDActionButton
)Property
Type
Description
Id
String?
The property that returns the tapped button ID.
actionString
String?
The property that returns the optional action ID.
actionType
DTDActionType
The property that returns an enum’s DTDActionType
value.
Possible values:
App - a default value
Url - an external link opening
Share - content sharing
Deeplink - an in-app link opening
icon
String?
The property that returns the button’s icon name.
isBackground
Boolean
The button-click app open mode.
text
String?
The property that returns the text of the tapped button.
Please take a look at our before integrating the events.
To track payments in a real currency, dispatch this event right after the system validates that the payment went through successfully. The event is fundamental and mandatory for all the app metrics related to monetization.
How to find the transaction ID in GooglePlay transaction?
Find the INAPP_PURCHASE_DATA object In the JSON fields that are returned in the response data for a purchase order. A unique transaction identifier is the value of orderId property in INAPP_PURCHASE_DATA object. If the order is a test purchase made via the In-app Billing Sandbox, orderId property will be empty.
How to find the transaction ID in GooglePlay transaction?
Find the INAPP_PURCHASE_DATA object In the JSON fields that are returned in the response data for a purchase order. A unique transaction identifier is the value of orderId property in INAPP_PURCHASE_DATA object. If the order is a test purchase made via the In-app Billing Sandbox, orderId property will be empty.
By default (easy to change in the app’s settings) devtodev server invalidates transactions with previously-used identifiers. Besides, the server performs identifier checks by its outer appearance in order to avoid obvious fraud.
If you want to exclude fraud payments from your reports altogether, before creating ‘Real Currency Payment’ event, use devtodev anti-cheat feature.
If you want to track non-basic events, you can create custom events of your own. How you are going to apply them, depends solely on you.
Attention! We strongly recommend that you do not use custom event properties to transfer and store data that fits the definition of !
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use DTDCustomEventParameters
class instance.
The following data types can be passed using the DTDCustomEventParameters
object:
If you want to pass custom parameters, use an object with parameters.
The following data types can be passed using parameters object:
If you want to pass custom parameters, use:
The following data types can be passed using the DTDCustomEventParameters object:
If you want to pass custom parameters, use GDDTDCustomEventParameters
class instance.
The following data types can be passed using the GDDTDCustomEventParameters
object:
devtodev supports no more than 300 custom event names in a single project. Events that exceed the limit of custom event names will be discarded. Try to integrate the tracked actions by type to the event name level, and move the characteristic tags in the parameters.
For example, if you need to track purchasing “Paper” and “Pen” items, then you don’t need to create two events with the names “Paper Purchase” and “Pen Purchase”. Create a “Purchase” event and add an “Item” parameter to it with the appropriate “Paper” or “Pen” value. This way, you can use just one event to track many items.
For a string parameter, you can use no more than 50,000 unique values for the entire history of events. If the number of unique values exceeds the limit, the parameter gets locked by the system and gets discarded from the received data. Therefore, we don’t recommend using highly variable parameters like user IDs or time as string values (moreover, they are automatically added to the event).
We strongly recommend that you do not change the data type passed in the same parameter. If you change the data type in a parameter, it will be duplicated with the same name, which may cause issues while processing reports.
The described method is available beginning with version 2.1.0!
Tracking of subscriptions is now available for Apple App Store and Google Play only.
Please note that in order to track subscriptions, you need to do the following:
Call the subscriptionPayment
method (described below)
To track your income from subscriptions, you need to call the following method at the moment of the subscription purchase even if the user signed up for a trial subscription: func subscriptionPayment(transaction: SKPaymentTransaction, product: SKProduct).
For example:
Further user actions - renewal, unsubscription, etc. are tracked by using the data received from AppStore in the server-server format. You will need the corresponding setting for it.
Also, if you want to track changes in the status of the subscriptions purchased before devtodev SDK 2.0 integration, you need to transfer your history of previously purchased subscriptions to devtodev.
The SDK monitors the need for historical data to avoid sending out excessive queries to App Store. Use the DTDAnalytics.isRestoreTransactionHistoryRequired
method to check whether or not there is a need in sending out the information about the previously purchased subscriptions to devtodev. The method returns BOOL value.
An example of a purchase history query with verification of the need for it:
Use the DTDAnalytics.subscriptionHistory
method to transfer the list of previously purchased subscriptions received from App Store.
If your project accounts users by user ID (not by device ID) and the device is used by more than one user, you need to filter the transaction history so that it will contain only those transactions that belong to the active user. Otherwise, subscriptions of all device users will be attributed to the user who was the first to launch the app after the integration of subscription tracking.
To recover the purchase history, the user should be logged in with his Apple ID. Be mindful of this before starting the recovering process.
Please note that in order to track subscriptions, you need to do the following:
Call the subscriptionPayment
method (described below)
To track your income from subscriptions, you need to call the following method at the moment of the subscription purchase even if the user signed up for a trial subscription: func subscriptionPayment(transaction: Transaction, product: Product).
For example:
Fork with Transaction.updates:
Further user actions - renewal, unsubscription, etc. are tracked by using the data received from AppStore in the server-server format. You will need the corresponding setting for it.
Also, if you want to track changes in the status of the subscriptions purchased before devtodev SDK 2.0 integration, you need to transfer your history of previously purchased subscriptions to devtodev.
The SDK monitors the need for historical data to avoid sending out excessive queries to App Store. Use the DTDAnalytics.isRestoreTransactionHistoryRequired
method to check whether or not there is a need in sending out the information about the previously purchased subscriptions to devtodev. The method returns BOOL value.
An example of a purchase history query with verification of the need for it:
Use the DTDAnalytics.subscriptionHistory
method to transfer the list of previously purchased subscriptions received from App Store.
If your project accounts users by user ID (not by device ID) and the device is used by more than one user, you need to filter the transaction history so that it will contain only those transactions that belong to the active user. Otherwise, subscriptions of all device users will be attributed to the user who was the first to launch the app after the integration of subscription tracking.
To recover the purchase history, the user should be logged in with his Apple ID. Be mindful of this before starting the recovering process.
Please note that in order to track subscriptions, you need to do the following:
Call the subscriptionPayment
method (described below)
To track your income from subscriptions, you need to call the following method at the moment of the subscription purchase even if the user signed up for a trial subscription:
(void)subscriptionPaymentWithTransaction:(SKPaymentTransaction * _Nonnull)transaction product:(SKProduct * _Nonnull)product;
For example:
Further user actions - renewal, unsubscription, etc. are tracked by using the data received from AppStore in the server-server format. You will need the corresponding setting for it.
Also, if you want to track changes in the status of the subscriptions purchased before devtodev SDK 2.0 integration, you need to transfer your history of previously purchased subscriptions to devtodev.
The SDK monitors the need for historical data to avoid sending out excessive queries to App Store. Use the (void)isRestoreTransactionHistoryRequiredWithCompletionHandler:( void (^ _Nonnull)(BOOL))completionHandler;
method to check whether or not there is a need in sending out the information about the previously purchased subscriptions to devtodev. The method returns BOOL value.
An example of a purchase history query with verification of the need for it:
Use the (void)subscriptionHistoryWithTransactions:(NSArray<SKPaymentTransaction *> * _Nonnull)transactions;
method to transfer the list of previously purchased subscriptions received from App Store.
If your project accounts users by user ID (not by device ID) and the device is used by more than one user, you need to filter the transaction history so that it will contain only those transactions that belong to the active user. Otherwise, subscriptions of all device users will be attributed to the user who was the first to launch the app after the integration of subscription tracking.
To recover the purchase history, the user should be logged in with his Apple ID. Be mindful of this before starting the recovering process.
Please note that in order to track subscriptions, you need to do the following:
Call the subscriptionPayment
method (described below)
Before sending a request for subscription from your app, during the creation of BillingFlowParams
, to the setObfuscatedAccountId
function of the BillingFlowParams.newBuilder()
object insert obfuscatedAccountId
obtained from DTDAnalytics.getObfuscatedAccountId
.
Attention! The obfuscated identifier is returned asynchronously, outside of the calling thread!
Example:
To track your subscriptions, add this event immediately after the platform confirms that the subscription was approved by the user.
How to find the transaction ID in GooglePlay transaction?
Find the INAPP_PURCHASE_DATA object In the JSON fields that are returned in the response data for a purchase order. A unique transaction identifier is the value of orderId property in INAPP_PURCHASE_DATA object. If the order is a test purchase made via the In-app Billing Sandbox, orderId property will be empty.
Further user actions - renewal, unsubscription, etc. are tracked by using the data received from Google Play in the server-server format. You will need the corresponding setting for it.
The subscriptionHistory
method is used for matching users with subscribers who purchased their subscriptions before the SDK 2.0 integration. Otherwise, it will be impossible to establish the affiliation when it gets renewed or cancelled.
To get a list of active subscriptions call billingClient.queryPurchasesAsync
. After successfully receiving a response from Google Play Services, pass it to DTDAnalytics.subscriptionHistory(purchaseList: List<String>).
purchaseList: List<String> purchaseList
- a string containing list of json objects is passed to the DTDAnalytics.subscriptionHistory
method. For the event to run, the json object must contain the following keys:
orderID
- a unique transaction identifier
productID
- a unique product identifier
The SDK monitors the need for historical data to avoid sending out excessive queries. Use the DTDAnalytics.isRestoreTransactionHistoryRequired
method to check whether or not there is a need in sending out the information about the previously purchased subscriptions to devtodev. The method returns a Boolean value.
Attention! DTDAnalytics.isRestoreTransactionHistoryRequired
is returned asynchronously, outside of the calling thread!
Example:
If your project accounts users by user ID (not by device ID) and the device is used by more than one user, you need to filter the transaction history so that it will contain only those transactions that belong to the active user. Otherwise, subscriptions of all device users will be attributed to the user who was the first to launch the app after the integration of subscription tracking.
Please note that in order to track subscriptions, you need to do the following:
Call the subscriptionPayment
method (described below)
Before sending a request for subscription from your app, during the creation of BillingFlowParams
, to the setObfuscatedAccountId
function of the BillingFlowParams.newBuilder()
object insert obfuscatedAccountId
obtained from DTDAnalytics.INSTANCE.getObfuscatedAccountId.
Attention! The obfuscated identifier is returned asynchronously, outside of the calling thread!
Example:
To track your subscriptions, add this event immediately after the platform confirms that the subscription was approved by the user.
How to find the transaction ID in GooglePlay transaction?
Find the INAPP_PURCHASE_DATA object In the JSON fields that are returned in the response data for a purchase order. A unique transaction identifier is the value of orderId property in INAPP_PURCHASE_DATA object. If the order is a test purchase made via the In-app Billing Sandbox, orderId property will be empty.
Further user actions - renewal, unsubscription, etc. are tracked by using the data received from Google Play in the server-server format. You will need the corresponding setting for it.
The subscriptionHistory
method is used for matching users with subscribers who purchased their subscriptions before the SDK 2.0 integration. Otherwise, it will be impossible to establish the affiliation when it gets renewed or cancelled.
To get a list of active subscriptions call billingClient.queryPurchasesAsync
. After successfully receiving a response from Google Play Services, pass it to DTDAnalytics.subscriptionHistory(purchaseList: List<String>).
purchaseList: List<String> purchaseList
- a string containing list of json objects is passed to the DTDAnalytics.INSTANCE.subscriptionHistory
method. For the event to run, the json object must contain the following keys:
orderID
- a unique transaction identifier
productID
- a unique product identifier
The SDK monitors the need for historical data to avoid sending out excessive queries. Use the DTDAnalytics.INSTANCE.isRestoreTransactionHistoryRequired
method to check whether or not there is a need in sending out the information about the previously purchased subscriptions to devtodev. The method returns a Boolean value.
Attention! DTDAnalytics.INSTANCE.isRestoreTransactionHistoryRequired
is returned asynchronously, outside of the calling thread!
Example:
If your project accounts users by user ID (not by device ID) and the device is used by more than one user, you need to filter the transaction history so that it will contain only those transactions that belong to the active user. Otherwise, subscriptions of all device users will be attributed to the user who was the first to launch the app after the integration of subscription tracking.
In order to work with Unity subscriptions, you need to integrate the subscription module to your project. You can do it by manually importing the unitypackage.
Import DTDAnalytics.unitypackage to your project
Import DTDSubscriptions.unitypackage to your project.
For the DTDSubscriptions
module to function you need the DTDAnalytics
and Unity IAP modules.
You also need to create an AppleTangle
file. Open the Unity editor menu and choose Window → Unity IAP → Receipt Validation Obfuscator (pic. 1).
In case you don’t use the IAP receipt validation, clear the input field under “2. Paste the key here:” and click Obfuscate Google Play Licence Key (pic. 2).
Restore purchase history in order for the module to function correctly.
If you use Google Play, after successful IAP initialization call the DTDSubscriptions.History()
method.
To avoid excessive restoring of subscription history, use the DTDSubscriptions.IsRestoreTransactionHistoryRequired(Action<bool> resultCallback)
method. If the resultCallback returns true, call the DTDSubscriptions.History()
method.
Example:
Example:
Add a DTDSubscriptions.Payment(Product product)
call to the ProcessPurchase
method.
Below you can see an example of the entire script:
The event allows you to track tutorial completion and identify the stages where you lose new users.
We recommend tracking the starting point (value -1) before beginning the first tutorial stage, then passing the counting number of every completed stage after its completion (integers larger than 0), and at the end, marking the moment of the last tutorial stage completion (value -2).
If your app has an option of skipping the tutorial and the user has used it, then it’s necessary to send a refusal value (value 0) only.
The method takes on the step value with an integer type.
The method takes on the step value with an integer type.
The method takes on the step value with an integer type.
The method takes on the step value with an integer type.
The method takes on the step value with an integer type.
The method takes on the step value with an int base type.
The method takes on the step value with an integer type.
The method takes on the step value with an int32 base type.
The method takes on the step value with an integer type.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
You can send and track the following data along with the level values: an average amount of the in-game currency by the end of the level, user spendings on the level, and amounts of purchased or earned in-game currency/resources. Unfortunately, Web SDK doesn’t allow to automatically calculate spending and receiving of the in-game currency/resources while users are passing the level (data accumulation on the Web might be inaccurate as users might utilize multiple browsers and devices, as well as erase local browser data).
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
The event should be dispatched right after the level-up. The number of the level reached is passed to the level
parameter.
To monitor the average account balance of in-game currency by the end of each level, dispatch in-game currencies (resources) names and their amounts to the method signature:
Attention! The number of tracked in-game currencies or resources (their unique names) should not exceed 30 at all times.
To track the average balance of in-game currency disregarding the level up event, pass the list of in-game currency (resource) names and their amount to the method signature:
You need to dispatch the event after every game account balance refill if you want to track the average in-game currency amount acquired or earned by the players for a certain timeframe or during a level playthrough.
acrualType
can receive one of the following values:
acrualType
can receive one of the following values:
accrualType
can receive one of the following values:
accrualType
can receive one of the following values:
AccrualType
can receive one of the following values:
AccrualType
can receive one of the following values:
Example:
acrualType
can receive one of the following values:
Pass this event after every purchase if you want to track in-game currency spends and items’ popularity. You can apply this event to both games and any apps with virtual currency.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names (FString) and amounts of the currencies/resources (int32) .
In case the item is sold for more than one currency/resource, you need to build a dictionary with all the names and amounts of the currencies/resources.
First of all, the progression event is used in games with short (within one game session) areas/game levels, e.g. match 3 games. You can use the event to collect data on how well or how fast users complete levels, how difficult it is for them, how many resources they gained or spent, and other parameters.
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
StartProgressionEvent
FinishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
StartProgressionEvent
FinishProgressionEvent
When a player spawns at a location, the following method is called:
DTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
DTDFinishProgressionEventParameters
:
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called:
startProgressionEvent
event parameters:
Example:
Once the player completes the location (instead of successfully or not), the following method is called:
startProgressionEvent
event parameters:
Example:
There are two methods in working with progression event:
startProgressionEvent
finishProgressionEvent
When a player spawns at a location, the following method is called (one of them):
Start progression event with parameters:
FDTDStartProgressionEventParams:
Example:
Once the player completes the location (instead of successfully or not), the following method is called (one of them):
Finish progression event with parameters:
FDTDFinishProgressionEventParameters:TMap<FString, int64>
Example:
There are two methods in working with progression event:
StartProgressionEvent
FinishProgressionEvent
When a player spawns at a location, the following method is called:
GDDTDStartProgressionEventParameters
:
Once the player completes the location successfully, the following method is called:
GDDTDFinishProgressionEventParameters
:
The user can only be in one area at a time. When moving to another area (including nested ones), the previous location must be completed. Information about events that have not been completed by calling the finishProgressionEvent
method during a game session (the finishProgressionEvent
method call is not integrated, or the user uses the cached app, or the app has crashed) is not included in the statistics.
If you want to use this event to track actions that take more than one game session, you can prepare the required data and call both methods when the action is completed (successfully or unsuccessfully). For example, you can use this event to track the main questline.
This method is used to initialize the user in applications where you have set calculation by user ID specified by the developer, applications that are part of a cross-platform project.
You can also use this method when calculating by device ID (by default) to pass in the user ID used on your servers so that you can easily find the user on devtodev.
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the setUserId
method.
To get the current value of the user ID, use the asynchronous method
getDeviceId(_ completionHandler: @escaping (String) -> Void)
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the setUserId
method.
To get the current value of the user ID, use the asynchronous method
(void)deviceIdHandler:( void (^ _Nonnull)(NSString * _Nonnull))completion-Handler;
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the setUserId
method.
To get the current value of the user ID, use the asynchronous method
getDeviceId(block: (String) -> Unit)
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the setUserId
method.
To get the current value of the user ID, use the asynchronous method
getDeviceId(block: (String) -> Unit)
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the SetUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the SetUserId
method.
To get the current value of the user ID, use the asynchronous method:
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of theDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the SetUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the SetUserId
method.
To get the current value of the user ID, use the asynchronous method:
We recommend that you pass this parameter in the initialization configuration (userId
property in config object).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the setUserId
method.
To get the current value of the user ID, use the getUserId
method
We recommend that you pass this parameter in the initialization configuration (UserId
property of an instance of the FDTDAnalyticsConfiguration
class).
Do not pass an empty string ("") to the SetUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use method:
To get the current value of the user ID, use the asynchronous method:
We recommend that you pass this parameter in the initialization configuration (userId
property of an instance of the GDDTDAnalyticsConfiguration class).
Do not pass an empty string ("") to the setUserID
method as the user ID. Assigning an empty string is a command to assign a default value to the user ID (it is equal to the current device ID). In applications with calculation by user ID, this can lead to unnecessary registrations.
To set a new value as the user ID, use the SetUserId
method.
To get the current value of the user ID, use the asynchronous method
DTDAnalytics.GetUserId(
onResult: Callable)
This method is used in very rare cases. It is applicable in the case when the calculation of users in the project is carried out by the user ID specified by the developer. In this case, the application can change this identifier. For example, calculation in the application is carried out by user emails and in the application, it is possible to change this email to another one. At the time of replacement, you need to call this method, specifying the user's previous email and the one with which it was replaced.
Do not use this method to re-login as a different user! The setUserId method is used for relogging.
This method is used in cross-platform and data synchronized applications. The method is required to update user level data.
To set the current value to the user level, use setCurrentLevel(currentLevel: Int)
method:
We recommend that you use the setCurrentLevel
method immediately after using the setUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the setCurrentLevel
method when the user reaches a new level. In this case, you must use the levelUp
method.
To get the user-level value stored by the SDK, use getCurrentLevel(completionHandler: @escaping (Int) -> Void)
method
To set the current value to the user level, use (void)currentLevel:(NSInteger)currentLevel;
method:
We recommend that you use the setCurrentLevel
method immediately after using the setUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the setCurrentLevel
method when the user reaches a new level. In this case, you must use the levelUp
method.
To get the user-level value stored by the SDK, use (void)currentLevelHandler:( void (^ _Nonnull)(NSInteger))completionHandler;
method
To set the current value to the user level, use method:
We recommend that you use the setCurrentLevel
method immediately after using the setUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the setCurrentLevel
method when the user reaches a new level. In this case, you must use the levelUp
method.
To get the user-level value stored by the SDK, use getCurrentLevel(completionHandler: @escaping (Int) -> Void)
method
To set the current value to the user level, use method:
We recommend that you use the setCurrentLevel
method immediately after using the setUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the setCurrentLevel
method when the user reaches a new level. In this case, you must use the levelUp
method.
To get the user-level value stored by the SDK, use getCurrentLevel(completionHandler: @escaping (Int) -> Void)
method
To set the current value to the user level, use method:
We recommend that you use the SetCurrentLevel
method immediately after using the SetUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the SetCurrentLevel
method when the user reaches a new level. In this case, you must use the LevelUp
method.
To get the user-level value stored by the SDK, use GetCurrentLevel
method:
To set the current value to the user level, use method:
We recommend that you use the SetCurrentLevel
method immediately after using the SetUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the SetCurrentLevel
method when the user reaches a new level. In this case, you must use the LevelUp
method.
To get the user-level value stored by the SDK, use GetCurrentLevel
method:
To set the current value to the user level, use method:
We recommend that you use the setCurrentLevel
method immediately after using the setUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the DTDAnalyticsConfiguration
).
Do not use the setCurrentLevel
method when the user reaches a new level. In this case, you must use the levelUp
method.
To get the user-level value stored by the SDK, use getCurrentLevel
method.
To set the current value to the user level, use method:
We recommend that you use the SetCurrentLevel
method immediately after using the SetUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the EDTDAnalyticsConfiguration
).
Do not use the SetCurrentLevel
method when the user reaches a new level. In this case, you must use the LevelUp
method.
To get the user-level value stored by the SDK, use method:
To set the current value to the user level, use SetCurrentLevel(level: int)
method:
We recommend that you use the SetCurrentLevel
method immediately after using the SetUserID
method or specify the current user level in the initialization configuration (the level property of an instance of the GDDTDAnalyticsConfiguration
).
Do not use the SetCurrentLevel
method when the user reaches a new level. In this case, you must use the LevelUp
method.
To get the user-level value stored by the SDK, use GetCurrentLevel(onResult: Callable)
method
If you have your own methods for detecting cheaters in the application, you can tag such users. Actions taken by these users will not be counted in statistics.
Attention! These properties have been removed since the devtodev SDK versions: iOS & macOS 2.4.0, Android 2.5.0, Unity SDK 3.8.0, Godot 1.0.0.
Attention! We strongly discourage the storage of personal user data! If you plan to pass this data, be sure to indicate this in the ‘Nutrition label’ when submitting the application to the App Store review.
Attention! We strongly discourage the storage of personal user data! If you plan to pass this data, be sure to indicate this in the ‘Nutrition label’ when submitting the application to the App Store review.
Attention! We strongly discourage the storage of personal user data! If you plan to pass this data, be sure to indicate this in the ‘Nutrition label’ when submitting the application to the App Store review.
Attention! We strongly discourage the storage of personal user data! If you plan to pass this data, be sure to indicate this in the ‘Nutrition label’ when submitting the application to the App Store review.
Example:
Each devtodev project can have up to 30 custom user properties. User custom property values can be a number, a string (up to 500 symbols), or a boolean value.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
getValue(key: String, _completionHandler: @escaping (Any) -> Void)
When using the getValue
method, note that the Any
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
(void)getValueWithKey:(NSString * _Nonnull)key :(void (^ _Nonnull)(id _Nullable))completionHandler;
When using the getValue
method, note that the Any
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
getValue(key: String, handler: (Any?) -> Unit)
When using the getValue
method, note that the Any
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
getValue(key: String, handler: (Any?) -> Unit)
When using the getValue
method, note that the Any
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
When using the Get
method, note that the object
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
When using the Get
method, note that the object
return type will need to be cast to the data type you want.
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use the method:
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current value stored in the user profile on the SDK, you need to use methods:
This is how you can set properties on the current user profile:
It is important to remember that the key for custom user properties has a length limit. If the limit is exceeded (from 1 to 64 characters), the key will be truncated to the maximum allowed length
To get the current values stored in the user profile on the SDK, you need to use the methods:
TryGetBool(key: String, callback: Callable)
TryGetFloat(key: String, callback: Callable)
TryGetInt(key: String, callback: Callable)
TryGetString(key: String, callback: Callable
The isValid parameter is responsible for the presence of the requested key in the user card.
It removes a property or a list of properties and their values from the current user profile.
To remove all properties from the user card, use:
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the SetCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the SetCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the SetCheater
method.
Keep in mind that the cheater mark is not cleared from the user card; you can only uncheck the mark manually using the setCheater
method.
A/B testing is the best way to challenge your hypotheses. A/B testing is essentially an experiment where you show your users different variants of the app at random and then analyze the results to determine which variation performed better.
In devtodev, you can work with A/B testing in the ‘A/B Testing’ section on the app level. All tests are stored in one table. Besides basic information about each test, you can see its status. There are five types of status:
Draft - draft of an unexecuted test.
Stopped - the test was stopped before completion. It’s not possible to restart the test. If you want to restart it, make a copy of the test and launch it.
In progress - the test is currently in progress.
Finished: No winner - test results determined that there was no winner.
Finished: Success - test results determined a winner group.
Before creating a test in the devtodev interface, you need to set variables through the SDK and use the methods for launching A/B tests. Use certain classes to set the variables and their default values. In case the variables are involved with the test, their values will vary depending on the group defined by the server. If the app will be offline and won’t be able to present the test to the user, he will see default values and the app will continue to function correctly.
Here you can find more information about SDK configuration (about setting variables and methods for launching A/B tests).
To go to the test creation wizard, open the desired devtodev project, navigate to the ‘A/B Testing’ tab and click the ‘+ Add new A/B test’ button.
You have opened the segment creation wizard that consists of five steps:
In this section, you need to create test assignment rules and define the audience size. Use the ‘Filter your audience’ and ‘Triggering event’ sections to set the assignment rules.
Filter your audience - use this option to define user properties that are needed to be included into the test. The devtodev SDK which is integrated into the application, will use the filters to select the audience whose current properties match the test requirements.
In this example, all paying users will participate in the test.
If you use several filters at once, only users or devices (this depends on the selected user identification method) that meet all conditions will participate in the test.
Set a triggering event if you want your test to include only the users who performed a certain event.
In this example, the devtodev SDK will include the user or device (this depends on the selected user identification method) in the test when the SDK receives information that the said user or device reached the fourth level.
The selected filters and trigger events cannot be altered after the start of the experiment.
The filters and trigger events become available for audience configuration after at least one event/property is received via the SDK, processed and accounted for in the devtodev analytics.
When applying both filters and trigger events, all conditions have to be met for the user/device to be included into the test.
Audience fraction - use this option to define the percentage or an absolute number of users out of those selected by the filter and/or completed the trigger event who will participate in the test. If the initial audience size is not enough for drawing firm conclusions, you can change it even after the test begins.
Please note that one user can participate in only one test at a time.
If you need to run several tests in parallel, then:
You need to create non-overlapping test audiences
If your audience overlaps, you need to configure the audience fraction so that part of the audience will be included into each test (e.g. 50% of the overlapping audience gets included into each of the two tests).
If you know the number of users that you need to achieve a statistically significant result, insert it in the ‘Max number of observation’ cell.
In this example,100% of users who completed more than three levels at the time of a sign up will be included in the test.
A user can be excluded from the test only in two cases:
The test time is up.
The test is stopped.
In this section, you can define the goal of your A/B test - metrics for analysis, criteria for stopping the experiment for a group, and the duration of the experiment.
You can set up one ‘Primary metric’ and no more than five ‘Secondary metrics’ for each test. The ‘Primary metric’ is used to assess the test result and to calculate statistical significance of the obtained result. ‘Secondary metrics’ are optional and do not take part in the final result assessment. However, they can improve the quality of the analysis and prove that the implemented changes did not influence other key metrics of the app.
For example, you can select one of the following as a secondary metric:
One of the fundamental metrics (ARPU, Paying conversion, Day-N retention, etc.)
User engagement with an event.
Average number of times an event was completed (per user).
Below, you can set the ‘Estimated experiment duration’ (days). The test will be stopped after the set number of days. You can also automatically stop the test execution in case the winning group is defined - simply check the ‘Stop the experiment when there is a winning group’ box.
If you don’t see any sense in continuing the test or you want to change the group settings and restart it, you are free to change the duration of the test or even stop it anytime during its course.
The main goal of the test above is to improve conversion to payment. However you can use the same method to test the conversion to trial or to ARPU.
One of the most crucial steps is setting up test groups and variables. You create a config containing various groups and their parameters. After the devtodev SDK reports that the user has been successfully included in the experiment, one of the groups becomes available in the app via the SDK.
By default, there are two groups available to you: Group A and a control group. You can increase the number of groups to maximum 4 in a single test by clicking the ‘+Add group’ button.
The control group usually includes users as they currently are. This way, you can test other variants to see the change in their metrics, relative to the same metrics at the moment. For each group you need to define a set of variables that is composed of the name of the variable and its value. The variables have to be defined inside of your app - they are supposed to grant your users different experiences.
In the above example, you can see three groups: the control group (it has default parameters) and two more groups that have other parameters for the button_color and button_size variables. The test will be focused on defining the most favorable size and color of the button. If one of the groups wins, it may lead to the change of interface for all users of the app.
When the app is launching, the SDK defines the test that the user will participate in. Then he is randomly assigned to a test group and the SDK applies all the variables defined for this group.
To make sure that all the test groups are set up correctly and that the app is handling the selected variables the right way, we highly recommend you to test the current test settings. In this section, you can check how the A/B test configuration runs on test devices, manually determine relevant groups for them and also check how the design and app behavior change in different groups.
Click ‘+Add test device’ to add a test device using an Advertising ID / User ID / devtodev ID or select it from the list of test devices in the current devtodev Space. After that, select a user group that you want to test on and click ‘Start checking’.
The settings of the selected group will be applied to the selected test device. From this moment on, the test device will start the test for the selected group and they will not wait for meeting the entry conditions that you have specified above.
Test devices do not save the information about the active test or the group. After you successfully finish testing one group, select the next one for the same test device and click ‘Restart checking’.
To be able to access the active test and its group at a test device after restarting the app, use the DTDRemoteConfig.сacheTestExperiment()
method before initializing the SDK.
After you check all group settings on the test devices, you can launch the test for the entire selected audience or save it as a draft.
A maximum of 8 A/B tests can be run simultaneously in one project.
The test can have several outcomes. Let's look at them in more detail.
Force stop and test delete
It may so happen that you’ve launched an incorrectly configured test and now you need to stop it. To do this, you can select the required test by clicking on it in the list of experiments.
To stop the test (full stop, no chance to resume) - open the A/B test report and click on the edit icon in the upper right corner. The test editing wizard will open. Click on the Stop Test button at the bottom of the wizard page.
To remove the A/B test from the list - open the test editing wizard. At the bottom of the wizard page, click the Delete Test button. Please note that you can delete only the tests that were stopped or completed. The created A/B tests stay in the project until the user deletes them.
The SDK updates the A/B test config only during initialization. If the deleted experiment was previously activated on any device, then when the SDK is initialized, it will be available for activation. After the config gets updated, the SDK will remove this test from the database but will not report it via external interfaces.
This is intended to avoid changing the app settings that were received from the experiment config at the beginning of the session (e.g, the UI that the user is currently interacting with). The next time the app starts, the test will be deleted during SDK initialization.
Do not update the app interface and behavior when the user interacts with it. Do not use the network to receive default parameters. It is better to define them in the app
Test completion using the specified criteria
If you check the ‘Stop the experiment when there is a winning group’ box at the third step of the A/B test creation process, the test will automatically stop if ‘Probability to be best’ of one of the groups is larger than 95%. This metric (Probability to be best) can be considered to be a Bayesian approach. This value is auto-calculated for each group based on the selected Primary metric. If you want to stop the test when reaching a higher number (e.g. 99%), you can change the test duration and continue with its execution until you reach the desired outcome.
The test can finish when it reaches the end of the time period specified at the ‘Goals’ step in the ‘Estimated experiment duration → duration days’ section which is responsible for the test duration. For example, you set ‘duration days’ as 3. This means that the entire audience has only three days since the test creation to be included into the test and participate in it. When the app is launched and the SDK is initialized, it will compare the current time with the end time of the test. If the experiment time is up, the SDK will erase the test from the database and the users will not be able to receive any data. If the test time has run out when the app has been used, the SDK will not respond.
This is intended to avoid changing the app settings that were received from the experiment config at the beginning of the session (e.g, the UI that the user is currently interacting with). The next time the app starts, the test will be deleted as described above.
During the test execution, a report on the test results will be built and updated in real time. In the upper block, you can find all the basic information about the current state:
Current test status
Name of the group with the highest ‘Probability to be best’ and its value
Number of groups, total number of users in the test, and number of users in each group
Experiment time frame
Below you can see a graph. Its horizontal axis represents calendar days starting from the test start date, while the vertical axis represents the value of the selected metric for each of the groups. You can select the displayed metric in the top left corner of the graph. These are:
The Primary and Secondary metrics selected in the wizard
Probability to be best
A/B test audience
Underneath you can find a table with aggregated values for each of the metrics in each test group and their fluctuations relative to the control group. The ‘Probability to be best’ is also calculated for each metric including the Secondary. This way you can make sure that all the tested changes do not influence other metrics in a negative way. After that you can see the funnels configured in the A/B test creation wizard. They contain data on the number of users at each funnel stage, conversion rate from one stage to another, and the ‘Probability to be best’ for conversion from the first to the last stage.
When a user gets included into a test group, he is automatically marked with the ID of this group.
If you want to drill down even more and understand a subtle difference in metrics and behavior of the users, you can use these user groups as filters in any devtodev reports. Simply go to the report filters, open the ‘Segments’ tab, and select the required segment.
A/B test segment values are saved as a separate user property (‘A/B test groups’) in the user card at the moment the user gets included into an A/B test group.
The user can not enroll into two A/B tests at the same time. He can be included into one test and after it completes, be included into another. In this case, the ‘ A/B test groups’ field will contain names of the two groups.
iOS Integration
You use Member Center to generate a push notification client SSL certificate that allows your notification server to connect to the APNs. Each App ID is required to have its own client SSL certificate. The client SSL certificate Member Center generates is a universal certificate that allows your app to connect to both the development and production environments.
Only a team agent or admin can generate Apple Push Notification service SSL certificates.
To generate a universal client SSL certificate
In , select Certificates.
Click the Add button (+)
Under Production, select the “Apple Push Notification service SSL (Sandbox & Production)” checkbox, and click Continue.
Choose an App ID from the App ID pop-up menu, and click Continue. Choose the explicit App ID that matches your bundle ID.
Create a certificate request on your Mac.
Click Choose File.
In the dialog that appears, select the certificate request file (with a .certSigningRequest extension), and click Choose File.
Click Generate.
Click Download.
Open "Keychain access" application
If the certificate hasn't been added to keychain access yet, choose "File" → "Import". Find the certificate file (CER-file) provided by Apple
Choose "Keys" section in "Keychain access" application
Choose a personal key associated with your iPhone developer certificate. Personal key is identified by open certificate associated with it "iPhone developer: ". Choose "File" → Export objects. Save key as .p12
You'll be suggested to create a password which is used when you need to import the key to another computer
Upload the .p12-file into Integration section of application settings panel (Settings -> Push Notifications):
2. After the DTDAnalytics initialization block call the StartNotificationService
method to activate the Messaging module:
You can listen to basic notification module events. To do this, create a class that implements the IDTDPushListener
interface and pass it to the DTDMessaging.IOS.SetPushListener
method.
Example:
You can specify the necessary display options using the DTDMessaging.IOS.SetNotificationOptions
method.
Example:
A complete example of the notification module initialization:
It is an OptionSet used for push notification authorization and configuration interaction with users.
Attention: The user can change the allowed parameters in the notification settings at any time.
Possible values:
DTDNotificationOptionBadge
- an option for displaying a badge on the application icon
DTDNotificationOptionSound
- an option for playing sound
DTDNotificationOptionAlert
- an option for displaying an alert
DTDNotificationOptionCarPlay
- an option for showing a push notification in CarPlay DTDNotificationOptionCriticalAlert
- an option for playing sound for critical alerts regardless of whether “do not disturb” is on or not. (Critical alerts require special permission from Apple). Available from iOS 12.0 onwards
DTDNotificationOptionProvidesSettings
- an option for indicating that the system should show a notification settings button in the application. Available from iOS 12.0 onwards
DTDNotificationOptionProvisional
- an option for sending provisional notifications to the Notification Center without interrupting functioning processes. Available from iOS 12.0 onwards
DTDNotificationOptionAnnunciation
- an option for Siri to automatically read messages through AirPods. Available from iOS 13.0 onwards
Attention: DTDNotificationOptionProvisional
- Provisional push notifications are shown in the User Notification Center but not on the lock screen. This type of push notification doesn’t require an explicit opt-in from the user. You can start sending them as soon as the user installs and launches your app. However, the user can also explicitly enable/disable your notifications.
Use this setting to avoid the permission request on app launch because it is seen as intrusive, and most users opt-out of it.
It’s also important that when using the DTDNotificationOptionProvisional
setting, the user needs to go to Notification Center settings to allow explicit notifications.
After the build, open the signing and capabilities tab in the XCode project settings and add "Push Notifications" and "Background Modes" (tick the box against Remote notifications).
The framework provides support for iOS 10+ notification attachments, such as images, animated gifs, and video. In order to take advantage of this functionality, you will need to create a notification service extension alongside your main application. Create a new iOS target in Xcode (File -> New -> Target) and select the Notification Service Extension type. In the Member Center, a Push Notifications service will appear as Configurable (not Enabled) until you create a client SSL certificate.
The framework supports notification attachments: images, audio, and video. To enable the functionality, you need to complete several steps:
Create a new iOS target in Xcode (File -> New -> Target) and select the Notification Service Extension
Set language to ‘Swift’
In the next window, click ‘Activate’
In the ‘Build Settings’ tap, change 'Architectures’ to ‘Standard Architecture (arm64, armv7)
Open the ‘Frameworks’ folder in your project, find the ‘DTDMessagingUnity’ framework and tick the box of your target in the ‘Target Membership’ section
In the NotificationService class (in the folder named after your target), replace the code with the following:
When creating a push company, it is important to specify the full name of the sound with file extension (for example, sound.wav).
Download the latest version of devtodev package from the repository:
Initialize the DTDAnalytics
module (see our ).
Add DTDSubscriptions.Initialize(IStoreController controller)
to the method.
If you use AppleStore, first set the DTDSubscriptions.IsRestoring
property to true (this will filter out unwanted transactions). After , call the DTDSubscriptions.History()
method. After that, set the DTDSubscriptions.IsRestoring propert
y to false.
This event is for games only. It is worthwhile to integrate this event into a game type project, as specified in the . In projects with the “app” type, game events will not be tracked and displayed in the interface, even if they are integrated. You can verify and change the project type in Settings → .
The event allows you to analyze the distribution of players over different game levels, monitor the in-game currency balance by levels. You can find more information about the right moment to use LevelUp
event .
This event is for games only. It is worthwhile to integrate this event into a game type project, as specified in the . In projects with the “app” type, game events will not be tracked and displayed in the interface, even if they are integrated. You can verify and change the project type in Settings → .
This event is for games only. It is worthwhile to integrate this event into a game type project, as specified in the . In projects with the “app” type, game events will not be tracked and displayed in the interface, even if they are integrated. You can verify and change the project type in Settings → .
This event is for games only. It is worthwhile to integrate this event into a game type project, as specified in the . In projects with the “app” type, game events will not be tracked and displayed in the interface, even if they are integrated. You can verify and change the project type in Settings → .
This event is for games only. It is worthwhile to integrate this event into a game type project, as specified in the . In projects with the “app” type, game events will not be tracked and displayed in the interface, even if they are integrated. You can verify and change the project type in Settings → .
We strongly recommend not to use these properties because they refer to .
Attention! We strongly recommend that you do not use these properties to transfer and store data that fits the definition of !
Enter a unique name of the test and its description. Try to make the description of the test as detailed as possible: its hypothesis, audience, description of the test groups, target metric, desired outcome, etc. Or simply insert a link to the test description. To learn more about test planning, open
To each trigger event, you can add more parameters that are related to the event. Events have different lists of additional parameters (see ). Please note that you can’t use an event that you sent to devtodev via API as a trigger event.
To calculate the size of the test audience, use any of the . To use them, first estimate the current value of the Primary metric and then define the result that you expect to get from the tested changes. In addition, you can set up several user experience funnels and display their results in the test report. This will give you additional information about how successful the test has been.
1. For the Messaging module to function you need the basic Analytics package. Before the notification initialization, you need to initialize the SDK. More about it you can read here: .
To use custom sounds for push notifications, you need to copy the necessary sound files to the Libraries folder of your Xcode project. You can read more about supported formats .
orderId
string
from 1 to 65 symbols
A unique transaction ID.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
string
from 1 to 65 symbols
A unique transaction ID.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from double.MinValue to double.MaxValue
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
string
from 1 to 65 symbols
A unique transaction ID.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.MinValue to Double.MaxValue
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
string
from 1 to 65 symbols
A unique transaction ID.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Number.MIN_VALUE to Number.MAX_VALUE
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
FString
from 1 to 65 symbols
A unique transaction ID.
currencyCode
FString
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
float
from float.MinValue to float.MaxValue
The item price in the transaction currency.
productId
FString
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
String
from 1 to 65 symbols
A unique transaction ID.
currencyCode
String
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
Float
from Double.min to Double.max
The item price in the transaction currency.
productId
String
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
Long
from Long.min to Long.max
String
from 1 to 255 symbols
Boolean
true/false
Double
from Double.min to Double.max
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
Long
from Long.min to Long.max
String
from 1 to 255 symbols
Boolean
true/false
Double
from Double.min to Double.max
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
long
from long.MinValue to long.MaxValue
string
from 1 to 255 symbols
bool
true/false
double
from double.MinValue to double.MaxValue
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
long
from Int64.MinValue to Int64.MaxValue
string
from 1 to 255 symbols
bool
true/false
double
from Double.MinValue to Double.MaxValue
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
object
key - from 1 to 32 symbols
value - see below
Custom event parameters.
long
from Number.MIN_SAFE_INTEGER to Number.MAX_SAFE_INTEGER
string
from 1 to 255 symbols
bool
true/false
double
from Number.MIN_VALUE to Number.MAX_VALUE
eventName
FString
from 1 to 72 symbols
Custom event name.
eventName
FString
from 1 to 72 symbols
Custom event name.
parameters
FDTDCustomEventParams
StringParameters (TMap<FString, FString>)
IntParameters (TMap<FString, int64>)
FloatParameters (TMap<FString, float>)
BoolParameters (TMap<FString, bool>)
key - from 1 to 32 symbols
value - see below
Custom event parameters.
Warning: avoid duplicate keys in all dictionaries. Because dictionaries are combined into a generic dictionary [string: any] in native code.
int64
from int64.MinValue to int64.MaxValue
FString
from 1 to 255 symbols
bool
true/false
float
from float.MinValue to float.MaxValue
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
GDDTDCustomEventParams
key - from 1 to 32 symbols
value - see below
Custom event parameters.
int
from Int64.min to Int64.max
String
from 1 to 255 symbols
bool
true/false
Float
from Float.min to Float.max
Parameter
Type
Restrictions
Description
orderId
string
from 1 to 65 symbols
A unique transaction identifier.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
Parameter
Type
Restrictions
Description
orderId
string
from 1 to 65 symbols
A unique transaction identifier.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
step
int32
From 1 to int32.MaxValue - 1
Tutorial step
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int32
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
0
The user skipped the tutorial
-1
The value defines the beginning of the tutorial
1..int
Counting number of completed tutorial stage
-2
The value defines the completion of the tutorial
level
int
From 1 to Int32.max - 1
Level reached
balances
[String:Int]
String - from 1 to 24 symbols
Int - from Int64.min to int64.max
Resources’ names and number at the time of level up
level
NSInteger
From 1 to Int32.max - 1
Level reached
balances
NSDictionary<NSString *,NSNumber *>
String - from 1 to 24 symbols
Int - from Int64.min to int64.max
Resources’ names and number at the time of level up
level
int
From 1 to Int.max - 1
Level reached
balances
Map<String,Long>
String - from 1 to 24 symbols
Long - from Long.min to Long.max
Resources’ names and number at the time of level up
level
int
From 1 to Int.max - 1
Level reached
balances
Map<String,Long>
String - from 1 to 24 symbols
Long - from Long.min to Long.max
Resources’ names and number at the time of level up
level
int
From 1 to int.MaxValue - 1
Level reached
balances
[string: long]
String - from 1 to 24 symbols
Long - from long.MinValue to long.MaxValue
Resources’ names and number at the time of level up
level
int
From 1 to int32.MaxValue - 1
Level reached
balances
[string: long]
String - from 1 to 24 symbols
Long - from long64.MinValue to long64.MaxValue
Resources’ names and number at the time of level up
level
int
From 1 to int.MaxValue - 1
Level reached
balances
[string: long]
String - from 1 to 24 symbols
Long - from long.MinValue to long.MaxValue
Resources’ names and number at the time of level up
spent
[string: long]
String - from 1 to 24 symbols Long - from 0 to Number.MAX_SAFE_INTEGER
Game currency amount spent during the level. Optional.
earned
[string: long]
String - from 1 to 24 symbols Long - from 0 to Number.MAX_SAFE_INTEGER
Game currency earned during the level. Optional.
bought
[string: long]
String - from 1 to 24 symbols Long - from 0 to Number.MAX_SAFE_INTEGER
Game currency amount bought during the level. Optional.
level
int32
From 1 to int32.MaxValue - 1
Level reached
level
int32
From 1 to int32.MaxValue - 1
Level reached
balance
TMap<FString, int64>
FString - from 1 to 24 symbols
int64 - from int64.MinValue to int64.MaxValue
Resources’ names and number at the time of level up
level
int
From 1 to Int32.max - 1
Level reached
balances
GDDTDInt64Resources
String - from 1 to 24 symbols
Int - from Int64.min to int64.max
Resources’ names and number at the time of level up
balance
TMap<FString, int64>
FString - from 1 to 24 symbols
int64 - from int64.MinValue to int64.MaxValue
Resources’ names and number
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int32.max
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
NSString
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
NSInteger
from 1 to Int32.max
Amount of currency in circulation
source
NSString
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int.max
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int.max
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int.MaxValue
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int32.MaxValue
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
DTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
string
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int.max
Amount of currency in circulation
source
string
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
int
The currency/resource source type. The player can either gain resources during the game (0
) or purchase them for money (1
)
currencyName
FString
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int32
from 1 to Int32.MaxValue
Amount of currency in circulation
source
FString
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
EDTDAccrualType
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
currencyName
String
from 1 to 24 symbols
In-game currency/resource name
currencyAmount
int
from 1 to Int32.max
Amount of currency in circulation
source
String
from 1 to 23 symbols
The sources of currency/resources. It can be used for breaking down income by its sources. For example, a city builder game may have some: “Rent” for the profit received from rental property, or “Bank” if the player has purchased some currency.
accrualType
GDDTDAccrualType (enum)
The currency/resource source type. The player can either gain resources during the game (earned
) or purchase them for money (bought
)
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Int32.max
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Int32.max
The price of the purchased item in the specified in-game currency.
purchaseId
NSString
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
NSString
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
NSInteger
from 1 to Int32.max
The number of units of goods purchased.
purchaseCurrency
NSString
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
NSInteger
from 1 to Int32.max
The price of the purchased item in the specified in-game currency.
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Int.max
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Int.max
The price of the purchased item in the specified in-game currency.
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Int.max
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Int.max
The price of the purchased item in the specified in-game currency.
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to int.MaxValue
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to int.MaxValue
The price of the purchased item in the specified in-game currency.
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Int32.MaxValue
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Int32.MaxValue
The price of the purchased item in the specified in-game currency.
purchaseId
string
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
string
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Number.MAX_SAFE_INTEGER
The number of units of goods purchased.
purchaseCurrency
string
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Number.MAX_SAFE_INTEGER
The price of the purchased item in the specified in-game currency.
purchaseId
FString
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
FString
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int32
from 1 to Int32.MaxValue
The number of units of goods purchased.
purchaseCurrency
FString
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int32
from 1 to Int32.MaxValue
The price of the purchased item in the specified in-game currency.
purchaseId
FString
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
FString
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int32
from 1 to int32.MaxValue
The number of units of goods purchased.
resources
TMap<FString, int32>
FString - from 1 to 24 symbols
int32 - from 1 to int32.MaxValue
Map with resources.
purchaseId
String
from 1 to 32 symbols
A unique purchase name or ID. Make sure that the names are always in the same language otherwise they will be listed as different items.
purchaseType
String
from 1 to 96 symbols
The name of a resource group. For example, for “Wood” it can be “Construction materials”.
purchaseAmount
int
from 1 to Int32.max
The number of units of goods purchased.
purchaseCurrency
String
from 1 to 24 symbols
The name of a currency used for the purchase.
purchasePrice
int
from 1 to Int32.max
The price of the purchased item in the specified in-game currency.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Int32.max
An optional difficulty value which is set using the value: setDifficulty(difficulty: Int)
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int
from 0 to Int64.max
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
[String: Int]
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources consumed during an area completion.
earned
[String: Int]
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources earned during an area completion.
eventName
NSString
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
NSString
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
NSInteger
from 0 to Int32.max
An optional difficulty value which is set using the value: setDifficulty(difficulty: Int)
eventName
NSString
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
BOOL
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
NSInteger
from 0 to Int64.max
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
NSDictionary<NSString *,NSNumber *>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources consumed during an area completion.
earned
NSDictionary<NSString *,NSNumber *>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources earned during an area completion.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Int32.max
An optional difficulty value which is set using the value: setDifficulty(difficulty: Int)
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int
from 0 to Int64.max
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
Map<String, Long>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources consumed during an area completion.
earned
Map<String, Long>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources earned during an area completion.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Int32.max
An optional difficulty value which is set using the value: setDifficulty(difficulty: Int)
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int
from 0 to Int64.max
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
Map<String, Long>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources consumed during an area completion.
earned
Map<String, Long>
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources earned during an area completion.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to int.MaxValue
An optional difficulty value.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True
’ if successful, ‘false
’ if unsuccessful/lost.
duration
int
from 0 to int.MaxValue
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between StartProgressionEvent
and FinishProgressionEvent
method calls.
spent
[String: Int]
key - from 1 to 24 symbols
value - From 1 to int.MaxValue
Resources consumed during an area completion.
earned
[String: Int]
key - from 1 to 24 symbols
value - From 1 to int.MaxValue
Resources earned during an area completion.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Int32.MaxValue
An optional difficulty value.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True
’ if successful, ‘false
’ if unsuccessful/lost.
duration
int
from 0 to Int64.MaxValue
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between StartProgressionEvent
and FinishProgressionEvent
method calls.
spent
[String: Int]
key - from 1 to 24 symbols
value - From 1 to Int64.MaxValue
Resources consumed during an area completion.
earned
[String: Int]
key - from 1 to 24 symbols
value - From 1 to Int64.MaxValue
Resources earned during an area completion.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
parameters
object
see below
Location event parameters.
source
string
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Number.MAX_SAFE_INTEGER
An optional difficulty value.
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
parameters
object
see below
Location event parameters.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int
from 0 to Number.MAX_SAFE_INTEGER
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
[String: Int]
key - from 1 to 24 symbols
value - from 1 to Number.MAX_SAFE_INTEGER
Resources consumed during an area completion.
earned
[String: Int]
key - from 1 to 24 symbols
value - from 1 to Number.MAX_SAFE_INTEGER
Resources earned during an area completion.
eventName
FString
from 1 to 72 symbols
Progression event name.
eventName
FString
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
params
FDTDStartProgressionEventParams
see below
Start progression event parameters.
source
FString
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int32
from 0 to int32.MaxValue
An optional difficulty value.
eventName
FString
from 1 to 72 symbols
Progression event name.
eventName
FString
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
parameters
FDTDFinishProgressionEventParams
see below
Finish progression event parameters.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int32
from 0 to int32.MaxValue
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
TMap<FString, int64>
key - from 1 to 24 symbols
value - from 0 to int64.MaxValue
Resources consumed during an area completion.
earned
TMap<FString, int64>
key - from 1 to 24 symbols
value - from 0 to int64.MaxValue
Resources earned during an area completion.
eventName
String
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area.
source
String
from 1 to 40 symbols
The name of the previous event used for connecting events together. E.g. a previous area visited by the player.
difficulty
int
from 0 to Int32.max
An optional difficulty value which is set using the value: SetDifficulty()
eventName
string
from 1 to 40 symbols
The name of the event. It is usually the number or the name of the area. It’s important to use the name that was specified at the area’s opening.
successfulCompletion
bool
true/false
The completion event result. ‘True’ if successful, ‘false’ if unsuccessful/lost.
duration
int
from 0 to Int64.max
Time in seconds taken to complete the area. If not specified, it is automatically calculated as the difference between startProgressionEvent
and finishProgressionEvent
method calls.
spent
GDDTDInt64Resources
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources consumed during an area completion.
earned
GDDTDInt64Resources
key - from 1 to 24 symbols
value - from 1 to Int64.max
Resources earned during an area completion.
userId
FString
User ID.
onResult
FAnalyticsDynamicGetterStringDelegate
FDTDGetterStringDelegate
Callback
level
int32
Current level.
onResult
FAnalyticsDynamicGetterIntDelegate
FDTDGetterIntDelegate
Callback
cheater
bool
Cheater flag
tester
bool
Tester flag
Property
Getter
Setter
Name
setName(name: String)
getName(completionHandler: @escaping (String?) -> Void)
setEmail(email: String)
getEmail(completionHandler: @escaping (String?) -> Void)
Phone
setPhone(phone: String)
getPhone(completionHandler: @escaping (String?) -> Void)
Photo
setPhoto(photo: String)
getPhoto(completionHandler: @escaping (String?) -> Void)
Gender
setGender(gender: DTDGender)
getGender(completionHandler: @escaping (DTDGender) -> Void)
Age
setAge(age: Int)
getAge(completionHandler: @escaping (Int) -> Void
Property
Setter
Getter
Age
[DTDUserCard setAge:(NSInteger)];
[DTDUserCard getAgeHandler:^(NSInteger age) { }]
[DTDUserCard setEmail:(NSString * _Nonnull)];
[DTDUserCard getEmailHandler:^(NSString * email) { }];
Gender
[DTDUserCard setGender:(enum Gender)];
[DTDUserCard getGenderHandler:^(enum Gender gender) { }];
Name
[DTDUserCard setName:(NSString * _Nonnull)];
[DTDUserCard getNameHandler:^(NSString * name) { }];
Phone
[DTDUserCard setPhone:(NSString * _Nonnull)];
[DTDUserCard getPhoneHandler:^(NSString * phone) { }];
Photo
[DTDUserCard setPhoto:(NSString * _Nonnull)];
[DTDUserCard getPhotoHandler:^(NSString * photo) { }];
Property
Getter
Setter
Name
setName(name: String)
getName(handler: (String) -> Unit)
setEmail(email: String)
getEmail(handler: (String) -> Unit)
Phone
setPhone(phone: String)
getPhone(handler: (String) -> Unit)
Photo
setPhoto(photo: String)
getPhoto(handler: (String) -> Unit)
Gender
setGender(gender: DTDGender)
getGender(handler: (DTDGender) -> Void)
Age
setAge(age: Int)
getAge(handler: (String) -> Unit)
Property
Getter
Setter
Name
setName(name: String)
getName(handler: (String) -> Unit)
setEmail(email: String)
getEmail(handler: (String) -> Unit)
Phone
setPhone(phone: String)
getPhone(handler: (String) -> Unit)
Photo
setPhoto(photo: String)
getPhoto(handler: (String) -> Unit)
Gender
setGender(gender: DTDGender)
getGender(handler: (DTDGender) -> Void)
Age
setAge(age: Int)
getAge(handler: (String) -> Unit)
Property
Getter
Setter
Name
SetName(name: string)
Task<string> GetName();
SetEmail(email: string)
Task<string> GetEmail()
Phone
SetPhone(phone: string)
Task<string> GetPhone()
Photo
SetPhoto(photo: string)
Task<string> GetPhoto()
Gender
SetGender(gender: DTDGender)
Task<DTDGender> GetGender()
Age
SetAge(age: long)
Task<long> GetAge()
Property
Getter
Setter
Name
SetName(name: string)
GetName(Action<string> onGetName)
SetEmail(email: string)
GetEmail(Action<string> onGetEmail)
Phone
SetPhone(phone: string)
GetPhone(Action<string> onGetPhone)
Photo
SetPhoto(photo: string)
GetPhoto(Action<string> onGetPhoto)
Gender
SetGender(gender: DTDGender)
GetGender(Action<DTDGender> onGetGender)
Age
SetAge(age: long)
GetAge(Action<string> onGetAge)
Property
Getter
Setter
Type
Name
getName()
setName("John Doe")
String
getEmail()
setEmail("email@me.com")
String
Phone
getPhone()
setPhone("+15555555555")
String
Photo
getPhoto()
setPhoto("https://domain.com/photo.jpg")
String
Gender
getGender()
setGender(gender)
Age
getAge()
setAge(age)
Int
Name
SetName(name: FString)
GetName(delegate: FUserCardDynamicGetterStringDelegate)
GetName(delegate: FDTDGetterStringDelegate)
Email
SetEmail(email: FString)
GetEmail(delegate: FUserCardDynamicGetterStringDelegate)
GetEmail(delegate: FDTDGetterStringDelegate)
Phone
SetPhone(phone: FString)
GetPhone(delegate: FUserCardDynamicGetterStringDelegate)
GetPhone(delegate: FDTDGetterStringDelegate)
Photo
SetPhoto(photo: FString)
GetPhoto(delegate: FUserCardDynamicGetterStringDelegate)
GetPhoto(delegate: FDTDGetterStringDelegate)
Gender
SetGender(gender: EDTDGender)
GetGender(delegate: FUserCardDynamicGetterGenderDelegate)
GetGender(delegate: FDTDGetterGenderDelegate)
Age
SetAge(age: int64)
GetAge(delegate: FUserCardDynamicGetterLongDelegate)
GetAge(delegate: FDTDGetterLongDelegate)
key
FString
Parameter key.
value
bool
Parameter value.
key
FString
Parameter key.
value
float
Parameter value.
key
FString
Parameter key.
value
int64
Parameter value.
key
FString
Parameter key.
value
FString
Parameter value.
key
FString
Parameter key.
onResult
FUserCardDynamicGetterOptionalBoolDelegate
FDTDGetterOptionalBoolWithKeyDelegate
Callback.
key
FString
Parameter key.
onResult
FUserCardDynamicGetterOptionalFloatDelegate
FDTDGetterOptionalFloatWithKeyDelegate
Callback.
key
FString
Parameter key.
onResult
FUserCardDynamicGetterOptionalLongDelegate
FDTDGetterOptionalLongWithKeyDelegate
Callback.
key
FString
Parameter key.
onResult
FUserCardDynamicGetterOptionalStringDelegate
FDTDGetterOptionalStringWithKeyDelegate
Callback.
key
FString
Parameter key.
keys
TArray<FString>
Parameter keys.
void DTDMessaging.IOS.StartPushService()
The method responsible for push notification activation:
Requests user permission to receive push notifications
Sends push token and current state isAllowed
void DTDMessaging.IOS.GetToken(Action<string> onGetToken)
The method that returns current push token to onGetToken
callback
DTDMessaging.IOS.SetPushListener(IDTDPushListener listener)
The method for assigning a push notification event listener
void DTDMessaging.IOS.PushNotificationsOptions(uint options)
options is responsible for setting up the display of Push Notifications. It is set by the developer to select the method of notifying the user. It can be changed by the end-user.
By default, it has the value:
[.DTDNotificationOptionBadge, .DTDNotificationOptionSound, .DTDNotificationOptionAlert]
void DTDMessaging.IOS.PushIsAllowed (bool isAllowed )
The method is responsible for enabling / disabling the ability to send a push notification to the user from devtodev.
void DTDMessaging.IOS.GetPushState(Action<bool> onGetPushState)
The method that returns the push module state to onGetPushState
callback
void OnPushServiceRegistrationSuccessful (string deviceId);
The method is called if a push token is successfully received, represented by a string.
void OnPushServiceRegistrationFailed (string error);
The method is called if at the time of receiving a pushToken errors occur. It passes the text of the error that occurred
void OnInvisibleNotificationReceived (DTDPushMessage message);
The method is called when an invisible remote push notification is received. The DTDPushMessage
object is passed
void OnPushNotificationReceived (DTDPushMessage message);
The method is called when a remote push notification is received while the application runs in the Foreground state. The DTDPushMessage
object is passed.
void OnPushNotificationOpened (DTDPushMessage pushMessage, DTDActionButton actionButton);
The method is called when the end-user opens a remote push notification. The DTDPushMessage
object and the optional DTDActionButton
object are passed.
IDictionary<string,string> GetData():
Complete information passed with the push notification.
DTDActionType ActionType:
The property that returns the value of enum’s DTDActionType
.
Possible values:
App
- app open
Url
- external link open
Share
- share content
Deeplink
- open a link that leads straight to a specific in-app location
string ActionString
The property that returns an optional action identifier
IDictionary<string,string> AdditionalData()
Additional data sent to push notification
DTDActionType ActionType
The property that returns the value of enum’s DTDActionType
.
Possible values:
App
- app open
Url
- external link open
Share
- share content
Deeplink
- open a link that leads straight to a specific in-app location
string ActionString
The property that returns an optional action identifier
string ButtonId
The property that returns the ID of the clicked button
string ButtonText
The property that returns the text of the clicked button
orderId
string
from 1 to 65 symbols
A unique transaction ID. Use transactionIdentifier
property value in SKPaymentTransaction
object in a complete transaction receipt.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
NSString
from 1 to 65 symbols
A unique transaction ID. Use transactionIdentifier
property value in SKPaymentTransaction
object in a complete transaction receipt.
currencyCode
NSString
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
NSString
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
orderId
string
from 1 to 65 symbols
A unique transaction ID.
currencyCode
string
precisely 3 symbols
Transaction currency (ISO 4217 standard) e.g. USD, EUR etc.
price
double
from Double.min to Double.max
The item price in the transaction currency.
productId
string
from 1 to 255 symbols
Item name. We recommend using a bundle or names in the same language.
eventName
string
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
int
from Int64.min to Int64.max
string
from 1 to 255 symbols
bool
true/false
double
from Double.min to Double.max
eventName
NSString
from 1 to 72 symbols
Custom event name.
parameters
DTDCustomEventParameters
key - from 1 to 32 symbols
value - see below
Custom event parameters.
int
from Int64.min to Int64.max
string
from 1 to 255 symbols
bool
true/false
double
from Double.min to Double.max
Some operations can take a while because the SDK operates asynchronously. These operations are:
A/B test configuration.
After you’ve created an A/B test in the web interface, the SDK will receive its configuration via the network. Use the remoteConfigWaiting
property in the DTDRemoteConfig
class to set the maximum time allowed for waiting for the A/B test configuration.
remoteConfigWaiting
is set in seconds
By default, the remoteConfigWaiting
value is equal to null. This means that the test configuration waiting time is unlimited. The limitation is important in case the test that you are about to execute can influence your app functioning.
Example: DTDRemoteConfig.remoteConfigWaiting = 10
In this case, the SDK will wait for the A/B test configuration for 10 seconds. If it won’t receive the config during the allocated time, it will notify the developer by using the onReceived(result: DTDRemoteConfigReceiveResult)
method with Failure value and disable the A/B testing until the next SDK initialization.
After the SDK finds a test, it will wait for a suitable group to include the user into and start the experiment.
By default, waiting time (groupDefinitionWaiting
) is 10 seconds.
You can change this value up or down.
Example: DTDRemoteConfig.groupDefinitionWaiting = 15
In this case, the SDK will wait for a group for no more than 15 seconds. If It can't find a suitable test for 15 seconds, it will be cancelled and its activation will be impossible. After the next SDK initialization (app restart), the user will have another chance to participate in the test.
The DTDRemoteConfig.remoteConfigWaiting
and DTDRemoteConfig.groupDefinitionWaiting
values can be set only prior to SDK initialization!
In the DTDRemoteConfig
class you need to set the default variables and their values using the DTDRemoteConfig.defaults
property.
The variable values in the defaults
property do not change on the SDK side.
After setting up DTDRemoteConfig.defaults
, you can receive the variable values by using the DTDRemoteConfig.config
property.
When working with A/B tests, always use the config
property to receive the actual variables and their values!
If for some reasons, the device can not be included in the test (no network or network problems, devtodev did not assign it to a group, incorrect SDK implementation, etc.) DTDRemoteConfig.config
will return default values. Using this approach, you can always shape the desirable UI and the business logic of the app.
To work with A/B testing, use the DTDAnalytics.initializeWithAbTest
initialization method.
If you used DTDAnalytics.initialize
previously, you need to replace it with DTDAnalytics.initializeWithAbTest
as the SDK initialization method.
The DTDRemoteConfigListener
interface is added to the initializeWithAbTest
method. It implements three methods:
onReceived(result: DTDRemoteConfigReceiveResult)
onPrepareToChange()
onChanged(result: DTDRemoteConfigChangeResult, error: Error?)
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the [DTDAnalytics applicationKey:* abConfigListener:*]
initialization method.
If you used [DTDAnalytics applicationKey:*]
previously, you need to replace it with [DTDAnalytics applicationKey:* abConfigListener:*] as the SDK initialization method.
The DTDRemoteConfigListener
interface is added to the [DTDAnalytics applicationKey:* abConfigListener:*]
method. It implements three methods:
-(void)onReceivedResult:(enum DTDRemoteConfigReceiveResult)result
-(void)onPrepareToChange
-(void)onChangedResult:(enum DTDRemoteConfigChangeResult)result error:(NSError *)error
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the DTDAnalytics.initializeWithAbTest
initialization method.
If you used DTDAnalytics.initialize
previously, you need to replace it with DTDAnalytics.initializeWithAbTest
as the SDK initialization method.
The IRemoteConfigListener
interface is added to the initializeWithAbTest
method. It implements three methods:
onReceived(result: DTDRemoteConfigReceiveResult)
onPrepareToChange()
onChanged(result: DTDRemoteConfigChangeResult, ex: Exception?)
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the DTDAnalytics.INSTANCE.initializeWithAbTest
initialization method.
If you used DTDAnalytics.INSTANCE.initialize
previously, you need to replace it with DTDAnalytics.INSTANCE.initializeWithAbTest
as the SDK initialization method.
The IRemoteConfigListener
interface is added to the initializeWithAbTest
method. It implements three methods:
void onReceived(@NonNull DTDRemoteConfigReceiveResult result)
void onPrepareToChange()
void onChanged(@NonNull DTDRemoteConfigChangeResult result, @Nullable Exception ex)
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the DTDAnalytics.InitializeWithAbTests
initialization method.
If you used DTDAnalytics.Initialize
previously, you need to replace it with DTDAnalytics.InitializeWithAbTests
as the SDK initialization method.
The DTDRemoteConfigListener
interface is added to the InitializeWithAbTests
method. It implements three methods:
OnReceived(DTDRemoteConfigReceiveResult result)
OnPrepareToChange()
OnChanged(DTDRemoteConfigChangeResult result, string exceptionMessage = null)
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the DTDAnalytics.InitializeWithAbTests
initialization method.
If you used DTDAnalytics.Initialize
previously, you need to replace it with DTDAnalytics.InitializeWithAbTests
as the SDK initialization method.
The IDTDRemoteConfigListener
interface is added to the InitializeWithAbTests
method. It implements three methods:
OnReceived(DTDRemoteConfigReceiveResult result)
OnPrepareToChange()
OnChanged(DTDRemoteConfigChangeResult result, string error)
The DTDRemoteConfigListener
methods are not called in the main thread - you need to keep this in mind when interacting with UI elements of the app. Also, do not execute operations that block the thread in the DTDRemoteConfigListener
methods, because this will disable the SDK operation (see examples).
To work with A/B testing, use the UDTDAnalyticsBPLibrary::InitializeWithAbTest
initialization method.
If you used UDTDAnalyticsBPLibrary::Initialize
previously, you need to replace it with UDTDAnalyticsBPLibrary::InitializeWithAbTest
as the SDK initialization method.
Implements three delegate methods:
onRemoteConfigReceive(EDTDRemoteConfigReceiveResult result)
onRemoteConfigPrepareToChange()
onRemoteConfigChange(EDTDRemoteConfigChangeResult result, FString error)
To work with A/B testing, use the DTDAnalytics.InitializeWithAbTest
initialization method.
If you used DTDAnalytics.initialize
previously, you need to replace it with DTDAnalytics.initializeWithAbTest
as the SDK initialization method.
The InitializeWithAbTest
method takes 3 Callable
as arguments, to work with A/B tests it is necessary to implement:
onRemoteConfigReceive(result: GDDTDRemoteConfigReceiveResult.ReceiveResult)
onRemoteConfigPrepareToChange()
onRemoteConfigChange(result: GDDTDRemoteConfigChangeResult.ChangeResult, error: String)
Methods implementation for working with A/B tests. When suitable conditions for the test occur, the following chain of events gets initiated:
Calling onReceived
method
Calling onPrepareToChange
method
Calling onChanged
method
The onReceived
method is triggered every time when the SDK loads A/B test configuration. The result
argument returns the following:
Success if the configuration was loaded in the time provided. Time is set by the user in DTDRemoteConfig.remoteConfigWaiting.
Failure if the config wasn’t received during the provided time defined by the user in DTDRemoteConfig.remoteConfigWaiting
.
Empty if the configuration was loaded in the time provided, but the list of experiments is empty. Time is set by the user in DTDRemoteConfig.remoteConfigWaiting
.
If the DTDRemoteConfig.remoteConfigWaiting
’s default value is equal to null, the OnReceived
method and DTDRemoteConfigReceiveResult.Success
are called when the config is received. The time of the OnReceived call depends on the network speed.
The onPrepareToChange()
method is designed to notify the developer that the configuration of the A/B tests will be changed (the test is found or canceled, switch to a user who is not participating in the experiment, etc. (see Some features in the behavior of interfaces)).
SDK asynchronous behavior causes a gap in time between the moment the suitable conditions for the test occur and its possible activation. You need to keep this in mind when changing the app’s UI and UX and pause the user’s interaction with the app until it comes into action:
onChanged
(see onChanged
description) and a decision on test participation with a new config is made (see applyConfig
description).
A timer on the developer’s side. The timer defines the time allocated for new config waiting. After the time has run out, waiting for the config should be canceled.
See the implementation example (Scenario 1)
After calling onPrepareToChange, the SDK executes an asynchronous request for entering the test. That will result in calling onChanged.
In case of disruption of the Internet connection or loss of focus, the test will be considered canceled until the next app launch.
The onChanged
method is triggered in one of the following cases:
The DevToDev server offers to enroll in a test.
onChanged()
with DTDRemoteConfigChangeResult.success
is called
The DevToDev server refuses to execute the test.
onChanged()
with DTDRemoteConfigChangeResult.failure
is called
The device has no internet connection.
onChanged()
with DTDRemoteConfigChangeResult.failure
is called
If the offer is received after the 30 second waiting time has expired
onChanged()
with DTDRemoteConfigChangeResult.failure
is called
The test was previously activated (during the initialization)
onChanged()
with DTDRemoteConfigChangeResult.success
is called
If the onChanged
method is triggered with status == DTDRemoteConfigChangeResult.success
value, the possible options are:
Accept the configuration by calling the DTDRemoteConfig.applyConfig()
method
If the configuration is accepted, the default parameters and group parameters (issued by the server) will overlap. After that, the parameters of the new configuration will be available in DTDRemoteConfig.config
(you can use them to change the behavior or the interface of the app).
Refuse enrollment in the test DTDRemoteConfig.resetConfig()
If the test enrollment is refused or the time for decision making is up, the SDK will temporarily flag the test and it will become unavailable until the next initialization. After the next initialization, the test will be available for participation when its requirements are fulfilled.
In the cases where status
== DTDRemoteConfigChangeResult.failure
, the DTDRemoteConfig.applyConfig()
method will be triggered and the default configuration will stay in place.
Set the default values DTDRemoteConfig.defaults
= ["button_color": "green", "button_size": "8"]
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig.config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values DTDRemoteConfig.defaults
= @{"button_color": @"green", @"button_size": @"8"}
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig.config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values DTDRemoteConfig.defaults
= mapOf("button_color" to "green", "button_size" to "8")
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig.config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values:
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig.config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values:
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.Defaults
Example of the DTDRemoteConfig.Config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values:
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.Defaults
Example of the DTDRemoteConfig.Config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values:
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig.config
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
Set the default values DTDRemoteConfig.SetDefaults()
Variable names have to be the same as in the ‘Group settings’ section of the web interface (see ‘web’ above). When the SDK gets included in the A/B test, the devtodev server automatically assigns it to a group.
SDK will not use new variable values that are not set in DTDRemoteConfig.defaults
Example of the DTDRemoteConfig
value variants:
button_color
green
green
blue
gray
button_size
8
8
12
14
Example of SDK initialization that includes A/B testing:
When the SDK finds a suitable test(s), it calls the onPrepareToChange
method and reports it. Then the SDK starts a timer for 30 seconds and sends a request to the devtodev server. The server returns an experiment number and information about a group. Or the server answers that the user can not participate in the test. This process takes some time. The request and answer can take as little as milliseconds, or much longer (30 seconds maximum) if, for example, the device’s internet connection is bad. Below, you can find several use cases that may help you to solve this problem if your app’s interface is sensitive to waiting for the config from devtodev.
When working with this class, the SDK provides synchronization of threads that aims at providing safe operation taking into account the asynchrony of the SDK.
remoteConfigWaiting: Double
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
groupDefinitionWaiting: Double
Wait time for test group.
Default value - 10.0 (measured in seconds)
defaults: [String, Any]
Variables and their default values
config: DTDRemoteConfigCollection
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
applyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
resetConfig()
It cancels a suitable or running test
cacheTestExperiment()
A debug method for saving a test experiment after restarting the application
remoteConfigWaiting: double
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
groupDefinitionWaiting: double
Wait time for test group.
Default value - 10.0 (measured in seconds)
defaults: NSDictionary<NSString *,id>
Variables and their default values
config: DTDRemoteConfigCollection
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
(void) applyConfig
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
(void) resetConfig
It cancels a suitable or running test
(void) cacheTestExperiment
A debug method for saving a test experiment after restarting the application
remoteConfigWaiting: Double
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
groupDefinitionWaiting: Double
Wait time for test group.
Default value - 10.0 (measured in seconds)
defaults: Map<String, Any>
Variables and their default values
config: DTDRemoteConfigCollection
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
applyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
resetConfig()
It cancels a suitable or running test
cacheTestExperiment()
A debug method for saving a test experiment after restarting the application
setRemoteConfigWaiting
()
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
getRemoteConfigWaiting
()
Wait time for test group.
setGroupDefinitionWaiting
()
Wait time for test group.
Default value - 10.0 (measured in seconds)
getGroupDefinitionWaiting
()
Get time for test group.
setDefaults(Map<String, ? extends Object>
)
Set map of variables and their default values
Map<String,Object> getDefaults()
Get map of variables and their default values
DTDRemoteConfigCollection getConfig()
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
applyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
resetConfig()
It cancels a suitable or running test
cacheTestExperiment()
A debug method for saving a test experiment after restarting the application
double RemoteConfigWaiting {get;set;}
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
double GroupDefinitionWaiting {get;set}
Wait time for test group.
Default value - 10.0 (measured in seconds)
Dictionary<string, object> DTDRemoteConfig.Defaults {get;set}
Variables and their default values
DTDRemoteConfigCollection DTDRemoteConfig.Config
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
void ApplyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
void ResetConfig()
It cancels a suitable or running test
void CacheTestExperiment()
A debug method for saving a test experiment after restarting the application
RemoteConfigWaiting: double
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
GroupDefinitionWaiting: double
Wait time for test group.
Default value - 10.0 (measured in seconds)
Defaults: IDictionary<String, object>
Variables and their default values
Config: DTDRemoteConfigCollection
Wrapper for remote parameters in the form of a collection. It allows access to the configuration values by using the subscripting syntaxis.
Actual variables and their values for working with A/B tests
ApplyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
ResetConfig()
It cancels a suitable or running test
CacheTestExperiment()
A debug method for saving a test experiment after restarting the application
SetRemoteConfigWaiting(float value)
Wait time for A/B test configuration.
Default value - 0.0 (measured in seconds)
float GetRemoteConfigWaiting()
Wait time for test group.
SetGroupDefinitionWaiting(float value)
Wait time for test group.
Default value - 10.0 (measured in seconds)
GetGroupDefinitionWaiting()
Get time for test group.
SetDefaults(const FDTDRemoteConfigDefaults& defaults)
Set USTRUCT with variables and their default values
TMap<FString, FDTDRemoteConfigValue> GetConfig()
Actual variables and their values for working with A/B tests
FDTDRemoteConfigValue GetRemoteConfigValue(const FString& key)
Return actual value for variable key
bool HasKey(const FString& key)
Verify if there are any values associated with the variable key in the remote configuration.
ApplyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
ResetConfig()
It cancels a suitable or running test
CacheTestExperiment()
A debug method for saving a test experiment after restarting the application
void SetRemoteConfigWaiting(int value)
Wait time for A/B test configuration.
Default value - 0 (measured in seconds)
int GetRemoteConfigWaiting()
Wait time for test group.
void SetGroupDefinitionWaiting(int value)
Wait time for test group.
Default value - 10 (measured in seconds)
int GetGroupDefinitionWaiting()
Get time for test group.
void SetDefaults(defaults: GDDTDRemoteConfigDefaults)
Set GDDTDRemoteConfigDefaults
with variables and their default values
GDDTDRemoteConfigValue GetRemoteConfigValue(key: String)
Return actual value for variable key
bool HasKey(key: String)
Verify if there are any values associated with the variable key in the remote configuration.
void ApplyConfig()
It applies the A/B testing configuration. After the call, the default parameters get matched with the group parameters.
void ResetConfig()
It cancels a suitable or running test
void CacheTestExperiment()
A debug method for saving a test experiment after restarting the application
Wrapper for remote parameters collection. Enables access to configuration values by using subscripting syntax.
hasKey(key: String)
Return true if current configuration has value for a key.
Wrapper for working with remote configuration variables. It represents a method for data source identification, as well as methods for presenting values in the form of various data types.
DTDRemoteConfigSource.Default
The variable is set by default.
DTDRemoteConfigSource.Remote
The variable is set by the test group.
DTDRemoteConfigSource.Empty
The variable is not found in the remote configuration.
stringValue
String?
Gets the value as an optional string.
floatValue
Float
Gets the value as a Float.
doubleValue
Double
Gets the value as a Double.
Int32Value
Int32
Gets the value as an Int32.
Int64Value
Int64
Gets the value as an Int64.
integerValue
Int
Gets the value as an Int.
boolValue
Bool
Gets the value as a Bool.
stringValue
NSString
Gets the value as an optional string.
floatValue
float
Gets the value as a Float.
doubleValue
double
Gets the value as a Double.
Int32Value
long
Gets the value as an long.
Int64Value
long long
Gets the value as an long long.
integerValue
NSInteger
Gets the value as an NSInteger.
boolValue
BOOL
Gets the value as a Bool.
stringValue
String?
Gets the value as an optional string.
floatValue
Float
Gets the value as a Float.
doubleValue
Double
Gets the value as a Double.
intValue
Int
Gets the value as an int.
longValue
Long
Gets the value as an long.
booleanValue
Boolean
Gets the value as a Bool.
getStringValue
String
Gets the value as an optional string.
getFloatValue
float
Gets the value as a Float.
getDoubleValue
double
Gets the value as a Double.
getIntValue
int
Gets the value as an Int.
getLongValue
long
Gets the value as an Long.
getBooleanValue
Boolean
Gets the value as a Boolean.
StringValue
string
Gets the value as an optional string.
FloatValue
float
Gets the value as a float.
DoubleValue
double
Gets the value as a double.
LongValue
long
Gets the value as an long.
IntValue
int
Gets the value as an int.
BoolValue
bool
Gets the value as a bool.
StringValue
String
Gets the value as an optional string.
FloatValue
float
Gets the value as a float.
DoubleValue
double
Gets the value as a double.
Int16Value
Int16
Gets the value as an Int16
Int32Value
Int32
Gets the value as an Int32
Int64Value
Int64
Gets the value as an Int64
BoolValue
bool
Gets the value as a bool.
StringValue
FString
Gets the value as an string.
FloatValue
float
Gets the value as a float.
LongValue
int64
Gets the value as an long.
IntValue
int32
Gets the value as an int.
BoolValue
bool
Gets the value as a bool.
Source
EDTDRemoteConfigSource
Gets source of the value.
GetStringValue
String
Gets the value as an string.
GetFloatValue
float
Gets the value as a float.
GetIntValue
int
Gets the value as an int.
GetBoolValue
bool
Gets the value as a bool.
GetSource
GDDTDRemoteConfigSource.Source
Gets source of the value.
It implements methods that report the status of A/B tests.
onReceived(result: DTDRemoteConfigReceiveResult)
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), onReceived
does not get called
onPrepareToChange()
It notifies the developer about coming changes in the A/B test configuration.
onChanged(result: DTDRemoteConfigChangeResult,
error: Error?)
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
-(void)onReceivedResult:
(enum DTDRemoteConfigReceiveResult)result
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), onReceived
does not get called
-(void)onPrepareToChange
It notifies the developer about coming changes in the A/B test configuration.
- (void)onChangedResult:
(enum DTDRemoteConfigChangeResult)result
error:(NSError *)error
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
onReceived(result: DTDRemoteConfigReceiveResult)
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), onReceived
does not get called
onPrepareToChange()
It notifies the developer about coming changes in the A/B test configuration.
onChanged(result: DTDRemoteConfigChangeResult, ex: Exception?)
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
onReceived(DTDRemoteConfigReceiveResult result)
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), onReceived
does not get called
onPrepareToChange()
It notifies the developer about coming changes in the A/B test configuration.
onChanged( DTDRemoteConfigChangeResult result, Exception ex)
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
IDTDRemoteConfigListener
void OnReceived(DTDRemoteConfigReceiveResult result)
;
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), OnReceived
does not get called
void OnPrepareToChange();
It notifies the developer about coming changes in the A/B test configuration.
void OnChanged(DTDRemoteConfigChangeResult result, string exceptionText = null)
;
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
IDTDRemoteConfigListener
OnReceived(DTDRemoteConfigReceiveResult result)
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), OnReceived
does not get called
OnPrepareToChange()
It notifies the developer about coming changes in the A/B test configuration.
OnChanged(DTDRemoteConfigChangeResult result, string error)
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
FDTDRemoteConfigReceiveResultDelegate
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), OnReceived
does not get called
FDTDRemoteConfigPrepareToChangeDelegate
It notifies the developer about coming changes in the A/B test configuration.
FDTDRemoteConfigChangeResultDelegate
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
onRemoteConfigReceive(result: GDDTDRemoteConfigReceiveResult.ReceiveResult):
It is triggered every time the SDK loads an A/B test configuration. If the remoteConfigWaiting has a default value (null), onReceived
does not get called
onRemoteConfigPrepareToChange()
It notifies the developer about coming changes in the A/B test configuration.
onRemoteConfigChange(result: GDDTDRemoteConfigChangeResult.ChangeResult, error: String)
It notifies the developer that the configuration has changed. Or about the reason why the configuration could not change.
It is triggered every time the SDK loads the configuration of A/B tests.
DTDRemoteConfigReceiveResult.Success
It is triggered when the configuration of the A/B test is received.
DTDRemoteConfigReceiveResult.Failure
It is triggered if the SDK did not manage to get the A/B test configurations for the time period set in remoteConfigWaiting.
DTDRemoteConfigReceiveResult.Empty
It is triggered when the configuration of the A/B test is received, but the list of experiments is empty.
Notifies whether the configuration of the A/B test has been changed.
DTDRemoteConfigReceiveResult.Success
Configuration is changed.
DTDRemoteConfigReceiveResult.Failure
Configuration change attempt failed.
Data options returned by the configChanged
method signature
DTDRemoteConfigChangeResult.Success
null
When receiving an offer from the backend.
DTDRemoteConfigChangeResult.Success
null
When launching the SDK with a previously started test.
DTDRemoteConfigChangeResult.Success
null
When replacing the user with another user who previously started the test.
DTDRemoteConfigChangeResult.Failure
[A/B-Test Module] The Server refused to conduct the test.
If the server refused to provide a test available for participation.
DTDRemoteConfigChangeResult.Failure
[A/B-Test Module] Offer from devtodev not received within the allotted N seconds.
The backend offer is returned after a deadline e.g. due to a bad internet connection.
DTDRemoteConfigChangeResult.Failure
[A/B-Test Module] Offer from devtodev not received within the allotted N seconds.
The SDK was unable to receive an offer from the backend within N seconds e.g, duea bad internet connection or network problems.
DTDRemoteConfigChangeResult.Failure
[A/B-Test Module] In the process of receiving an offer from the server, the user was changed. Offer has been canceled.
When replacing the user with another user at the time of receiving an offer.
DTDRemoteConfigChangeResult.Failure
[A/B-Test Module] Offer refused, because application went into the background.
If a suitable test is found but the user made the app go into the background before the offer was received.
fromUserId
FString
From user ID
toUserId
FString
To user ID
Our analytics data show that most of the people make a purchase during their first session. However, only 70% of users open our in-app store during the first session. We hypothesize that if we add a purchase screen to the tutorial then 100% of users will face it and the number of purchases during the first session will increase.
The criteria for test inclusion is starting the tutorial. The DTDAnalytics.tutorial(step: Int)
event with step = -1 is the trigger.
Control group: a 10 step tutorial, no purchase screens
Group А: an 11 step tutorial. At step number 5, we will offer a special offer.
Our analytics data show that N users installed the app more than half a year ago but still did not make a purchase. We hypothesize that if we offer a huge discount then we can get additional income.
The criteria for test inclusion is the app install date and the “payer” status.
Control group: current version with usual prices
Group А: it has a discount badge on the main page. After clicking on the badge, a purchase window pops up
Note
When receiving the configuration, the SDK always calls the onReceived(result: DTDRemoteConfigReceiveResult)
method, and when enrolling in a test - the onPrepareToChange()
and onChanged(result: DTDRemoteConfigChangeResult, error: Error?)
method. However, you can take some additional precocious measures. You can add a timer as in the following example:
Note
When receiving the configuration, the SDK always calls the onReceivedResult
method, and when enrolling in a test - the onPrepareToChange
and onChangedResult
method. However, you can take some additional precocious measures. You can add a timer as in the following example:
Note
When receiving the configuration, the SDK always calls the onReceivedResult
method, and when enrolling in a test - the onPrepareToChange
and onChangedResult
method. However, you can take some additional precocious measures. You can add a timer as in the following example:
Note
When receiving the configuration, the SDK always calls the onReceivedResult
method, and when enrolling in a test - the onPrepareToChange
and onChangedResult
method. However, you can take some additional precocious measures. You can add a timer as in the following example:
Note
When receiving the configuration, the SDK always calls the OnReceived(DTDRemoteConfigReceiveResult result)
method, and when enrolling in a test - the OnPrepareToChange()
and OnChanged(DTDRemoteConfigChangeResult result, string exceptionText = null)
method. However, you can take some additional precocious measures. You can add a timer as in the following example:
Note
When receiving the configuration, the SDK always calls the OnReceived(DTDRemoteConfigReceiveResult result)
method, and when enrolling in a test - the OnPrepareToChange()
and OnChanged(DTDRemoteConfigChangeResult result, string error)
. However, you can take some additional precocious measures. You can add a timer as in the following example:
Our analytics data show that only 60% of our users complete the tutorial. We hypothesize that if we make it easier (group A) or reduce the number of seps (group B), we will increase the percentage of tutorial completion.
New users who have not started the tutorial yet.
Control group: current version with usual difficulty and usual number of steps
Group А: low difficulty, usual number of steps
Group B: usual difficulty, few steps
Blueprint