From aaea918343544262e3692ef2a4b0de0561b79ee5 Mon Sep 17 00:00:00 2001 From: Dmitriy Date: Tue, 16 Jan 2024 11:27:33 +0400 Subject: [PATCH 1/2] Fix nullability issue, update dependencies --- CHANGELOG.md | 12 ++++ composer-c1x/build.gradle.kts | 3 + composer/build.gradle.kts | 3 + .../io/piano/android/composer/Composer.kt | 5 +- .../android/composer/EdgeCookiesProvider.kt | 6 ++ .../android/composer/model/EdgeCookies.kt | 2 + .../io/piano/android/composer/ComposerTest.kt | 9 ++- gradle.properties | 3 +- gradle/libs.versions.toml | 18 ++--- .../android/ktlint/KtlintConfigPlugin.kt | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- id/id/build.gradle.kts | 1 + .../io/piano/android/id/models/CustomField.kt | 2 +- sample/build.gradle.kts | 5 ++ .../java/io/piano/sample/ComposerActivity.kt | 2 +- .../main/java/io/piano/sample/MainActivity.kt | 71 ++++++++++++++++++- .../sample/SimpleDependenciesProvider.kt | 7 ++ sample/src/main/res/layout/activity_main.xml | 6 ++ 18 files changed, 141 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 234f832..e42ac1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Piano SDK for Android +## v2.9.1-SNAPSHOT +* Fix nullability for custom field value in Piano ID user profile +* Updated dependencies + - androidx.activity:activity [1.8.1 -> 1.8.2] + https://developer.android.com/jetpack/androidx/releases/activity#1.8.2 + - androidx.annotation:annotation [1.7.0 -> 1.7.1] + https://developer.android.com/jetpack/androidx/releases/annotation#1.7.1 + - androidx.lifecycle:lifecycle-common-java8 [2.6.2 -> 2.7.0] + https://developer.android.com/jetpack/androidx/releases/lifecycle#2.7.0 + - com.facebook.android:facebook-login [16.2.0 -> 16.3.0] + https://github.com/facebook/facebook-android-sdk + ## v2.9.0 * Change `pageview_id`/`visit_id` format * Add support for Edge integration and deprecated `Composer.accessToken` diff --git a/composer-c1x/build.gradle.kts b/composer-c1x/build.gradle.kts index 02a1a47..d7308ff 100644 --- a/composer-c1x/build.gradle.kts +++ b/composer-c1x/build.gradle.kts @@ -8,6 +8,9 @@ android { buildConfigField("String", "SDK_VERSION", """"$version"""") } namespace = "io.piano.android.composer.c1x" + buildFeatures { + buildConfig = true + } } dependencies { diff --git a/composer/build.gradle.kts b/composer/build.gradle.kts index 05749af..cb44860 100644 --- a/composer/build.gradle.kts +++ b/composer/build.gradle.kts @@ -9,6 +9,9 @@ android { buildConfigField("String", "SDK_VERSION", """"$version"""") } namespace = "io.piano.android.composer" + buildFeatures { + buildConfig = true + } } dependencies { diff --git a/composer/src/main/java/io/piano/android/composer/Composer.kt b/composer/src/main/java/io/piano/android/composer/Composer.kt index 5c37428..e9d30e8 100644 --- a/composer/src/main/java/io/piano/android/composer/Composer.kt +++ b/composer/src/main/java/io/piano/android/composer/Composer.kt @@ -115,7 +115,10 @@ class Composer internal constructor( * @return The instance of [Composer]. */ @Suppress("unused") // Public API. - fun userToken(userToken: String?) = apply { this.userToken = userToken } + fun userToken(userToken: String?) = apply { + this.userToken = userToken + edgeCookiesProvider.userToken(userToken) + } /** * Sets the Google Analytics client ID. diff --git a/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt b/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt index d44446d..0122349 100644 --- a/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt +++ b/composer/src/main/java/io/piano/android/composer/EdgeCookiesProvider.kt @@ -16,12 +16,14 @@ internal class EdgeCookiesProvider( private val pcusAdapter: JsonAdapter, ) { private var lastUserSegmentsContainer: UserSegmentsContainer? = null + private var lastUserToken: String? = null val edgeCookies: EdgeCookies get() = EdgeCookies( prefsStorage.tpAccessCookie, prefsStorage.tpBrowserCookie, prefsStorage.xbuilderBrowserCookie, + lastUserToken.orEmpty(), buildPprvValue(), lastUserSegmentsContainer?.let { pcusAdapter.toJson(PcusContainer(it)) }?.toBase64String().orEmpty() ) @@ -30,6 +32,10 @@ internal class EdgeCookiesProvider( lastUserSegmentsContainer = userSegmentsContainer } + internal fun userToken(userToken: String?) { + lastUserToken = userToken + } + private fun buildPprvValue() = pianoConsents?.let { pprvAdapter.toJson( PprvContainer( diff --git a/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt b/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt index 54e457f..5fd44db 100644 --- a/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt +++ b/composer/src/main/java/io/piano/android/composer/model/EdgeCookies.kt @@ -17,6 +17,7 @@ class EdgeCookies( val tac: String, val tbc: String, val xbc: String, + val userToken: String, val pprv: String, val pcus: String, ) { @@ -28,6 +29,7 @@ class EdgeCookies( "__tac" to tac, "__tbc" to tbc, "xbc" to xbc, + "__utp" to userToken, "_pprv" to pprv, "_pcus" to pcus ).filterValues { it.isNotEmpty() } diff --git a/composer/src/test/java/io/piano/android/composer/ComposerTest.kt b/composer/src/test/java/io/piano/android/composer/ComposerTest.kt index f56bdfa..5562e4c 100644 --- a/composer/src/test/java/io/piano/android/composer/ComposerTest.kt +++ b/composer/src/test/java/io/piano/android/composer/ComposerTest.kt @@ -62,7 +62,14 @@ class ComposerTest { ) } private val edgeCookiesProvider: EdgeCookiesProvider = mock { - on { edgeCookies } doReturn EdgeCookies(DUMMY_STRING, DUMMY_STRING2, DUMMY_STRING, DUMMY_STRING2, DUMMY_STRING) + on { edgeCookies } doReturn EdgeCookies( + DUMMY_STRING, + DUMMY_STRING2, + DUMMY_STRING, + DUMMY_STRING2, + DUMMY_STRING, + DUMMY_STRING2 + ) } private val pianoConsents: PianoConsents = mock { on { consents } doReturn emptyMap() diff --git a/gradle.properties b/gradle.properties index 0283b59..172ccc3 100755 --- a/gradle.properties +++ b/gradle.properties @@ -17,7 +17,7 @@ # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects # org.gradle.parallel=true -VERSION_NAME=2.9.0 +VERSION_NAME=2.9.1-SNAPSHOT GROUP=io.piano.android POM_DESCRIPTION=Piano SDK for Android @@ -39,5 +39,4 @@ android.useAndroidX=true android.enableJetifier=false android.nonTransitiveRClass=true android.nonFinalResIds=false -android.defaults.buildfeatures.buildconfig=true org.gradle.configuration-cache=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9ead9ec..2401e17 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,25 +1,25 @@ [versions] # Plugins kotlin = "1.8.22" -android = "8.1.4" +android = "8.2.1" dokka = "1.8.20" -versionUpdater = "0.49.0" -ktlint = "11.6.1" -mavenRelease = "0.25.3" +versionUpdater = "0.50.0" +ktlint = "12.1.0" +mavenRelease = "0.27.0" moshiIR = "0.22.1" # AndroidX libraries compatLibrary = "1.6.1" -androidxActivity = "1.8.1" -annotationsLibrary = "1.7.0" +androidxActivity = "1.8.2" +annotationsLibrary = "1.7.1" fragmentLibrary = "1.6.2" -materialLibrary = "1.10.0" -lifecycleLibrary = "2.6.2" +materialLibrary = "1.11.0" +lifecycleLibrary = "2.7.0" prefsLibrary = "1.2.1" multidex = "2.0.1" # Third party Libraries -facebookLogin = "16.2.0" +facebookLogin = "16.3.0" googlePlayServices = "20.7.0" retrofit = "2.9.0" okhttp = "4.12.0" diff --git a/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt b/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt index 545f055..3956976 100644 --- a/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt +++ b/gradle/plugins/src/main/kotlin/io/piano/android/ktlint/KtlintConfigPlugin.kt @@ -11,7 +11,7 @@ class KtlintConfigPlugin : Plugin { apply() if (this != rootProject) { extensions.configure(KtlintExtension::class.java) { - version.set("1.0.1") + version.set("1.1.1") android.set(true) } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 44f9869..2cc299f 100755 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip diff --git a/id/id/build.gradle.kts b/id/id/build.gradle.kts index 15f4292..dd8fc93 100644 --- a/id/id/build.gradle.kts +++ b/id/id/build.gradle.kts @@ -13,6 +13,7 @@ android { unitTests.isIncludeAndroidResources = true } buildFeatures { + buildConfig = true viewBinding = true } namespace = "io.piano.android.id" diff --git a/id/id/src/main/java/io/piano/android/id/models/CustomField.kt b/id/id/src/main/java/io/piano/android/id/models/CustomField.kt index aeec323..a50179c 100644 --- a/id/id/src/main/java/io/piano/android/id/models/CustomField.kt +++ b/id/id/src/main/java/io/piano/android/id/models/CustomField.kt @@ -8,7 +8,7 @@ import java.util.Date class CustomField( @Json(name = "field_name") val fieldName: String, - val value: String, + val value: String?, val created: Date? = null, @Json(name = "email_creator") val emailCreator: String? = null, diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 021e9fe..c4d80aa 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -15,6 +15,8 @@ val aid: String = pianoProperties.getProperty("io.piano.aid") ?: throw IllegalArgumentException("You missed 'io.piano.aid' in piano.properties") val endpoint: String = pianoProperties.getProperty("io.piano.endpoint", "") val qaPrefix: String = pianoProperties.getProperty("io.piano.qaPrefix", "") +val siteUrl: String = pianoProperties.getProperty("siteUrl", "https://example.com/") +val edgeUrl: String = pianoProperties.getProperty("edgeUrl", "https://example.com/") val siteId: String = pianoProperties.getProperty("cxenseSiteid", "1111111111111111111") val fbAppId: String = pianoProperties.getProperty("facebookAppId", "1111111111111111") val fbAppToken: String = pianoProperties.getProperty("facebookClientToken", "00000000000000000000000000000000") @@ -28,6 +30,8 @@ android { buildConfigField("String", "CX_SITE_ID", """"$siteId"""") buildConfigField("String", "PIANO_ENDPOINT", """"$endpoint"""") buildConfigField("String", "PIANO_QA_PREFIX", """"$qaPrefix"""") + buildConfigField("String", "SITE_URL", """"$siteUrl"""") + buildConfigField("String", "EDGE_URL", """"$edgeUrl"""") multiDexEnabled = true manifestPlaceholders += mapOf( @@ -52,6 +56,7 @@ android { } } buildFeatures { + buildConfig = true viewBinding = true } lint { diff --git a/sample/src/main/java/io/piano/sample/ComposerActivity.kt b/sample/src/main/java/io/piano/sample/ComposerActivity.kt index 83bbe19..ce67592 100644 --- a/sample/src/main/java/io/piano/sample/ComposerActivity.kt +++ b/sample/src/main/java/io/piano/sample/ComposerActivity.kt @@ -73,7 +73,7 @@ class ComposerActivity : AppCompatActivity() { .request("requestKey", "requstValue3") val request = ExperienceRequest.Builder() - .url("https://example.com") + .url(BuildConfig.SITE_URL) .referer("https://google.com") .tag("tag") .debug(true) diff --git a/sample/src/main/java/io/piano/sample/MainActivity.kt b/sample/src/main/java/io/piano/sample/MainActivity.kt index 49c2077..87f9592 100644 --- a/sample/src/main/java/io/piano/sample/MainActivity.kt +++ b/sample/src/main/java/io/piano/sample/MainActivity.kt @@ -6,6 +6,9 @@ import android.webkit.CookieManager import androidx.appcompat.app.AppCompatActivity import com.google.android.material.snackbar.Snackbar import io.piano.android.composer.Composer +import io.piano.android.composer.listeners.EventsListener +import io.piano.android.composer.model.EdgeResult +import io.piano.android.composer.model.ExperienceRequest import io.piano.android.id.PianoId import io.piano.android.id.PianoId.Companion.isPianoIdUri import io.piano.android.id.PianoId.Companion.parsePianoIdToken @@ -15,11 +18,21 @@ import io.piano.android.id.models.PianoIdAuthSuccessResult import io.piano.android.id.models.PianoIdToken import io.piano.android.id.models.PianoUserInfo import io.piano.sample.databinding.ActivityMainBinding +import okhttp3.Call +import okhttp3.Callback +import okhttp3.Cookie +import okhttp3.FormBody +import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response import timber.log.Timber +import java.io.IOException class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private lateinit var prefsStorage: PrefsStorage + private lateinit var okHttpClient: OkHttpClient private val isDeepLink: Boolean get() { @@ -47,6 +60,7 @@ class MainActivity : AppCompatActivity() { Timber.d("Is this a new user registered? %b", r.isNewUser) setAccessToken(r.token) } + is PianoIdAuthFailureResult -> showError(r.exception) } } @@ -54,7 +68,9 @@ class MainActivity : AppCompatActivity() { @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - prefsStorage = SimpleDependenciesProvider.getInstance(this).prefsStorage + val dependenciesProvider = SimpleDependenciesProvider.getInstance(this) + prefsStorage = dependenciesProvider.prefsStorage + okHttpClient = dependenciesProvider.okHttpClient binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) if (isDeepLink) { @@ -92,6 +108,57 @@ class MainActivity : AppCompatActivity() { ) ) } + buttonComposerEdge.setOnClickListener { + val edgeCookies = Composer.getInstance().edgeCookies.toMap().map { "${it.key}=${it.value}" } + val edgeBody = FormBody.Builder() + .add("url", BuildConfig.SITE_URL) + .add("inflate", "true") + .add("debug", "true") + .add("customVariables", "{\"variable1\":\"value1\"}") + .add("contentAuthor", "JohnDoe") + .add("contentSection", "sport") + .add("contentCreated", "2024-01-12T08:00:00") + .add("tags", "premium") + .build() + val edgeRequest = Request.Builder() + .url(BuildConfig.EDGE_URL) + .apply { + edgeCookies.forEach { addHeader("Cookie", it) } + } + .post(edgeBody) + .build() + okHttpClient.newCall(edgeRequest).enqueue(object : Callback { + override fun onFailure(call: Call, e: IOException) { + showError(e) + } + + override fun onResponse(call: Call, response: Response) { + val cookies = Cookie.parseAll(BuildConfig.SITE_URL.toHttpUrl(), response.headers) + val request = ExperienceRequest.Builder() + .url(BuildConfig.SITE_URL) + .edgeResult( + EdgeResult( + cookies.getCookieValue("__tbc"), + cookies.getCookieValue("xbc"), + cookies.getCookieValue("_pcer") + ) + ) + .debug(true) + .build() + val eventsListener: EventsListener = { + val eventTypes = it.joinToString(prefix = "[", postfix = "]") { event -> + event.eventData.toString() + } + val message = "Got events: $eventTypes" + Timber.d(message) + showMessage(message) + } + Composer.getInstance().getExperience(request, eventsListener) { + showError(it) + } + } + }) + } buttonComposerClearStorage.setOnClickListener { Composer.getInstance().clearStoredData() } @@ -103,6 +170,8 @@ class MainActivity : AppCompatActivity() { } } + private fun List.getCookieValue(name: String): String = firstOrNull { it.name == name }?.value.orEmpty() + private fun signOut() { val token = prefsStorage.pianoIdToken setAccessToken(null) diff --git a/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt b/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt index d768099..2a942eb 100644 --- a/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt +++ b/sample/src/main/java/io/piano/sample/SimpleDependenciesProvider.kt @@ -3,11 +3,18 @@ package io.piano.sample import android.content.Context import com.squareup.moshi.Moshi import io.piano.android.id.PianoIdJsonAdapterFactory +import okhttp3.OkHttpClient +import okhttp3.logging.HttpLoggingInterceptor class SimpleDependenciesProvider private constructor(context: Context) { val appContext: Context = context.applicationContext val moshi: Moshi = Moshi.Builder().add(PianoIdJsonAdapterFactory()).build() val prefsStorage: PrefsStorage = PrefsStorage(appContext, moshi) + val okHttpClient: OkHttpClient = OkHttpClient.Builder() + .addInterceptor( + HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY) + ) + .build() companion object { @JvmStatic diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index aea6c5c..0d54e4b 100755 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -50,6 +50,12 @@ android:layout_height="wrap_content" android:text="Composer screen with scroll depth" /> +