Android (3.3.0+)
Before I start
Since version 3.3.0, our Android SDK is written in Kotlin.
Integrate the library
The first step to use our SDK is to integrate our library in your project. You have multiple ways to do this.
Maven
Add this following line in your build.gradle file (app-level) under dependencies:
implementation("io.piano.android:analytics:VERSION") // replace VERSION with the version you target
Add required Google/Huawei ID libraries, if you want to use it as Visitor ID
dependencies {
...
// for GOOGLE_ADVERTISING_ID or ADVERTISING_ID
implementation("com.google.android.gms:play-services-ads-identifier:GOOGLE_VERSION")
// for HUAWEI_OPEN_ADVERTISING_ID or ADVERTISING_ID
implementation("com.huawei.hms:hms-ads-identifier:HUAWEIVERSION")
}
Add Huawei libraries repository (only if you've added Huawei ID library at the previous step)
repositories {
...
maven("https://developer.huawei.com/repo/")
}
Manually
-
Clone the Android SDK from our GitHub repository:
- SSH:
git@github.com:at-internet/piano-analytics-android.git - HTTPS:
https://github.com/at-internet/piano-analytics-android.git
- SSH:
-
From your Android Studio
- Go to File > Project Structure > Modules
- Click on the plus sign + and go to Import...
- Search for the cloned directory and select the piano-analytics folder
- Click on Finish
-
After a sync of Gradle you might have an error like 'Build was configured to prefer settings repositories over project repositories'
- Open your project-level settings.gradle file and replace/add the repositoriesMode as below
repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
- Resync Gradle
- Open your project-level settings.gradle file and replace/add the repositoriesMode as below
-
As a support to Huawei in our SDK, you might also have a warning on sync (error on build) talking about a library from
com.huawei.hms-
For Gradle plugin earlier than 7.0
- Open your project-level
build.gradlefile - Add the Maven repository as below under buildscript > repositories and allproject > repositories
maven {url 'https://developer.huawei.com/repo/'}
- Open your project-level
-
For Gradle plugin 7.0
- Open your project-level
build.gradlefile - Add the Maven repository as below under buildscript > repositories
maven {url 'https://developer.huawei.com/repo/'}
- Open your project-level
settings.gradlefile - Add the Maven repository as below under dependencyResolutionManagement > repositories
maven {url 'https://developer.huawei.com/repo/'}
- Open your project-level
-
For Gradle plugin 7.1 or Later
- Open your project-level
settings.gradlefile - Add the Maven repository as below under pluginManagement > repositories and dependencyResolutionManagement > repositories
maven {url 'https://developer.huawei.com/repo/'}
- Open your project-level
-
piano-analytics should now be recognized as a library
Instantiate tracker
First of all, you should ensure that your app permissions are correctly set. You need the following permissions in your AndroidManifest.xml:
<!-- Allow the application to send events to Piano Analytics -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Allow to check network condition before trying to send events -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Our Android SDK requires you to configure and init a tracker before using it.
You should pass the application context as a parameter.
val configuration = Configuration.Builder(
collectDomain = "<xxxxxxx>.pa-cd.com",
site = 123456789,
// you can set other configurations here
).defaultPrivacyMode(...)
// or set configurations via builder methods
.build()
PianoAnalytics.init(applicationContext, configuration)
Don't hesitate to read our collection methods article to find the collection domain that has been assigned to you.
You can also use a custom domain thanks to our CDDC.
Here are the available configurations:
| Category | Name | Description | Type | Value | More info |
|---|---|---|---|---|---|
| Global | collectDomain | Collection domain | string | https://<xxxxxxx>.pa-cd.com | View |
| Global | site | Site id | int | 123456789 | View |
| Global | path | Request path | string | event | |
| Global | reportUrlProvider | ≥ 3.3.2 Dynamic provider for collection domain, site id and path. Overrides static collectDomain, site and path. | ReportUrlProvider | Custom implementation or StaticReportUrlProvider | View |
| Global | detectCrashes | Enable (true) or not (false) automatic crash detection | boolean | true (default), false | |
| Global | sessionBackgroundDuration | Backgound delay before considering a session as over (seconds) | int | 30 (default) | |
| Privacy | ignoreLimitedAdTracking | Whether the SDK should ignore (true) or not (false) the end-user choice to limit ad tracking. | boolean | true, false (default) | |
| Privacy | sendEventWhenOptout | Do you want to send events when optout? | boolean | true (default), false | |
| Privacy | defaultPrivacyMode | Privacy mode by default | Configuration.PrivacyMode | optin (default) | View |
| Storage | offlineStorageMode | Offline feature storage mode. Configuration.OfflineStorageMode.ALWAYS will always store data, you need to send data yourself Configuration.OfflineStorageMode.REQUIRED automatically manage offline storage depending on network conditions. If you want to disable storage, set eventsOfflineStorageLifetime to 0. | Configuration.OfflineStorageMode | Configuration.OfflineStorageMode.ALWAYS, Configuration.OfflineStorageMode.REQUIRED (default) | |
| Storage | eventsOfflineStorageLifetime | Offline feature storage lifetime (days). | int | 30 (default) | |
| Storage | privacyStorageLifetime | Lifetime Storage Privacy value | int | 395 (days) | View |
| Storage | userStorageLifetime | Lifetime Storage User value | int | 395 (days) | View |
| Storage | visitorStorageLifetime | Lifetime Storage Visitor value | int | 395 (days) | View |
| Storage | visitorStorageMode | Relative or fixed cookie lifetime value for visitor | Configuration.VisitorStorageMode | Configuration.VisitorStorageMode.FIXED (default), Configuration.VisitorStorageMode.RELATIVE | |
| Visitor Policy | visitorIDType | Visitor ID type | Configuration.VisitorIDType | Configuration.VisitorIDType.UUID (default), Configuration.VisitorIDType.ADVERTISING_ID, Configuration.VisitorIDType.GOOGLE_ADVERTISING_ID, Configuration.VisitorIDType.HUAWEI_OPEN_ADVERTISING_ID, Configuration.VisitorIDType.CUSTOM |
Dynamically update collect domain and site
ReportUrlProvider is available since ≥ 3.3.2.
Since version 3.3.0, the SDK configuration cannot be replaced after PianoAnalytics.init(). If you need to switch collectDomain, site, or path at runtime (for example when the end user changes country or environment), pass a custom ReportUrlProvider at initialization.
You cannot replace the ReportUrlProvider instance after init, but the SDK does not cache the values it returns. Each time an event is sent, the SDK reads the current collectDomain, site, and path from your provider.
class CustomReportUrlProvider(
private val remoteConfig: FirebaseRemoteConfig,
) : ReportUrlProvider {
override val collectDomain: String
get() = remoteConfig.getString("collectDomain")
override val site: Int
get() = remoteConfig.getInt("site")
// Optional — defaults to Configuration.DEFAULT_PATH ("event")
// override val path: String
// get() = remoteConfig.getString("path")
}
val configuration = Configuration.Builder(
reportUrlProvider = CustomReportUrlProvider(remoteConfig),
).build()
PianoAnalytics.init(applicationContext, configuration)
You can also keep mutable fields in your provider and update them when the selected environment changes:
class MutableReportUrlProvider(
override var collectDomain: String,
override var site: Int,
) : ReportUrlProvider
val reportUrlProvider = MutableReportUrlProvider(
collectDomain = "<xxxxxxx>.pa-cd.com",
site = 123456789,
)
val configuration = Configuration.Builder(
reportUrlProvider = reportUrlProvider,
).build()
PianoAnalytics.init(applicationContext, configuration)
// Later, when the environment changes:
reportUrlProvider.collectDomain = "<yyyyyyy>.pa-cd.com"
reportUrlProvider.site = 987654321
Events already stored offline keep being flushed with the current provider values. If you change collectDomain or site, previously stored events may be sent to the new destination.
Call PianoAnalytics.getInstance().deleteOfflineStorage() before switching if you want to drop unsynced events instead.
Data storage encryption
If you need your data storage to be encrypted, you should specify an encoder on SDK init:
object PlainDataEncoder : DataEncoder {
override fun encode(data: String): String = data
override fun decode(data: String): String = data
}
PianoAnalytics.init(applicationContext, configuration, PlainDataEncoder)
Changelog
You can find the Android changelog directly on GitHub.
If you want to stay updated with our SDK releases, subscribe on GitHub:

Migration from < 3.3.0
We rewritten our SDK from Java to Kotlin starting from version 3.3.0.
Here are the breaking changes you should be aware of when migrating from a version < 3.3.0:
io.piano.analyticsis nowio.piano.android.analytics.- You should update your Maven implementation:
implementation("io.piano.android:analytics:VERSION"). - You should update your imports:
import io.piano.android.analytics.PianoAnalytics.
- You should update your Maven implementation:
- Event tagging has changed. Please check our documentation.
- We do not provide
sendEvent()method anymore, onlysendEvents().
- We do not provide
- AV Insights tagging has changed. Please check our documentation.
setPropertymethod should be updated to useContextProperties.- Privacy management has been reviewed, please check our documentation.
- We don't offer Android ID as a visitor identification option anymore, to follow Android guidelines.
- SDK initialisation has changed. Please check our documentation.
- Configuration can't be changed after init anymore. To switch
collectDomain,site, orpathat runtime, use aReportUrlProvider(≥ 3.3.2). - Some configuration names have changes:
visitorIdType->visitorIDTypeprivacyDefaultMode->defaultPrivacyModestorageLifetimeVisitor->visitorStorageLifetimestorageLifetimePrivacy->privacyStorageLifetimestorageLifetimeUser->userStorageLifetimestorageLifetimeVisitor->visitorStorageLifetimeignoreLimitedAdvertisingTracking->ignoreLimitedAdTrackingcrashDetection->detectCrashes
- Some configurations must be implemented in another way:
offlineEncryptionModemust be replaced by an encoder set on SDK init.visitorIdmust be set usingPianoAnalytics.getInstance().customVisitorId = "custom-visitor-id"(used only ifvisitorIDTypeis set toVisitorIDType.CUSTOM)
- You can't set custom User-Agent anymore (now fixed to
Piano Analytics SDK <SDK_VERSION>).