Flutter

Follow

This document includes necessary information for integrating Countly Flutter SDK in your application. Flutter SDK requires Android and iOS SDKs, hence all the features and limitations regarding those platforms also apply to Countly Flutter SDK.

Installing the SDK

Add this to your package's pubspec.yaml file:

dependencies:
  countly_flutter:
    git: 
      url: https://github.com/Countly/countly-sdk-flutter-bridge.git
      ref: master

You can install packages from the command line with Flutter:

flutter pub get

Example Flutter application

Below you can see steps to download a Flutter example application:

git clone https://github.com/Countly/countly-sdk-flutter-bridge.git
cd countly-sdk-flutter-bridge/example
flutter pub get
flutter run

This example application has all the methods mentioned in this documentation. It is a great way of understanding how different methods work, like custom events, custom user profiles and views.

Implementation

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.

Initialization

First, you'll need to decide which device ID generation strategy to use. There are several options defined below:

First and easiest method is, if you want Countly SDK to take care of device ID seamlessly, use the line below. You can find your app key on your Countly dashboard, under "Applications" menu item.

// use your server name below if required.
Countly.init("https://try.count.ly","App_Key");

Changing a Device ID

In case your application authenticates users, you can also change device ID to your user ID later. This helps you identify a specific user with a specific ID on a device she logs in, and the same scenario can also be used in cases this user logs in using a different way (e.g tablet, another mobile phone or web). In this case any data stored in Countly server database and associated with temporary device ID will be transferred into user profile with device id you specified in the following method call:

// change device id
Countly.changeDeviceId(deviceId, false);

Change deviceId to Temporary ID

In the previous ID managemend approaches, data is still sent your server, but it adds user inflation risk if badly managed. The use of a temporary ID can help to mitigate such problems. During app start or any time after init, you can enter a temporary device ID mode. All requests will be stored internally and not sent to your server until a new device ID is provided. In that case all events created during this temporary ID mode will be associated with the new device ID and sent to the server.

To enable this mode during init, you would call this on your config object before init:

Countly.init(SERVER_URL, APP_KEY, Countly.deviceIDType["TemporaryDeviceID"]);

To enable temporary id after init, you would call:

Countly.changeDeviceId(Countly.deviceIDType["TemporaryDeviceID"], false);

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");

Make sure not to use a salt on Countly server and not on SDK side, otherwise Countly won't accept any incoming requests.

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 later in the app's life cycle to disable the override. This function has to be called every time the app starts.

 Countly.setHttpPostForced(true); // default is false

Starting a session

//example to start
Countly.start();

Stopping a session

//example to stop Countly
Countly.stop();

Recording an event

A custom 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 Flutter SDK to Countly instance by default.

Data passed should be in UTF-8

All data passed to Countly server via SDK or API should be in UTF-8.

As an example, we will be recording a purchase event. Here is a quick summary what information each usage will provide us:

  • Usage 1: how many times purchase event occured.
  • Usage 2: how many times purchase event occured + the total amount of those purchases.
  • Usage 3: how many times purchase event occured + which countries and application versions those purchases were made from.
  • Usage 4: how many times purchase event occured + the total amount both of which are also available segmented into countries and application versions.
  • Usage 5: how many times purchase event occured + the total amount both of which are also available segmented into countries and application versions + the total duration of those events (under Timed Events topic below)

1. Event key and count

// example for sending basic custom event
var event = {
  "key": "Basic Event",
  "count": 1
};
Countly.recordEvent(event);

2. Event key, count and sum

// example for event with sum
var event = {
  "key": "Event With Sum",
  "count": 1,
  "sum": "0.99",
};
Countly.recordEvent(event);

3. Event key and count with segmentation(s)

// example for event with segment
var event = {
  "key": "Event With Segment",
  "count": 1
};
event["segmentation"] = {
  "Country": "Germany",
  "Age": "28"
};
Countly.recordEvent(event);

4. Event key, count and sum with segmentation(s)


// example for event with segment and sum
var event = {
  "key": "Event With Sum And Segment",
  "count": 1,
  "sum": "0.99"
};
event["segmentation"] = {
  "Country": "Germany",
  "Age": "28"
};
Countly.recordEvent(event);

Timed events

1.Timed event with key

// Basic event
Countly.startEvent("Timed Event");
Timer timer;
timer = new Timer(new Duration(seconds: 5), () {
    Countly.endEvent({ "key": "Timed Event" });
    timer.cancel();
});

2.Timed event with key and sum

// Event with sum
Countly.startEvent("Timed Event With Sum");
Timer timer;
timer = new Timer(new Duration(seconds: 5), () {
    Countly.endEvent({ "key": "Timed Event With Sum", "sum": "0.99" });
    timer.cancel();
});

3.Timed event with key, count and segmentation

// Event with segment
Countly.startEvent("Timed Event With Segment");
Timer timer;
timer = new Timer(new Duration(seconds: 5), () {
    var event = {
        "key": "Timed Event With Segment",
        "count": 1,
    };
    event["segmentation"] = {
      	"Country": "Germany",
      	"Age": "28"
    };
    Countly.endEvent(event);
    timer.cancel();
});

4.Timed event with key, count, sum and segmentation

// Event with Segment, sum and count
Countly.startEvent("Timed Event With Segment, Sum and Count");
Timer timer;
timer = new Timer(new Duration(seconds: 5), () {
    var event = {
        "key": "Timed Event With Segment, Sum and Count",
        "count": 1,
        "sum": "0.99"
    };
    event["segmentation"] = {
        "Country": "Germany",
        "Age": "28"
    };
    Countly.endEvent(event);
    timer.cancel();
});

User Profiles

In order to set a user profile, use the code snippet below. After you send a user data, it can be viewed under User Profiles menu.

Note that this feature is available only for Enterprise Edition.

// example for setting user data
Map<String, Object> options = {
    "name": "Nicola Tesla",
    "username": "nicola",
    "email": "info@nicola.tesla",
    "organization": "Trust Electric Ltd",
    "phone": "+90 822 140 2546",
    "picture": "http://images2.fanpop.com/images/photos/3300000/Nikola-Tesla-nikola-tesla-3365940-600-738.jpg",
    "picturePath": "",
    "gender": "M", // "F"
    "byear": "1919",
};
Countly.setUserData(options);

In order to modify a user's data (e.g increment, etc), the following code sample can be used.

Modifying custom data

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:


//set one custom properties
Countly.setProperty("setProperty", "My Property");
//increment used value by 1
Countly.increment("increment");
//increment used value by provided value
Countly.incrementBy("incrementBy", 10);
//multiply value by provided value
Countly.multiply("multiply", 20);
//save maximal value
Countly.saveMax("saveMax", 100);
//save minimal value
Countly.saveMin("saveMin", 50);
//set value if it does not exist
Countly.setOnce("setOnce", 200);

//insert value to array of unique values
Countly.pushUniqueValue("type", "morning");;
//insert value to array which can have duplocates
Countly.pushValue("type", "morning");
//remove value from array
Countly.pullValue("type", "morning");

Crash reporting

With this feature, Countly SDK will generate a crash report if your application crashes due to an exception, and send it to Countly server for further inspection.

If a crash report can not be delivered to server (e.g. no internet connection, unavailable server), then SDK stores the crash report locally in order to try again later.

Enabling crash reporting

// Using countly crash reports
Countly.enableCrashReporting();

Send a custom crash log

You can also send a custom crash log to Countly using code below.

// Send a custom crash log
Countly.enableCrashReporting();
Countly.addCrashLog("User Performed Step A");
Timer timer;
timer = new Timer(new Duration(seconds: 5), () {
    Countly.logException("one.js \n two.js \n three.js", true, {"_facebook_version": "0.0.1"});
    timer.cancel();
});

Sending an exception to the server

// Send Exception to the server
Countly.logException("execption", true, null);
Countly.logException(stackFramesFromStackTraceJS, booleanNonFatal, segments);

View tracking

You can manually add your own views in your application, and each view will be visible under Views menu item. Below you can see two examples of sending a view using Countly.recordview function.

// record a view on your application
Countly.recordView("HomePage");
Countly.recordView("Dashboard");

Getting user feedback

There are two ways of getting feedback from your users: Star rating dialog and 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.

Feedback 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 an 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:

Countly.askForFeedback("5da0877c31ec7124c8bf398d", "Close");

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".

Countly.askForStarRating();

Star rating dialog can be displayed in 2 ways:

  • Manually, by developer
  • Automatically, depending on session count

In order to display the Star rating dialog manually, you must call the ShowStarRating function. Optionally, you can provide the callback functions. There is no limit on how many times star-rating dialog can be displayed manually.

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 download

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.

Countly.setRemoteConfigAutomaticDownload((result){
	print(result);
});

If the callback returns a non null value, then you can expect that the request failed and no values where updated.

When doing a automatic update, all locally stored values are replaced with the ones received (all locally stored ones are deleted and in their place are put new ones). It is possible that a previously valid key returns no value after a update.

Manual remote config download

There are three ways for manually requesting 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, the request encountered some error and failed.

Functionally the manual update for everything remoteConfigUpdate is the same as the automatic update - replaces all stored values with the ones from the server (all locally stored ones are deleted and in their place are put new ones). 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((result){
	print(result);
});

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"],(result){
	print(result);
});

You might want to update all values except a few defined keys, for that call updateRemoteConfigExceptKeys. The key list is an array with string values of the keys. It has a callback to let you know when the request has finished.

Countly.updateRemoteConfigExceptKeys(["url"],(result){
	print(result);
});

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 a Object. The developer needs to cast it to the appropiate type. The returned values can also be a JSONArray, JSONObject or just a simple value like int.

Countly.getRemoteConfigValueForKey("name", (result){
	print(result);
});

Clearing stored remote config values

At some point you might want to erase all values downloaded from the server. To achieve that you need to call one function.

Countly.remoteConfigClearValues((result){
	print(result);
});

User consent management

To be compliant with GDPR, 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 notifications, consent is not persistent and will have to be set every time before Countly init. Therefore the storage and persistence of given consent relies 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 Flutter 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 custom 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
  • star-rating - allow to send their rating and feedback

Giving Multiple Consents

Countly.giveConsent(["events", "views", "star-rating", "crashes"]);

Removing multiple consents

Countly.removeConsent(["events", "views", "star-rating", "crashes"]);

Giving all consents

Countly.giveAllConsent();

Removing All Consents

Countly.removeAllConsent();

Troubleshooting

Warning about Java

Note: As per the new release, you will need Java 1.8 to bundle the application. You will need to update the CLASSPATH environment variable of Java and Javac to Java version 1.8

If you would like to set logging, use code snippet below in your code.

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
Map<String, Object> options = {
    "city": "Tampa",
    "country": "US",
    "latitude": "28.006324",
    "longitude": "-82.7166183"
};
Countly.setOptionalParametersForInitialization(options);




//and then call the below code
Countly.init(this, "https://YOUR_SERVER", "YOUR_APP_KEY", "YOUR_DEVICE_ID")

Enabling logging

If logging is enabled then our SDK will print out debug messages about its internal state and encountered problems.

When advise doing this while implementing Countly features in your application.

Countly.setLoggingEnabled(true);

Push notifications

Android

Step 1: Hope you have created your flutter app, and installed countly_flutter package.

Step 2: Make sure you have google-services.json from https://firebase.google.com/

Step 3: Make sure the app package name and the google-services.json package_name matches.

Step 4: Place the google-services.json file inside android/app

Step 5: Add the following line in file android/app/src/main/AndroidManifest.xml inside application tag.

<service android:name="ly.count.dart.countly_flutter.CountlyMessagingService">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Step 7: Use the latest version from this link https://firebase.google.com/support/release-notes/android#latest_sdk_versions and this link https://developers.google.com/android/guides/google-services-plugin

Step 6: Add the following line in file android/build.gradle

buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.3.2'
    }
}

Step 7: Add the following line in file android/app/build.gradle

dependencies {
    implementation 'ly.count.android:sdk:20.04'
    implementation 'com.google.firebase:firebase-messaging:20.0.0'
}
// Add this at the bottom of the file
apply plugin: 'com.google.gms.google-services'

iOS

For iOS push notification please follow the instruction from this URL https://resources.count.ly/docs/countly-sdk-for-ios-and-os-x#section-push-notifications

For Flutter you can find CountlyNotificationService.m file under Pods/Pods/Countly/CountlyNotificationService.m

You can drag and drop the file from Pod to Compile Sources.

Flutter implementation for push notifications is as follows:

Countly.askForNotificationPermission();
Was this article helpful?
0 out of 0 found this helpful

Looking for help?