diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1158ea9..6943c7b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,7 +24,7 @@ jobs: run: chmod +x gradlew - name: Check code style run: ./gradlew ktlintCheck --continue - - name: Run tests` + - name: Run tests run: ./gradlew testDebug - name: Build project run: ./gradlew app:asDeb diff --git a/CHANGELOG.md b/CHANGELOG.md index 23fcdd7..8582a3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Piano Analytics SDK for Android +## v3.3.2 +* Added `ReportUrlProvider` to `Configuration` for case "switching between several site ids for one app at runtime" + ## v3.3.1 * Fixed setting properties `av_previous_position`, `av_position` and `av_duration` * Added `PianoAnalytics.EventProcessorCallback` as a replacement for previous `OnWorkListener` diff --git a/piano-analytics/gradle.properties b/piano-analytics/gradle.properties index 937338c..739a247 100644 --- a/piano-analytics/gradle.properties +++ b/piano-analytics/gradle.properties @@ -1,4 +1,4 @@ -VERSION_NAME=3.3.1 +VERSION_NAME=3.3.2 GROUP=io.piano.android POM_NAME=Analytics POM_ARTIFACT_ID=analytics diff --git a/piano-analytics/src/main/java/io/piano/android/analytics/Configuration.kt b/piano-analytics/src/main/java/io/piano/android/analytics/Configuration.kt index a542639..ee8d6f7 100644 --- a/piano-analytics/src/main/java/io/piano/android/analytics/Configuration.kt +++ b/piano-analytics/src/main/java/io/piano/android/analytics/Configuration.kt @@ -9,9 +9,7 @@ import io.piano.android.analytics.model.VisitorStorageMode * Class for storing all configuration */ class Configuration private constructor( - val collectDomain: String, - val site: Int, - val path: String, + val reportUrlProvider: ReportUrlProvider, val defaultPrivacyMode: PrivacyMode, val visitorIDType: VisitorIDType, val offlineStorageMode: OfflineStorageMode, @@ -24,10 +22,10 @@ class Configuration private constructor( val detectCrashes: Boolean, val ignoreLimitedAdTracking: Boolean, val sendEventWhenOptOut: Boolean, -) { +) : ReportUrlProvider by reportUrlProvider { class Builder @JvmOverloads constructor( - var collectDomain: String, - var site: Int, + var collectDomain: String = "", + var site: Int = 0, var path: String = DEFAULT_PATH, var defaultPrivacyMode: PrivacyMode = PrivacyMode.OPTIN, var visitorIDType: VisitorIDType = VisitorIDType.UUID, @@ -41,6 +39,7 @@ class Configuration private constructor( var detectCrashes: Boolean = true, var ignoreLimitedAdTracking: Boolean = false, var sendEventWhenOptOut: Boolean = true, + var reportUrlProvider: ReportUrlProvider? = null, ) { /** @@ -179,28 +178,40 @@ class Configuration private constructor( @Suppress("unused") // Public API. fun sendEventWhenOptOut(sendEventWhenOptOut: Boolean) = apply { this.sendEventWhenOptOut = sendEventWhenOptOut } + /** + * Sets a custom [ReportUrlProvider], which overrides [collectDomain], [site] and [path] for [Configuration] + * @param reportUrlProvider [ReportUrlProvider] instance + * @return updated Builder instance + */ + fun reportUrlProvider(reportUrlProvider: ReportUrlProvider?) = apply { + this.reportUrlProvider = reportUrlProvider + } + /** * Get a new Configuration instance from Builder data set * @return an Configuration instance */ @Suppress("unused") // Public API. - fun build() = Configuration( - collectDomain, - site, - path, - defaultPrivacyMode, - visitorIDType, - offlineStorageMode, - visitorStorageMode, - eventsOfflineStorageLifetime, - privacyStorageLifetime, - visitorStorageLifetime, - userStorageLifetime, - sessionBackgroundDuration.coerceAtLeast(MIN_SESSION_BACKGROUND_DURATION), - detectCrashes, - ignoreLimitedAdTracking, - sendEventWhenOptOut - ) + fun build(): Configuration { + check(reportUrlProvider != null || (collectDomain.isNotEmpty() && site > 0)) { + "You have to provide collectDomain and site or reportUrlProvider" + } + return Configuration( + reportUrlProvider ?: StaticReportUrlProvider(collectDomain, site, path), + defaultPrivacyMode, + visitorIDType, + offlineStorageMode, + visitorStorageMode, + eventsOfflineStorageLifetime, + privacyStorageLifetime, + visitorStorageLifetime, + userStorageLifetime, + sessionBackgroundDuration.coerceAtLeast(MIN_SESSION_BACKGROUND_DURATION), + detectCrashes, + ignoreLimitedAdTracking, + sendEventWhenOptOut + ) + } } companion object { diff --git a/piano-analytics/src/main/java/io/piano/android/analytics/ReportUrlProvider.kt b/piano-analytics/src/main/java/io/piano/android/analytics/ReportUrlProvider.kt new file mode 100644 index 0000000..421fffa --- /dev/null +++ b/piano-analytics/src/main/java/io/piano/android/analytics/ReportUrlProvider.kt @@ -0,0 +1,32 @@ +package io.piano.android.analytics + +/** + * Interface for providing URL parts like [collectDomain], [site] adn [path] + * SDK doesn't cache results from these methods, which allows you to dynamically change values + */ +interface ReportUrlProvider { + /** + * fully qualified domain name (FQDN) collect + */ + val collectDomain: String + + /** + * site identifier + */ + val site: Int + + /** + * a resource name string prefixed by '/' + */ + val path: String + get() = Configuration.DEFAULT_PATH +} + +/** + * Implementation of [ReportUrlProvider], that return static values + */ +class StaticReportUrlProvider( + override val collectDomain: String, + override val site: Int, + override val path: String = Configuration.DEFAULT_PATH, +) : ReportUrlProvider diff --git a/piano-analytics/src/main/java/io/piano/android/analytics/SendTask.kt b/piano-analytics/src/main/java/io/piano/android/analytics/SendTask.kt index 90c3b5e..2d9a046 100644 --- a/piano-analytics/src/main/java/io/piano/android/analytics/SendTask.kt +++ b/piano-analytics/src/main/java/io/piano/android/analytics/SendTask.kt @@ -32,22 +32,22 @@ internal class SendTask( } internal fun send(events: List) { - val url = HttpUrl.Builder() - .scheme("https") - .host(configuration.collectDomain) - .addEncodedPathSegment(configuration.path) - .addQueryParameter("s", configuration.site.toString()) - .addQueryParameter("idclient", visitorIdProvider.visitorId) - .build() - val requestBody = with(Buffer()) { - eventsJsonAdapter.toJson(JsonWriter.of(this), EventsRequest(events.map { it.data })) - readByteString().toRequestBody(MEDIA_TYPE) - } - val request = Request.Builder() - .url(url) - .post(requestBody) - .build() runCatching { + val url = HttpUrl.Builder() + .scheme("https") + .host(configuration.collectDomain) + .addEncodedPathSegment(configuration.path) + .addQueryParameter("s", configuration.site.toString()) + .addQueryParameter("idclient", visitorIdProvider.visitorId) + .build() + val requestBody = with(Buffer()) { + eventsJsonAdapter.toJson(JsonWriter.of(this), EventsRequest(events.map { it.data })) + readByteString().toRequestBody(MEDIA_TYPE) + } + val request = Request.Builder() + .url(url) + .post(requestBody) + .build() okHttpClient.newCall(request).execute() }.onFailure { Timber.w(it)