From 6f9c39138231ba53ac5f7e696b7816925df0abc0 Mon Sep 17 00:00:00 2001 From: Denis Chilik Date: Wed, 25 Feb 2026 12:32:43 -0500 Subject: [PATCH 1/2] feat: add sharingFilterForPartners support to Android AppsFlyer kit --- .../kotlin/com/mparticle/kits/AppsFlyerKit.kt | 28 ++++++++++ .../com/mparticle/kits/AppsflyerKitTests.kt | 51 +++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt b/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt index e49bba7..c1cb1cd 100644 --- a/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt +++ b/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt @@ -62,6 +62,7 @@ class AppsFlyerKit : MParticle.getInstance()?.environment == MParticle.Environment.Development, ) settings[DEV_KEY]?.let { AppsFlyerLib.getInstance().init(it, this, context) } + applySharingFilterForPartners(setting?.get(SHARING_FILTER_FOR_PARTNERS)) val userConsentState = currentUser?.consentState setConsent(userConsentState) AppsFlyerLib.getInstance().start(context.applicationContext) @@ -575,6 +576,32 @@ class AppsFlyerKit : override fun onActivityDestroyed(activity: Activity): List = emptyList() + override fun onSettingsUpdated(settings: Map) { + settings[SHARING_FILTER_FOR_PARTNERS]?.let { applySharingFilterForPartners(it) } + } + + private fun applySharingFilterForPartners(jsonValue: String?) { + val partners = parseSharingFilterForPartners(jsonValue) + if (!partners.isNullOrEmpty()) { + instance.setSharingFilterForPartners(*partners.toTypedArray()) + } + } + + private fun parseSharingFilterForPartners(json: String?): List? { + if (json.isNullOrEmpty()) return null + return try { + val jsonWithFormat = json.replace("\\", "") + val array = JSONArray(jsonWithFormat) + (0 until array.length()).map { array.getString(it) } + } catch (e: JSONException) { + Logger.warning( + "AppsFlyer kit: failed to parse sharingFilterForPartners, " + + "consent filter for partners will not be applied. Error: ${e.message}", + ) + null + } + } + companion object { const val DEV_KEY = "devKey" const val APPSFLYERID_INTEGRATION_KEY = "appsflyer_id_integration_setting" @@ -601,6 +628,7 @@ class AppsFlyerKit : } } + private const val SHARING_FILTER_FOR_PARTNERS = "sharingFilterForPartners" private const val CONSENT_MAPPING = "consentMapping" @Suppress("ktlint:standard:property-naming") diff --git a/src/test/kotlin/com/mparticle/kits/AppsflyerKitTests.kt b/src/test/kotlin/com/mparticle/kits/AppsflyerKitTests.kt index 6c7201f..f83866d 100644 --- a/src/test/kotlin/com/mparticle/kits/AppsflyerKitTests.kt +++ b/src/test/kotlin/com/mparticle/kits/AppsflyerKitTests.kt @@ -76,6 +76,57 @@ class AppsflyerKitTests { Assert.assertTrue(name.isNotEmpty()) } + @Test + @Throws(Exception::class) + fun testParseSharingFilterForPartners_returnsListForValidJson() { + val method = + AppsFlyerKit::class.java.getDeclaredMethod( + "parseSharingFilterForPartners", + String::class.java, + ) + method.isAccessible = true + val result = method.invoke(kit, """["partner_1", "partner_2"]""") + Assert.assertEquals(listOf("partner_1", "partner_2"), result) + } + + @Test + @Throws(Exception::class) + fun testParseSharingFilterForPartners_returnsNullForEmptyInput() { + val method = + AppsFlyerKit::class.java.getDeclaredMethod( + "parseSharingFilterForPartners", + String::class.java, + ) + method.isAccessible = true + Assert.assertNull(method.invoke(kit, "")) + Assert.assertNull(method.invoke(kit, null)) + } + + @Test + @Throws(Exception::class) + fun testParseSharingFilterForPartners_returnsNullForInvalidJson() { + val method = + AppsFlyerKit::class.java.getDeclaredMethod( + "parseSharingFilterForPartners", + String::class.java, + ) + method.isAccessible = true + Assert.assertNull(method.invoke(kit, "not a json array")) + } + + @Test + @Throws(Exception::class) + fun testParseSharingFilterForPartners_stripsBackslashes() { + val method = + AppsFlyerKit::class.java.getDeclaredMethod( + "parseSharingFilterForPartners", + String::class.java, + ) + method.isAccessible = true + val result = method.invoke(kit, """[\"test_1\", \"test_2\"]""") + Assert.assertEquals(listOf("test_1", "test_2"), result) + } + /** * Kit *should* throw an exception when they're initialized with the wrong settings. * From c94f3f33474e981906433e8de4567821727b1016 Mon Sep 17 00:00:00 2001 From: Denis Chilik Date: Thu, 26 Feb 2026 10:04:02 -0500 Subject: [PATCH 2/2] Address PR comments --- src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt b/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt index c1cb1cd..f0b6d0c 100644 --- a/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt +++ b/src/main/kotlin/com/mparticle/kits/AppsFlyerKit.kt @@ -62,7 +62,9 @@ class AppsFlyerKit : MParticle.getInstance()?.environment == MParticle.Environment.Development, ) settings[DEV_KEY]?.let { AppsFlyerLib.getInstance().init(it, this, context) } - applySharingFilterForPartners(setting?.get(SHARING_FILTER_FOR_PARTNERS)) + setting?.get(SHARING_FILTER_FOR_PARTNERS)?.let { + applySharingFilterForPartners(it) + } val userConsentState = currentUser?.consentState setConsent(userConsentState) AppsFlyerLib.getInstance().start(context.applicationContext) @@ -580,7 +582,7 @@ class AppsFlyerKit : settings[SHARING_FILTER_FOR_PARTNERS]?.let { applySharingFilterForPartners(it) } } - private fun applySharingFilterForPartners(jsonValue: String?) { + private fun applySharingFilterForPartners(jsonValue: String) { val partners = parseSharingFilterForPartners(jsonValue) if (!partners.isNullOrEmpty()) { instance.setSharingFilterForPartners(*partners.toTypedArray()) @@ -592,7 +594,7 @@ class AppsFlyerKit : return try { val jsonWithFormat = json.replace("\\", "") val array = JSONArray(jsonWithFormat) - (0 until array.length()).map { array.getString(it) } + List(array.length()) { i -> array.getString(i) } } catch (e: JSONException) { Logger.warning( "AppsFlyer kit: failed to parse sharingFilterForPartners, " +