This document will guide you through the process of Countly SDK installation and it applies to version 21.11.0
Countly is an open source SDK, you can take a look at our SDK code in the Github repo
Click here, to access the documentation for older SDK versions.
Supported Platforms: Countly SDK supports iOS and Android.
You can take a look at our sample application in the Github repo. It should show how most of the functionalities can be used.
Adding the SDK to the project
The core of this SDK is developed around Cordova. We have a minimum version requirement for it's core and android, ios modules that have to be satisfied:
- cordova >= 9.0.0
- cordova-android >= 8.0.0
- cordova-ios >= 5.0.0
If you would integrate this SDK in any other project similar to cordova (like ionic, phonegap, meteor), you would have to make sure that you are setting the platform requirements for those projects similar to these.
Note : Development on PhoneGap stopped in 14 Aug 2020. To the best of our knowledge, this SDK should still be compatible with the final release.
For more information about PhoneGap shut down, click here
Setting up Countly SDK inside your Cordova, Ionics application is straightforward. Just follow the laid out steps for the specific projects:
Cordova
Add Countly SDK in your Cordova project using following commands:
Note: use the latest SDK version currently available, not specifically the one shown in the sample below.
cd PATH_TO_YOUR_PROJECT
cordova plugin add https://github.com/Countly/countly-sdk-cordova.git
# OR
cordova plugin add countly-sdk-js@20.11.0
If iOS/Android Platform are already added in your project, first remove them
cordova platform remove android
cordova platform remove ios
Now add platform of your choice
cordova platform add android
cordova platform add ios
It's important that you make sure you build it with Cordova, as Cordova links folders very well.
cordova build android
ordova build ios
Now run the application directly for Android,
cordova run android
Or iOS:
cordova run ios
Alternatively, you can open the source in Xcode, or Android Studio and move on with further development.
Ionic
Add Countly SDK in your Ionic project using following commands:
Note: use the latest SDK version currently available, not specifically the one shown in the sample below.
cd PATH_TO_YOUR_PROJECT
ionic cordova plugin add https://github.com/Countly/countly-sdk-cordova.git
# OR
ionic cordova plugin add countly-sdk-js@20.11.0
If iOS/Android Platform are already added in your project, first remove them
ionic cordova platform remove android
ionic cordova platform remove ios
Now add platform of your choice
ionic cordova platform add android
ionic cordova platform add ios
Now prepare the platforms you have added
ionic cordova prepare android
ionic cordova prepare ios
It's important that you make sure you build it with Cordova, as Cordova links folders very well.
ionic cordova build android
ionic cordova build ios
Now run the application directly for Android,
ionic cordova run android
Or iOS:
ionic cordova run ios
Alternatively, you can open the source in Xcode, or Android Studio and move on with further development.
In your index.html, use the following lines:
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="Countly.js"></script>
SDK Integration
Minimal setup
Below you can find necessary code snippets to initialize the SDK for sending data to Countly servers. Where possible, use your server URL instead of try.count.ly
in case you have your own server.
// initialize
Countly.isInitialized().then((result) => {
if(result != "true") {
Countly.init("https://try.count.ly", "YOUR_APP_KEY").then((result) => {
Countly.start();
},(err) => {
console.error(err);
});
}
},(err) => {
console.error(err);
});
Please check here for more information on how to acquire your application key (APP_KEY) and server URL.
If you are in doubt about the correctness of your Countly SDK integration you can learn about methods to verify it from here.
Enable logging
If logging is enabled then our sdk will print out debug messages about it's internal state and encountered problems.
When advise doing this while implementing countly features in your application.
// example for setLoggingEnabled
Countly.setLoggingEnabled();
Device ID
When the SDK is initialized for the first time and no device ID is provided, a device ID will be generated by SDK.
For iOS: the device ID generated by SDK is the Identifier For Vendor (IDFV) For Android: the device ID generated by SDK is the OpenUDID.
You may provide your own custom device ID when initializing the SDK
Countly.init(SERVER_URL, APP_KEY, DEVICE_ID)
SDK data storage
For iOS: SDK data is stored in Application Support Directory in file named "Countly.dat" For Android: SDK data is stored in SharedPreferences. A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them.
Crash reporting
The Countly SDK has the ability to collect crash reports, which you may examine and resolve later on the server.
Automatic crash handling
With this feature, the Countly SDK will generate a crash report if your application crashes due to an exception and send it to the Countly server for further inspection.
If a crash report cannot be delivered to the server (e.g. no internet connection, unavailable server, etc.), then the SDK stores the crash report locally in order to try again at a later time.
You will need to call the following method before calling init
in order to activate automatic crash reporting.
// Using countly crash reports
Countly.enableCrashReporting();
Handled exceptions
You might catch an exception or similar error during your app’s runtime.
You may also log these handled exceptions to monitor how and when they are happening with the following command:
You can also send a custom crash log to Countly using code below.
// Send Exception to the server
Countly.logException(["My Customized error message"], true, {"_facebook_version": "0.0.1"});
Countly.logException(stackFramesFromStackTraceJS, booleanNonFatal, segments);
The method logException
takes a string, array of strings or strackframes for the stack trace, a boolean flag indicating if the crash is considered fatal or not, and a segments dictionary to add additional data to your crash report.
Below are some examples that how to log handled/nonfatal and unhandled/fatal exceptions manually.
1. Manually report handled exception
// With stackframes
try {
// your code here...
} catch (err) {
StackTrace.fromError(err).then(function(stackframes) {
Countly.logException(stackframes, true);
});
}
// With error string
Countly.logException("ERROR_STRING", true);
// With array of strings
Countly.logException(["ERROR_STRING", "ERROR_STRING_2"], true);
2. Manually report handled exception with segmentation
// With stackframes
try {
// your code here...
} catch (err) {
StackTrace.fromError(err).then(function(stackframes) {
Countly.logException(stackframes, true, {"_facebook_version": "0.0.1"});
});
}
// With error string
Countly.logException("ERROR_STRING", true, {"\_facebook_version": "0.0.1"});
// With array of strings
Countly.logException(["ERROR_STRING", "ERROR_STRING_2"], true, {"\_facebook_version": "0.0.1"});
3. Manually report fatal exception
// With stackframes
try {
// your code here...
} catch (err) {
StackTrace.fromError(err).then(function(stackframes) {
Countly.logException(stackframes, false);
});
}
// With error string
Countly.logException("ERROR_STRING", false);
// With array of strings
Countly.logException(["ERROR_STRING", "ERROR_STRING_2"], false);
4. Manually report fatal exception with segmentation
// With stackframes
try {
// your code here...
} catch (err) {
StackTrace.fromError(err).then(function(stackframes) {
Countly.logException(stackframes, false, {"_facebook_version": "0.0.1"});
});
}
// With error string
Countly.logException("ERROR_STRING", false, {"\_facebook_version": "0.0.1"});
// With array of strings
Countly.logException(["ERROR_STRING", "ERROR_STRING_2"], false, {"\_facebook_version": "0.0.1"});
Crash breadcrumbs
Throughout your app you can leave crash breadcrumbs which would describe previous steps that were taken in your app before the crash. After a crash happens, they will be sent together with the crash report.
Following the command adds crash breadcrumb:
// Add crash breadcrumb
Countly.addCrashLog("My crash log from JavaScript");
Events
An Event is any type of action that you can send to a Countly instance, e.g purchase, settings changed, view enabled and so. This way it's possible to get much more information from your application compared to what is sent from SDK to Countly instance by default.
Here are the detail about properties which we can use with event:
key
identifies the eventcount
is the number of times this event occurredsum
is an overall numerical data set tied to an event. For example, total amount of in-app purchase event.duration
is used to record and track the duration of events.segmentation
is a key-value pairs, we can usesegmentation
to track additional information. The only valid data types are: "String", "Integer", "Double" and "Boolean". All other types will be ignored.
All data passed to Countly server via SDK or API should be in UTF-8.
Recording events
We will be recording a purchase event. Here is a quick summary of what information each usage will provide us:
- Usage 1: how many times purchase event occurred.
- Usage 2: how many times purchase event occurred + the total amount of those purchases.
- Usage 3: how many times purchase event occurred + which countries and application versions those purchases were made from.
- Usage 4: how many times purchase event occurred + the total amount both of which are also available segmented into countries and application versions.
- Usage 5: how many times purchase event occurred + the total amount both of which are also available segmented into countries and application versions + the total duration of those events.
1. Event key and count
// example for sending basic event
var events = {"key":"Basic Event","count":1};
Countly.recordEvent(events);
2. Event key, count and sum
// example for event with sum
var events = {"key":"Event With Sum","count":1,"sum":"0.99"};
Countly.recordEvent(events);
3. Event key and count with segmentation(s)
// example for event with segment
var events = {"key":"Event With Segment","count":1};
events.segments = {"Country" : "Turkey", "Age" : "28"};
Countly.recordEvent(events);
4. Event key, count and sum with segmentation(s)
// example for event with segment and sum
var events = {"key":"Event With Segment And Sum","count":1,"sum":"0.99"};
events.segments = {"Country" : "Turkey", "Age" : "28"};
Countly.recordEvent(events);
5. Event key, count, sum and duration with segmentation(s)
var events = {
"key": "Event With Sum And Segment duration",
"count": 1,
"Sum": "0.99",
"duration": "0"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.recordEvent(events);
Those are only a few examples of what you can do with events. You can extend those examples and use country, app_version, game_level, time_of_day and any other segmentation that will provide you valuable insights.
Timed events
It's possible to create timed events by defining a start and stop moment.
// Time Event
Countly.startEvent("Timed Event");
setTimeout(function() {
Countly.endEvent({ "key": "Timed Event");
}, 1000);
// Time Event With Sum
Countly.startEvent("Timed Event With Sum");
setTimeout(function() {
countly.endEvent({"key": "Timed Event With Sum", "sum": "0.99"});
}, 1000);
When ending an event you can also provide additional information. But in that case, you have to provide segmentation, count and sum. The default values for those are "null", 1 and 0.
// Time Event with segment
Countly.startEvent("Timed Event With Segment");
setTimeout(function() {
var events = {
"key": "Timed Event With Segment"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.endEvent(events);
}, 1000)
// Time Event with Segment, sum and count
Countly.startEvent("Timed Event With Segment, Sum And Count");
setTimeout(function() {
var events = {
"key": "timedEvent",
"count": 1,
"sum": "0.99"
};
events.segments = {
"Country": "Turkey",
"Age": "28"
};
Countly.endEvent(events);
}, 1000);
Sessions
Automatic session tracking
To start recording an automatic session tracking you would call:
Countly.start();
Countly.start();
will handle the start session, update session and end session automatically.
This is how it works:
- Start/Begin session Request: It is sent on
Countly.start();
call and when the app comes back to the foreground from the background, and it includes basic metrics. - Update Session Request: It automatically sends a periodical (60 sec by default) update session request while the app is in the foreground.
- End Session Request: It is sent at the end of a session when the app goes to the background or terminates.
If you want to end automatic session tracking you would call:
Countly.stop();
View tracking
You may track custom views with the following code snippet:
Countly.recordView("View Name")
While manually tracking views, you may add your custom segmentation to them like this:
var viewSegmentation = { "Country": "Germany", "Age": "28" };
Countly.recordView("View Name", viewSegmentation);
To review the resulting data, open the dashboard and go to Analytics > Views
. For more information on how to use view tracking data to its fullest potential, click here.
Device ID management
A device ID is a unique identifier for your users. You may specify the device ID yourself or allow the SDK to generate it. When providing one yourself, keep in mind that it has to be unique for all users. Some potential sources for such an id could be the username, email or some other internal ID used by your other systems.
Device ID generation
When the SDK is initialized for the first time with no device ID, then SDK will generate a device ID.
Here are the underlying mechanisms used to generate that value for some platforms:
For iOS: the device ID generated by SDK is the Identifier For Vendor (IDFV)
For Android: the device ID generated by SDK is the OpenUDID
Changing the Device ID
You may configure/change the device ID anytime using:
Countly.changeDeviceId(DEVICE_ID, ON_SERVER);
You may either allow the device to be counted as a new device or merge existing data on the server. If theonServer
bool is set to true
, the old device ID on the server will be replaced with the new one, and data associated with the old device ID will be merged automatically.
Otherwise, if onServer
bool is set to false
, the device will be counted as a new device on the server.
Temporary Device ID
You may use a temporary device ID mode for keeping all requests on hold until the real device ID is set later.
You can enable temporary device ID when initializing the SDK:
Countly.init(SERVER_URL, APP_KEY, "TemporaryDeviceID")
To enable a temporary device ID after init, you would call:
Countly.changeDeviceId("TemporaryDeviceID", ON_SERVER);
Note: When passing TemporaryDeviceID
for deviceID
parameter, argument for onServer
parameter does not matter.
As long as the device ID value is TemporaryDeviceID
, the SDK will be in temporary device ID mode and all requests will be on hold, but they will be persistently stored.
When in temporary device ID mode, method calls for presenting feedback widgets and updating remote config will be ignored.
Later, when the real device ID is set using Countly.changeDeviceId(DEVICE_ID, ON_SERVER);
method, all requests which have been kept on hold until that point will start with the real device ID
Retrieving current device ID
You may want to see what device id Countly is assigning for the specific device. For that you may use the following call:
// get device id
Countly.getCurrentDeviceId(function(deviceId){
console.log(deviceId);
}, function(getDeviceIDError){
console.log(getDeviceIDError);
});
Push notifications
Integration
Android setup
Here are the steps to make push notifications work on Android:
- For FCM credentials setup please follow the instruction from this URL https://support.count.ly/hc/en-us/articles/360037754031-Android#getting-fcm-credentials.
- Make sure you have
google-services.json
from https://firebase.google.com/ - Make sure the app package name and the
google-services.json
package_name
matches. - Place this
google-services.json
file under your root project folder. i.e. above www folder. - Put these tags in config.xml file for Android:
<platform name="android"> <resource-file src="google-services.json" target="app/google-services.json" /> </platform>
- Put these tags in config.xml file if you are using cordova-android 9.x or greater:
<preference name="GradlePluginGoogleServicesEnabled" value="true" /> <preference name="GradlePluginGoogleServicesVersion" value="4.2.0" />
- Install the google services plugin if you use cordova-android below version 9
cordova plugin add cordova-support-google-services --save
- Build your app, and test push notifications.
iOS setup
By default push notification is enabled for iOS, to disable you need to add the COUNTLY_EXCLUDE_PUSHNOTIFICATIONS=1
flag to the Build Settings
> Preprocessor Macros
section in Xcode.
This COUNTLY_EXCLUDE_PUSHNOTIFICATIONS is only supported by the minimum SDK version 20.11.3.
There are no additional steps required for iOS,everything is set up for you by the Countly Cordova SDK.
Enabling push
First, when setting up push for the Cordova SDK, you would first select the push token mode. This would allow you to choose either test or production modes, push token mode should be set before init.
// Set messaging mode for push notifications
Countly.pushTokenType(Countly.messagingMode.DEVELOPMENT, "Channel Name", "Channel Description");
When you are finally ready to initialise Countly push, you would call this:
// This method will ask for permission, enables push notification and send push token to countly server.
Countly.askForNotificationPermission();
Handling push callbacks
To register a Push Notification callback after initializing the SDK, use the method below.
Countly.registerForNotification(function(theNotification){
console.log(JSON.stringify(theNotification));
});
In order to listen to notification receive and click events, Place the below code in AppDelegate.m
Add header files
#import "CountlyNative.h"
#import <UserNotifications/UserNotifications.h>
Before @end
add these methods
// Required for the notification event. You must call the completion handler after handling the remote notification.
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
[CountlyNative onNotification: userInfo];
completionHandler(0);
}
// When app is killed.
- (void)userNotificationCenter:(UNUserNotificationCenter _)center didReceiveNotificationResponse:(UNNotificationResponse _)response withCompletionHandler:(void (^)(void))completionHandler{
NSDictionary \*notification = response.notification.request.content.userInfo;
[CountlyNative onNotification: notification];
completionHandler();
}
// When app is running.
- (void)userNotificationCenter:(UNUserNotificationCenter _)center willPresentNotification:(UNNotification _)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
[CountlyNative onNotification: notification.request.content.userInfo];
completionHandler(0);
}
Data Structure Received in Push Callbacks
Here is the example of how data will receive in push callbacks:
Data Received for Android platform:
{
"c.e.cc": "TR",
"c.e.dt": "mobile",
"Key": "value",
"c.i": "62b59b979f05a1f5e5592036",
"c.l": "https:\/\/www.google.com\/",
"c.m": "https:\/\/count.ly\/images\/logos\/countly-logo-mark.png?v2",
"c.li": "notify_icon",
"badge": "1",
"sound": "custom",
"title": "title",
"message": "Message"
}
Data Received for iOS platform:
{
Key = value;
aps = {
alert = {
body = Message;
subtitle = subtitle;
title = title;
};
badge = 1;
"mutable-content" = 1;
sound = custom;
};
c = {
a = "https://count.ly/images/logos/countly-logo-mark.png";
e = {
cc = TR;
dt = mobile;
};
i = 62b5b945cabedb0870e9f217;
l = "https://www.google.com/";
};
}
User location
While integrating this SDK into your application, you might want to track your user location. You could use this information to better know your apps user base or to send them tailored push notifications based on their coordinates. There are 4 fields that can be provided:
- country code in the 2 letter iso standard
- city name (has to be set together with country code)
- Comma separate latitude and longitude values, for example "56.42345,123.45325"
- ip address of your user
// send user location
Countly.setLocation("28.006324", "-82.7166183");
When those values are set, they will be sent every time when initiating a session. If they are set after a session was initiated, a separate request will also be sent. Except for ip address, because Countly Server processes ip address only when starting a session.
If you don't want to set specific fields, set them to null.
Users might want to opt out of location tracking. To do that, call:
It will erase cached location data from the device and the server.
Remote Config
Remote config allows you to modiffy how your app functions or looks by requesting key-value pairs from your Countly server. The returned values can be modiffied based on the user profile. For more details please see Remote Config documentation.
Automatic remote config
There are two ways of acquiring remote config data, by automatic download or manual request. By default, automatic remote config is disabled and therefore without developer intervention no remote config values will be requested.
Automatic value download happens when the SDK is initiated or when the device ID is changed. To enable it, you have to call setRemoteConfigAutomaticDownload before init. As a optional value you can provide a callback to be informed when the request is finished.
Note: call setRemoteConfigAutomaticDownload
method before init
// Call this method before init
Countly.setRemoteConfigAutomaticDownload(function(r){
alert(r)
}, function(r){
alert(r);
});
If the callback returns a non null value, then you can expect that the request failed and no values where updated.
When doing an automatic update, all locally stored values are replaced with the ones received (all locally stored ones are deleted and new ones are associated instead). It is possible that a previously valid key returns no value after an update.
Manual remote config
There are three ways for manually requesting a Remote Config update:
- Manually updating everything
- Manually updating specific keys
- Manually updating everything except specific keys
Each of these requests also has a callback. If that returns a non-null value, that means the request encountered an error and failed.
Functionally, the manual update for everything remoteConfigUpdate is the same as the automatic update - it replaces all stored values with the ones from the server (all locally stored ones are deleted and replaced with new ones instead). The advantage is that you can make the request whenever it is desirable for you. It has a callback to let you know when it has finished.
Countly.remoteConfigUpdate(function(r){
alert(r)
}, function(r){
alert(r);
});
You might want to update only specific key values. For that you need to call updateRemoteConfigForKeysOnly
with a list of keys you want to be updated. That list is an array with string values of those keys. It has a callback to let you know when the request has finished.
Countly.updateRemoteConfigForKeysOnly(["name"], function(r){
alert(r)
}, function(r){
alert(r);
});
You might want to update all values except a few defined keys, for that call updateRemoteConfigExceptKeys. The key list is a array with string values of the keys. It has a callback to let you know when the request has finished.
Countly.updateRemoteConfigExceptKeys(["url"], function(r){
alert(r)
}, function(r){
alert(r);
});
When making requests with a "inclusion" or "exclusion" array, if those arrays ar empty or null, they will function the same as a simple manual request and will update all values. This means that it will also erase all keys not returned by the server.
Getting Remote Config values
To request a stored value, call getRemoteConfigValueForKey
with the specified key. If it returns null then no value was found. The SDK has no knowledge of the returned value type and therefore returns an object. The developer needs to cast it to the appropriate type. The returned values can also be a JSONArray, JSONObject or just a simple value like int.
Countly.getRemoteConfigValueForKey("name", function(r){
alert(r)
}, function(r){
alert(r);
});
Clearing stored values
At some point you might want to erase all values downloaded from the server. To achieve that you need to call one function, depicted below:
Countly.remoteConfigClearValues(function(r){
alert(r)
}, function(r){
alert(r);
});
User Feedback
There are two ways of getting feedback from your users: Star rating dialog, feedback widget.
Star rating dialog allows users to give feedback as a rating from 1 to 5. The feedback widget allows to get the same 1 to 5 rating and also a text comment.
Ratings
Star Rating Dialog
Star rating integration provides a dialog for getting user's feedback about the application. It contains a title, simple message explaining what it is for, a 1-to-5 star meter for getting users rating and a dismiss button in case the user does not want to give a rating.
This star-rating has nothing to do with Google Play Store ratings and reviews. It is just for getting a brief feedback from users, to be displayed on the Countly dashboard. If the user dismisses star rating dialog without giving a rating, the event will not be recorded.
Star-rating dialog's title, message and dismiss button text can be customized either through the init function or the SetStarRatingDialogTexts
function. If you don't want to override one of those values, set it to "null".
// Star Rating
countly.askForStarRating(Function(ratingResult){
console.log(ratingResult);
});
Rating Widget
Feedback widget shows a server configured widget to your user devices.
It's possible to configure any of the shown text fields and replace with a custom string of your choice.
In addition to a 1 to 5 rating, it is possible for users to leave a text comment and also leave a email in case the user would want some contact from the app developer.
Trying to show the rating widget is a single call, but underneath is a two step process. Before it is shown, the SDK tries to contact the server to get more information about the dialog. Therefore a network connection to it is needed.
You can try to show the widget after you have initialized the SDK. To do that, you first have to get the widget ID from your server:
Using that you can call the function to show the widget popup:
// Feedback Modal
countly.askForFeedback("5e425407975d006a22535fc", "close");
User Profiles
Available with Enterprise Edition, User Profiles is a tool which helps you identify users, their devices, event timeline and application crash information. User Profiles can contain any information that either you collect, or is collected automatically by Countly SDK.
You can send user related information to Countly and let Countly dashboard show and segment this data. You may also send a notification to a group of users. For more information about User Profiles, see this documentation.
To provide information about the current user, you must call the Countly.userData.setUserData function. You can call it by providing a bundle of only the predefined fields or call it while also providing a second bundle of fields with your custom keys. After you have provided user profile information, you must save it by calling Countly.userData.save().
/ example for setting user data
var options = {};
options.name = "Nicola Tesla";
options.username = "nicola";
options.email = "info@nicola.tesla";
options.organization = "Trust Electric Ltd";
options.phone = "+90 822 140 2546";
options.picture = "http://www.trust.electric/images/people/nicola.png";
options.picturePath = "";
options.gender = "Male";
options.byear = 1919;
Countly.setUserData(options);
The keys for predefined user data fields are as follows:
Key | Type | Description |
---|---|---|
name | String | User's full name |
username | String | User's nickname |
String | User's email address | |
organization | String | User's organisation name |
phone | String | User's phone number |
picture | String | URL to avatar or profile picture of the user |
gender | String | User's gender as M for male and F for female |
byear | String | User's year of birth as integer |
Using "" for strings or a negative number for 'byear' will effectively delete that property.
For custom user properties you may use any key values to be stored and displayed on your Countly backend. Note: keys with . or $ symbols will have those symbols removed.
Setting custom values
Additionally you can do different manipulations on your custom data values, like increment current value on server or store a array of values under the same property.
Below is the list of available methods:
// example for extra user features
Countly.userData.setProperty("setProperty", "My Property");
Countly.userData.increment("increment");
Countly.userData.incrementBy("incrementBy", 10);
Countly.userData.multiply("multiply", 20);
Countly.userData.saveMax("saveMax", 100);
Countly.userData.saveMin("saveMin", 50);
Countly.userData.setOnce("setOnce", 200);
Countly.userData.pushUniqueValue("pushUniqueValue","morning");
Countly.userData.pushValue("pushValue", "morning");
Countly.userData.pullValue("pullValue", "morning");
In the end always call Countly.userData.save() to send them to the server.
Application Performance Monitoring
This feature is only supported by the minimum SDK version 20.4.0.
Performance Monitoring feature allows you to analyze your application's performance on various aspects. For more details please see Performance Monitoring documentation.
Here is how you can utilize Performance Monitoring feature in your apps:
First, you need to enable Performance Monitoring feature::
Countly.enableApm();
// Enable APM features.
With this, Countly SDK will start measuring some performance traces automatically. Those include app foreground time, app background time. Additionally, custom traces and network traces can be manually recorded.
App Start Time
For the app start time to be recorded, you need to call the appLoadingFinished
method. Make sure this method is called after init
.
// Example of appLoadingFinished
Countly.init("https://try.count.ly", "YOUR_APP_KEY").then((result) => {
Countly.appLoadingFinished();
},(err) => {
onsole.error(err);
});
This calculates and records the app launch time for performance monitoring. It should be called when the app is loaded and it successfully displayed its first user-facing view. E.g. onDeviceReady:
method or wherever is suitable for the app's flow. The time passed since the app has started to launch will be automatically calculated and recorded for performance monitoring. Note that the app launch time can be recorded only once per app launch. So, the second and following calls to this method will be ignored.
Custom traces
You may also measure any operation you want and record it using custom traces. First, you need to start a trace by using the startTrace(traceKey)
method:
Countly.startTrace(traceKey);
Then you may end it using the endTrace(traceKey, customMetric)
method, optionally passing any metrics as key-value pairs:
String traceKey = "Trace Key"
;
Map<String, int> customMetric = {
"ABC": 1233,
"C44C": 1337
};
Countly.endTrace(traceKey, customMetric);
The duration of the custom trace will be automatically calculated on ending. Trace names should be non-zero length valid strings. Trying to start a custom trace with the already started name will have no effect. Trying to end a custom trace with already ended (or not yet started) name will have no effect.
You may also cancel any custom trace you started, using cancelTrace(traceKey)
method:
Countly.cancelTrace(traceKey);
Additionally, if you need you may cancel all custom traces you started, using clearAllTraces()
method:
Countly.clearAllTraces(traceKey);
Network traces
You may record manual network traces using theecordNetworkTrace(networkTraceKey, responseCode, requestPayloadSize, responsePayloadSize, startTime, endTime)
method.
A network trace is a collection of measured information about a network request. When a network request is completed, a network trace can be recorded manually to be analyzed in the Performance Monitoring feature later with the following parameters:
- networkTraceKey
: A non-zero length valid string - responseCode
: HTTP status code of the received response - requestPayloadSize
: Size of the request's payload in bytes - responsePayloadSize
: Size of the received response's payload in bytes - startTime
: UNIX time stamp in milliseconds for the starting time of the request - endTime
: UNIX time stamp in milliseconds for the ending time of the request
Countly.recordNetworkTrace(networkTraceKey, responseCode, requestPayloadSize, responsePayloadSize, startTime, endTime);
User Consent
To be compliant with GDPR, starting from 18.04, Countly provides ways to toggle different Countly features on/off depending on the given consent.
More information about GDPR can be found here.
By default the requirement for consent is disabled. To enable it, you have to call setRequiresConsent with true, before initializing Countly.
Countly.setRequiresConsent(true);
By default no consent is given. That means that if no consent is enabled, Countly will not work and no network requests, related to features, will be sent. When consent status of a feature is changed, that change will be sent to the Countly server.
For all features, except push, consent is not persistent and will have to be set every time before countly init. Therefore the storage and persistance of given consent falls on the sdk integrator.
Consent for features can be given and revoked at any time, but if it is given after Countly init, some features might work partially.
If consent is removed, but the appropriate function can't be called before the app closes, it should be done at next app start so that any relevant server side features could be disabled (like reverse geo ip for location)
Feature names in the Android SDK are stored as static fields in the class called CountlyFeatureNames.
The current features are:
- sessions - tracking when, how often and how long users use your app
- events - allow sending events to server
- views - allow tracking which views user visits
- location - allow sending location information
- crashes - allow tracking crashes, exceptions and errors
- attribution - allow tracking from which campaign did user come
- users - allow collecting/providing user information, including custom properties
- push - allow push notifications
- starRating - allow to send their rating and feedback
- apm - allow application performance monitoring
- remote-config - allows downloading remote config values from your server
Changing consent
There are 3 ways of changing feature consent:
- giveConsentInit - To add consent for a single feature (string parameter) or a subset of features (array of strings parameter). Use this method for giving consent before initializing.
//giveConsent
Countly.giveConsentInit(["events", "views", "star-rating", "crashes"]);
// removeConsent
Countly.removeConsent(["events", "views", "star-rating", "crashes"]);
- giveConsent/removeConsent - gives or removes consent to a specific feature
//giveConsent
Countly.giveConsent(["events", "views", "star-rating", "crashes"]);
// removeConsent
Countly.removeConsent(["events", "views", "star-rating", "crashes"]);
- giveAllConsent/removeAllConsent - giveAll or removeAll consent to a specific feature
//giveAllConsent
Countly.giveAllConsent();
//removeAllConsent
Countly.removeAllConsent();
Security and privacy
Parameter Tampering Protection
You can set optional salt to be used for calculating checksum of request data, which will be sent with each request using &checksum field. You need to set exactly the same salt on Countly server. If salt on Countly server is set, all requests would be checked for validity of &checksum field before being processed.
// sending data with salt
Countly.enableParameterTamperingProtection("salt");
Using Proguard
If you are using Countly Messaging in your Android application, it is recommended to obfuscate the Countly Messaging classes using Proguard. To do so, please follow the instructions below:
-
Locate the app/proguard-rules.pro file within the /android/app/ folder.
-
Add the following lines to the file:
-keep class ly.count.android.sdk.** { *; }
-
If Proguard is not yet configured, you must first enable shrinking and obfuscation in the build file. To do so, locate the build.gradle file within the /android/app/ folder.
-
Add the following lines in bold to the build.gradle file:
...
buildTypes {
release { // Enables code shrinking, obfuscation, and optimization for only your project's release build type.
...
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
...
By following these steps, the Countly Messaging classes will be obfuscated using Proguard and your application will be better protected against reverse engineering.
Other features
Forcing HTTP POST
If the data sent to the server is short enough, the sdk will use HTTP GET requests. In case you want an override so that HTTP POST is used in all cases, call the "setHttpPostForced" function after you called "init". You can use the same function to later in the apps life cycle disable the override. This function has to be called every time the app starts.
Countly.setHttpPostForced(true); // default is false
Optional parameters during initialization
You can provide optional parameters that will be used during begin_session request. They must be set right after the init
function so that they are set before the request is sent to the server. To set them, use the setOptionalParametersForInitialization
function. If you want to set those optional parameters, this function has to be called every time the app starts. If you don't to set one off those values, leave that field null
.
The optional parameters are:
- Country code: ISO Country code for the user's country
- City: Name of the user's city
- Location: Comma separate latitude and longitude values, for example "56.42345,123.45325"
//setting optional parameters
Countly.setOptionalParametersForInitialization({
city: "Tampa",
country: "US",
latitude: "28.006324",
longitude: "-82.7166183",
ipAddress: "255.255.255.255"
});
//and then call the below code
Countly.init(this, "https://YOUR_SERVER", "YOUR_APP_KEY", "YOUR_DEVICE_ID")
Comments
Please sign in to leave a comment.