chore: merge main into workstation/6.0-Release#734
Conversation
## [5.78.4](v5.78.3...v5.78.4) (2026-03-23) ### Updates & Maintenance * Update submodules ([08dab75](08dab75))
## [5.78.5](v5.78.4...v5.78.5) (2026-03-25) ### Updates & Maintenance * Update submodules ([86d8d97](86d8d97))
* fix: increase MPLatch timeout from 5s to 30s The 5-second timeout is too short for WebView JS bridge tests running on newer GitHub Actions runner images (ubuntu24/20260309.50+). The MParticleJSInterfaceITest tests consistently fail because JS execution in the emulator WebView doesn't complete within 5 seconds on these environments. Increasing to 30 seconds provides sufficient margin while still catching genuine hangs via the workflow-level timeout-minutes: 15. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use explicit 30s timeout in JS bridge tests only Instead of increasing the global MPLatch timeout (used by 20+ test files), use an explicit 30-second await in MParticleJSInterfaceITest only. WebView JS execution needs more time on newer CI runner images, but other tests don't need the longer timeout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* TRIAGE-608: Add max persistence age override option * TRIAGE-608: Update throttl ts on success + tests * TRIAGE-608: Make properties @VisibleForTesting * TRIAGE-608: Fix retry-on-failure throttle logic
* feat: add customBaseURL CNAME support to NetworkOptions Adds NetworkOptions.Builder.setCustomBaseURL(String) which routes all mParticle endpoint traffic (config, events, identity, alias, audience) through a single HTTPS CNAME host. When set, customBaseURL takes priority over individual domain mappings and rewrites paths to match CDN routing: /config/v4/, /nativeevents/v2/, /identity/v1/, /nativeevents/v1/identity/, /nativeevents/v1/<key>/audience. Also adds R8 keep rules for MParticle$Internal and ConfigManager.getNetworkOptions() so kits can read customBaseURL after minification. The Rokt kit reads NetworkOptions.customBaseURL and forwards it to the Rokt SDK: mparticle-integrations/mparticle-android-integration-rokt#143 Mirrors iOS work from mparticle-apple-sdk#760. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: persist customBaseURL across NetworkOptions JSON round-trip NetworkOptions.toJson() and withNetworkOptions(String) did not include customBaseURL, so any value was silently dropped when UploadSettings serialized NetworkOptions to the upload database. Events and alias uploads read back NetworkOptions without customBaseURL and routed to the default mParticle endpoints instead of the partner CNAME. Also: - Extract the customBaseURL/DomainMapping host-resolution branch out of getUrl() into a private resolveHost() helper plus a small ResolvedHost value type, lowering getUrl()'s cyclomatic complexity. - Switch java.net.URL / java.net.MalformedURLException to imports. - Add two androidTest cases covering the round-trip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(android-core): cover custom base URL upload storage --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Thomson Thomas <thomson.thomas@rokt.com>
## [5.79.0](v5.78.5...v5.79.0) (2026-05-14) ### Features * add customBaseURL CNAME support to NetworkOptions ([#701](#701)) ([5285149](5285149)), closes [mparticle-apple-sdk#760](mParticle/mparticle-apple-sdk#760) * Add max persistence age override option [TRIAGE-608] ([#699](#699)) ([ca88322](ca88322)) ### Bug Fixes * increase MPLatch timeout from 5s to 30s ([#695](#695)) ([20f723f](20f723f)) ### Updates & Maintenance * Update submodules ([59a4a9a](59a4a9a))
Bumps [trunk-io/trunk-action](https://github.com/trunk-io/trunk-action) from 1.2.4 to 1.3.1. - [Release notes](https://github.com/trunk-io/trunk-action/releases) - [Commits](trunk-io/trunk-action@75699af...04ba50e) --- updated-dependencies: - dependency-name: trunk-io/trunk-action dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: James Newman <james.newman@rokt.com>
…714) The isolated urbanairship-kit lint/test steps in daily.yml and the kit-compatibility test in pull-request.yml run `./gradlew` from inside the kit dir without `-Pversion=...`. The kit's standalone build.gradle defaults `project.version = '+'`, so its `com.mparticle:android-kit-plugin` dependency resolves to the highest version on Maven Central — now `6.0.0-rc.1` (published 2026-05-22), which renamed/removed kit-base symbols and broke the kit's compile. Mirror the pattern already used in the Sonatype Release job: extract the SDK version via `./gradlew -q properties` and pass it as `-Pversion=...` to every standalone kit invocation, so it resolves the freshly-published mavenLocal artifact instead of the RC. Affected steps: - lint-checks → Run Isolated Kit Lint (urbanairship-kit) - kotlin-lint-checks → Run Isolated Kit Kotlin Lint (urbanairship-kit) - update-kits → Test Isolated Kits (urbanairship-kit) - kit-compatibility-test → Run Isolated Kit Compatibility Tests (urbanairship-kit) The companion defensive fix in mparticle-android-integration-urbanairship pins the kit's standalone `project.version` to `[5.0,6.0)`. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## [5.79.1](v5.79.0...v5.79.1) (2026-05-27) ### Bug Fixes * **ci:** pin isolated-kit gradle version to prevent 6.0.0-rc.1 pull ([#714](#714)) ([eff10ea](eff10ea)) ### Updates & Maintenance * bump trunk-io/trunk-action from 1.2.4 to 1.3.1 ([#705](#705)) ([f4ceca7](f4ceca7)) * Update submodules ([e435979](e435979))
These checks have been failing on nearly every recent PR. The cross-platform tests are known broken, and the semantic PR title / branch name checks are no longer enforced. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](actions/checkout@v6.0.2...v6.0.3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Enables Inspire-style flows where consent is collected before MPID changes at checkout, so kit forwarding rules and uploads keep the correct consent state.
## [5.80.0](v5.79.2...v5.80.0) (2026-06-25) ### Features * add device-based consent to override MPID-scoped consent ([#726](#726)) ([e92d352](e92d352))
…-6.0-release # Conflicts: # .github/workflows/cross-platform-tests.yml # .github/workflows/daily.yml # .github/workflows/pull-request.yml # .github/workflows/release.yml # CHANGELOG.md # android-core/src/main/java/com/mparticle/MParticleOptions.java # android-core/src/main/java/com/mparticle/networking/MParticleBaseClientImpl.java # android-core/src/test/kotlin/com/mparticle/external/ApiVisibilityTest.kt # build.gradle # kits/adjust-kit # kits/adobe-kit # kits/adobemedia-kit # kits/appboy-kit # kits/appsflyer-kit # kits/apptentive-kit # kits/apptimize-kit # kits/apteligent-kit # kits/branch-kit # kits/button-kit # kits/clevertap-kit # kits/comscore-kit # kits/flurry-kit # kits/foresee-kit # kits/googleanalyticsfirebase-kit # kits/googleanalyticsfirebasega4-kit # kits/iterable-kit # kits/kochava-kit # kits/leanplum-kit # kits/localytics-kit # kits/onetrust-kit # kits/optimizely-kit # kits/pilgrim-kit # kits/radar-kit # kits/responsys-kit # kits/revealmobile-kit # kits/rokt-kit # kits/singular-kit # kits/skyhook-kit # kits/taplytics-kit # kits/tune-kit # kits/urbanairship-kit # kits/wootric-kit
PR SummaryMedium Risk Overview Core behavior from CI / repo hygiene: Deletes Tests & docs: New/expanded instrumented and unit coverage for persistence deletes and consent; WebView JS tests use 30s latch timeouts; Reviewed by Cursor Bugbot for commit 0c13ba1. Bugbot is set up for automated code reviews on this repo. Configure here. |
BrandonStalnaker
left a comment
There was a problem hiding this comment.
There's a few documentation related nits that you might want to fix or do a separate PR for but the actual code looks good. At lest in relation to the changes I fully understand.
|
|
||
| - add device-based consent to override MPID-scoped consent ([#726](https://github.com/mParticle/mparticle-android-sdk/issues/726)) ([e92d352](https://github.com/mParticle/mparticle-android-sdk/commit/e92d3522a350be90a1f15eb3b81d5e6f089f1aed)) | ||
|
|
||
| ## Unreleased |
| @@ -1,3 +1,3 @@ | |||
| <!-- markdownlint-disable MD024 MD041 --> | |||
|
|
|||
| ## [Unreleased] | |||
| ```groovy | ||
| dependencies { | ||
| implementation 'com.mparticle:android-core:5.78.2' | ||
| implementation 'com.mparticle:android-core:5.80.0' |
There was a problem hiding this comment.
For the 6.0 branch shouldn't this be something like 6.0.0-rc.1
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 #v5.0.0 | ||
| uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 #v5.0.0 |
There was a problem hiding this comment.
I think this is actually the sha for v6.0.3
…ore/merge-main-into-6.0-release
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d0df6b4. Configure here.
| mConfigManager.setDeviceConsentState(state); | ||
| } | ||
| ConsentState newState = getConsentState(mpid); | ||
| mKitManager.onConsentStateUpdated(oldState, newState, mpid); |
There was a problem hiding this comment.
MPID consent ignored with override
Medium Severity
When a device consent override is still stored but deviceBasedConsentEnabled is off, setConsentState updates MPID storage only. getEffectiveConsentState keeps returning the device override, so uploads, user-facing consent reads, and onConsentStateUpdated can see no change after an MPID consent update.
Reviewed by Cursor Bugbot for commit d0df6b4. Configure here.
|
* feat: migrate appsflyer-kit from submodule to regular directory (#650) * feat: migrate appsflyer-kit from submodule to regular directory * feat: relocate appsflyer-kit to kits/appsflyer/appsflyer-6 and update settings-kits.gradle * Add kit lint/ktlint to PR workflow; ignore appsflyer-6 in Trunk Made-with: Cursor * Fix Trunk ignore: use glob patterns for appsflyer-6 and gradlew Made-with: Cursor * feat: remove .gitignore * feat: Braze 38 Kit Migrate (#651) * feat: migrate appboy-kit from submodule to regular directory * feat: relocate appboy-kit to kits/braze/braze-38 and update settings-kits.gradle Made-with: Cursor * fix: add braze-38 to settings-kits.gradle (alphabetical order) Made-with: Cursor * feat: GA 23 Kit Migrate (#652) * feat: migrate googleanalyticsfirebase-kit from submodule to regular directory * feat: relocate googleanalyticsfirebase-kit to kits/ga/ga-23 and update settings-kits.gradle Made-with: Cursor * fix agent typo * add bracket * feat: GA4 23 Kit Migrate (#653) * feat: migrate googleanalyticsfirebasega4-kit from submodule to regular directory * feat: relocate googleanalyticsfirebasega4-kit to kits/ga4/ga4-23 and update settings-kits.gradle * fix typo * feat: Migrate Rokt kit (#659) * feat: migrate rokt-kit from submodule to regular directory * feat: relocate rokt-kit to kits/rokt/rokt * feat: add rokt to settings-kits.gradle, remove accidental kit adds Made-with: Cursor * feat: Kochava 5 Kit Migrate (#654) * feat: migrate kochava-kit from submodule to regular directory * feat: relocate kochava-kit to kits/kochava/kochava-5 and update settings-kits.gradle Made-with: Cursor * fix typo * feat: Migrate Adjust kit (#656) * feat: migrate adjust-kit from submodule to regular directory * feat: relocate adjust-kit to kits/adjust/adjust-5 * feat: add adjust-5 to settings-kits.gradle Made-with: Cursor * feat: Migrate Localytics kit (#661) * feat: migrate localytics-kit from submodule to regular directory * feat: relocate localytics-kit to kits/localytics/localytics-6 Made-with: Cursor * feat: update settings-kits.gradle for localytics-6 path Made-with: Cursor * feat: Split instrumented tests in CI for parallel execution (#662) * feat: split instrumented tests in CI for parallel execution - Split instrumented tests into 4 parallel jobs: core, kit-base, testutils, orchestrator - Reduced timeout from 30 to 20 min per job - Each job runs only its module for faster feedback - Add kit directories for isolated testing (adjust, googleanalyticsfirebase, kochava, localytics, rokt) - Replace 2 shard jobs with matrix strategy (shards 0-3) - Each shard runs ~25% of tests in parallel - Timeout 12 min per shard, fail-fast: false - extract common part in instrumented-tests.yml * chore: remove rokt-kit submodule (migrated to monorepo) Rokt kit is now in kits/rokt/rokt, no longer a submodule. Made-with: Cursor * fix: add explicit permissions to instrumented-tests workflow for Checkov CKV2_GHA_1 Made-with: Cursor * fix: remove actions: write permission from instrumented-tests workflow Made-with: Cursor * feat: Leanplum 7 Kit Migrate (#655) * feat: migrate leanplum-kit from submodule to regular directory feat: relocate leanplum-kit to kits/leanplum/leanplum-7 and update settings-kits.gradle fix: replace exposed Google API key with placeholder in leanplum example Made-with: Cursor * chore: update .mobsf to suppress MobSF false positives - Add ignore-paths for src/test, example apps - Add webview_javascript_interface ignore (intentional JS bridge for WebView SDK) Made-with: Cursor * fix security issues * feat: Migrate CleverTap kit (#660) * feat: migrate clevertap-kit from submodule to regular directory * feat: relocate clevertap-kit to kits/clevertap/clevertap-7 Made-with: Cursor * feat: update settings-kits.gradle for clevertap-7 kit path Made-with: Cursor * feat: Migrate Apptentive kit (#657) feat: migrate apptentive-kit from submodule to regular directory feat: relocate apptentive-kit to kits/apptentive/apptentive-6 feat: add apptentive-6 to settings-kits.gradle * feat: Migrate Apptimize kit (#658) * feat: migrate apptimize-kit from submodule to regular directory * feat: relocate apptimize-kit to kits/apptimize/apptimize-3 * feat: add apptimize-3 to settings-kits.gradle Made-with: Cursor * feat: Migrate Adobe Media 5 kit (#671) * feat: migrate adobemedia-kit from submodule to regular directory * feat: relocate adobemedia-kit to kits/adobemedia/adobemedia-5 Made-with: Cursor * feat: add adobemedia-5 to settings-kits.gradle Made-with: Cursor * feat: Migrate Adobe 5 kit (#670) * feat: migrate adobe-kit from submodule to regular directory * feat: relocate adobe-kit to kits/adobe/adobe-5 Made-with: Cursor * feat: add adobe-5 to settings-kits.gradle Made-with: Cursor * feat: Migrate Iterable 3 kit (#669) * feat: migrate iterable-kit from submodule to regular directory * feat: relocate iterable-kit to kits/iterable/iterable-3 Made-with: Cursor * feat: add iterable-3 to settings-kits.gradle Made-with: Cursor * feat: Migrate ComScore 6 kit (#668) * feat: migrate comscore-kit from submodule to regular directory * feat: relocate comscore-kit to kits/comscore/comscore-6 Made-with: Cursor * feat: add comscore-6 to settings-kits.gradle Made-with: Cursor * feat: Migrate Radar kit (#665) * feat: migrate radar-kit from submodule to regular directory * feat: relocate radar-kit to kits/radar/radar-3 Made-with: Cursor * feat: update settings-kits.gradle for radar-3 Made-with: Cursor * feat: Migrate Singular 12 kit (#667) * feat: migrate singular-kit from submodule to regular directory * feat: relocate singular-kit to kits/singular/singular-12 Made-with: Cursor * feat: add singular-12 to settings-kits.gradle Made-with: Cursor * feat: Migrate Optimizely kit (#664) * feat: migrate optimizely-kit from submodule to regular directory * feat: relocate optimizely-kit to kits/optimizely/optimizely-3 Made-with: Cursor * feat: update settings-kits.gradle for optimizely-3 Made-with: Cursor * feat: Migrate Branch 5 kit (#666) * feat: migrate branch-kit from submodule to regular directory * feat: relocate branch-kit to kits/branch/branch-5 * feat: add branch-5 to settings-kits.gradle Made-with: Cursor * fix: remove old branch-kit path from settings-kits.gradle Made-with: Cursor * fix: resolve MobSF/mobsfscan security findings - Remove sensitive value from CustomDataParser log (android_kotlin_logging) - Add SampleApplication to ignore-paths and manifest rules to .mobsf (assetlinks, task hijacking for Branch sample app) Made-with: Cursor * Add nosemgrep to SampleApplication gradlew to fix Semgrep CI Made-with: Cursor * feat: Migrate Urban Airship kit (#673) * feat: migrate urbanairship-kit from submodule to regular directory * feat: relocate urbanairship-kit to kits/urbanairship/urbanairship-20 Made-with: Cursor * feat: add urbanairship-20 to settings-kits.gradle (commented, Kotlin 2.2.x standalone) Made-with: Cursor * fix: update CI and ONBOARDING for urbanairship standalone path (kits/urbanairship/urbanairship-20) Made-with: Cursor * Add nosemgrep to urbanairship PushSample gradlew to fix Semgrep CI Made-with: Cursor * Fix MobSF findings: remove sensitive logging, use SecureRandom in tests Made-with: Cursor * feat: Migrate OneTrust kit (#672) * feat: migrate onetrust-kit from submodule to regular directory * feat: relocate onetrust-kit to kits/onetrust/onetrust-5 Made-with: Cursor * feat: add onetrust-5 to settings-kits.gradle Made-with: Cursor * fix: use version 202411 from OneTrust SDK dependency (com.onetrust.cmp:native-sdk:202411.2.0.0) Made-with: Cursor * fix: OneTrust kit uses path without version (kits/onetrust/onetrust) Made-with: Cursor * Add nosemgrep to onetrust gradlew to fix Semgrep CI Made-with: Cursor * disable AVD cache because of the issues in CI * chore: Remove submodules, migrate kits to monorepo (#674) chore: remove submodules, migrate to monorepo - Remove .gitmodules and 12 kit submodules (apteligent, button, example, flurry, foresee, pilgrim, responsys, revealmobile, skyhook, taplytics, tune, wootric) - Update settings-kits.gradle to remove deleted kit references - Remove submodule steps from CI (pull-request.yml, release.yml, daily.yml) - Update ONBOARDING.md: kits are in monorepo, no submodule init needed - Update CONTRIBUTING.md: urbanairship path - Update urbanairship paths in release.yml and daily.yml Made-with: Cursor * chore: migrate to Rokt release process (#663) * chore: Migrate to Rokt release process * Fix trunk issues * Fixes for versions * Separate versions for coroutines * Change jvm version and fix lower case issue * Update KitPlugin.groovy * Pin actions versions up lint timeout --------- Signed-off-by: James Newman <james.newman@rokt.com> * fix: resolve trunk issues for all kits (#675) * fix: resolve trunk issues for adjust kit Made-with: Cursor * fix: resolve trunk issues for adobe kit Made-with: Cursor * fix: resolve trunk issues for adobemedia kit Made-with: Cursor * fix: resolve trunk issues for apptentive kit Made-with: Cursor * fix: resolve trunk issues for appsflyer kit Made-with: Cursor * fix: resolve trunk issues for apptimize kit Made-with: Cursor * fix: resolve trunk issues for branch kit Made-with: Cursor * fix: resolve trunk issues for braze kit Made-with: Cursor * fix: resolve trunk issues for clevertap kit Made-with: Cursor * fix: resolve trunk issues for comscore kit Made-with: Cursor * fix: resolve trunk issues for iterable kit Made-with: Cursor * fix: resolve trunk issues for ga kit Made-with: Cursor * fix: resolve trunk issues for ga4 kit Made-with: Cursor * fix: resolve trunk issues for kochava kit Made-with: Cursor * fix: resolve trunk issues for leanplum kit Made-with: Cursor * fix: resolve trunk issues for localytics kit Made-with: Cursor * fix: resolve trunk issues for onetrust kit Made-with: Cursor * fix: resolve trunk issues for optimizely kit Made-with: Cursor * fix: resolve trunk issues for radar kit Made-with: Cursor * fix: resolve trunk issues for rokt kit Made-with: Cursor * fix: resolve trunk issues for singular kit Made-with: Cursor * feat: Removing deprecations - Part 1 (#676) feat: Removing deprecations Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add Braze 39 kit (#677) * feat: copy Braze 39 kit from braze-38 * feat: update Braze 39 SDK to 39.0.0 * feat: Add Braze SDK 41 kit (braze-41) (#680) feat: add Braze SDK 41 kit (braze-41) - Add kits/braze/braze-41 with Braze android-sdk-ui:41.0.0 - Unique SonarQube project key and namespace (appboy41) - Maven artifact: com.mparticle:braze-41 - Include in settings-kits.gradle Made-with: Cursor * feat: Add Braze SDK 40 kit (braze-40) (#679) feat: add Braze SDK 40 kit (braze-40) - Add kits/braze/braze-40 with Braze android-sdk-ui:40.0.0 - Unique SonarQube project key and namespace (appboy40) - Maven artifact: com.mparticle:braze-40 - Include in settings-kits.gradle Made-with: Cursor Signed-off-by: denischilik <denis.chilik@rokt.com> * chore: Remove deprecated KitIntegration.getUserIdentities() (#681) * Remove deprecated KitIntegration.getUserIdentities() Made-with: Cursor * docs: Add CHANGELOG entry for KitIntegration.getUserIdentities removal Made-with: Cursor * test: Fix DataplanBlockingUserTests after KitIntegration.getUserIdentities removal Use getCurrentUser()?.userIdentities instead of removed kit-level API. Made-with: Cursor * chore: Remove deprecated KitIntegration.getAllUserAttributes() (#682) * chore: Remove deprecated KitIntegration.getAllUserAttributes() - Remove tests that only covered the removed API - Add CHANGELOG entry for custom kit migration path Made-with: Cursor * docs: Link CHANGELOG to PR 682 for getAllUserAttributes removal Made-with: Cursor * test: Fix DataplanBlockingUserTests after KitIntegration.getAllUserAttributes removal Use getCurrentUser().userAttributes instead of removed allUserAttributes property. Made-with: Cursor * feat: split LogoutListener from AttributeListener (#685) * feat: split LogoutListener from AttributeListener * feat: use local versions in ci during the checks * feat: inline user attribute removal in onRemoveUserAttribute (#687) * Add BaseAttributeListener for shared supportsAttributeLists() Introduce KitIntegration.BaseAttributeListener as the common superinterface for AttributeListener and UserAttributeListener. Document it as a temporary contract to enable incremental migration and smaller PRs. Made-with: Cursor * KitManagerImpl: call supportsAttributeLists once per provider Resolve via BaseAttributeListener before AttributeListener/UserAttributeListener branches in onUserAttributesReceived and setUserAttribute(list). Made-with: Cursor * Braze kit: delegate onRemoveUserAttribute to removeUserAttribute UserAttributeListener.onRemoveUserAttribute now forwards to the existing AttributeListener.removeUserAttribute implementation for braze-38 through braze-41. Made-with: Cursor * Move onRemoveUserAttribute to BaseAttributeListener Declare onRemoveUserAttribute on KitIntegration.BaseAttributeListener so AttributeListener and UserAttributeListener implementors must implement it. KitManagerImpl now dispatches removal once via BaseAttributeListener. AttributeListener-only kits delegate onRemoveUserAttribute to removeUserAttribute; AttributeListenerTestKit updated accordingly. Made-with: Cursor * Remove removeUserAttribute from AttributeListener; keep kit helpers Drop void removeUserAttribute(String) from KitIntegration.AttributeListener. Kits keep the same logic as private-style helpers (fun removeUserAttribute without override) and still satisfy BaseAttributeListener via onRemoveUserAttribute. AdobeKitBase implements onRemoveUserAttribute by delegating to removeUserAttribute. Made-with: Cursor * Inline remove-user-attribute logic into onRemoveUserAttribute Move kit-specific handling from removed helper methods into BaseAttributeListener.onRemoveUserAttribute implementations. Rename AttributeListenerTestKit callback to removeUserAttributeListener. Fix Braze custom-key branch for Kotlin smart-cast in Braze callback. Made-with: Cursor * chore: add no-op comments for Sonar empty-method rules Document intentional empty overrides in Adobe, AppsFlyer, Branch, Braze, and Kochava kits to satisfy SonarQube analysis. Made-with: Cursor * chore(kochava): Sonar no-op comment on onRemoveUserAttribute Made-with: Cursor * refactor(braze): use when in onRemoveUserAttribute success path Replace if/else chain with when for standard vs custom user attribute removal; behavior unchanged across braze 38-41 kits. Made-with: Cursor * feat: Migrate setUserAttribute (#689) * feat: align onSetUserAttribute with UserAttributeListener (nullable params, naming) - SingularKit: key/value/user naming, null checks for Java interop - AppsFlyerKit, Braze AppboyKit: consistent UserAttributeListener overrides Made-with: Cursor * feat: move onSetUserAttribute to BaseAttributeListener - KitIntegration: declare onSetUserAttribute on BaseAttributeListener; remove from UserAttributeListener - KitManagerImpl: dispatch scalar and CSV list paths via BaseAttributeListener; avoid double calls for dual-interface kits - AttributeListener-only kits: delegate onSetUserAttribute to setUserAttribute - AttributeListenerTestKit: implement onSetUserAttribute Made-with: Cursor * Remove setUserAttribute from AttributeListener; route via onSetUserAttribute - Drop setUserAttribute from KitIntegration.AttributeListener; kits keep setUserAttribute as a regular method (no override). - KitManagerImpl: use BaseAttributeListener.onSetUserAttribute for scalar and joined list paths; prefer UserAttributeListener when both interfaces apply. - AttributeListenerTestKit: rename callback to setUserAttributeCallback; update DataplanBlockingUserTests. Made-with: Cursor * Inline user attribute handling in onSetUserAttribute; remove kit setUserAttribute - Move scalar attribute logic from removed setUserAttribute helpers into onSetUserAttribute (or private helpers shared with setAllUserAttributes). - Braze: applyScalarUserAttribute for onSet + initial sync; update unit tests to call onSetUserAttribute with a mocked FilteredMParticleUser. - AttributeListenerTestKit: inline callback/onAttributeReceived in onSetUserAttribute. Made-with: Cursor * KitManagerImpl: restore AttributeListener before UserAttributeListener for list attrs Re-run both branches when a kit implements both interfaces; UserAttributeListener join path calls UserAttributeListener.onSetUserAttribute again. Made-with: Cursor * Braze kit: extract scalar user attribute branches into helpers Split applyScalarUserAttribute into applyScalarUserAttributeOnUser plus focused helpers for age, email/push subscribe, gender, subscription groups, and unmapped custom keys (braze-38 through braze-41). Made-with: Cursor * KitManagerImplTest: verify onSetUserAttribute for list-as-CSV path AttributeListener no longer has setUserAttribute; assert BaseAttributeListener onSetUserAttribute with joined value and FilteredMParticleUser. Made-with: Cursor * KitManagerImplTest: expect null FilteredMParticleUser in list CSV verify FilteredMParticleUser.getInstance returns null in JVM unit tests; Mockito any(Class) does not match null. Use isNull() for the third onSetUserAttribute arg. Made-with: Cursor * Align onSetUserAttribute Kotlin overrides with nullable key and value - Use String? and Any? for parameters matching Java Object/null call paths - Add early returns when key or value is null where needed - CleverTap: rename parameters to key/value; use mappedKey/mappedValue for mutations Made-with: Cursor * Use nullable FilteredMParticleUser in onSetUserAttribute overrides Third parameter is user: FilteredMParticleUser? to match KitManagerImpl and FilteredMParticleUser.getInstance. GA/GA4 use parameter name user. Made-with: Cursor * feat: move onSetUserAttributeList to BaseAttributeListener (#690) * Delegate onSetUserAttributeList to setUserAttributeList (dual-interface kits) Braze, AppsFlyer, and Singular implement both AttributeListener and UserAttributeListener; wire empty onSetUserAttributeList to existing setUserAttributeList behavior. Made-with: Cursor * Move onSetUserAttributeList to BaseAttributeListener - Declare onSetUserAttributeList on BaseAttributeListener; remove from UserAttributeListener. - KitManagerImpl calls BaseAttributeListener.onSetUserAttributeList for list attributes. - AttributeListener-only kits delegate onSetUserAttributeList to setUserAttributeList. - AttributeListenerTestKit implements onSetUserAttributeList via setUserAttributeList. Made-with: Cursor * test: KitManagerImplTest expect onSetUserAttributeList for list path KitManagerImpl forwards list-valued attributes via BaseAttributeListener.onSetUserAttributeList when supportsAttributeLists is true. Made-with: Cursor * refactor: remove setUserAttributeList from AttributeListener - Drop legacy two-arg setUserAttributeList from KitIntegration.AttributeListener; KitManagerImpl already forwards list attributes via onSetUserAttributeList. - Kits: use private helpers (Braze, Localytics) or inline no-ops; Adobe kits call syncIds from onSetUserAttributeList only. - AttributeListenerTestKit invokes list callback from onSetUserAttributeList. Made-with: Cursor * refactor: inline list attribute helpers into onSetUserAttributeList - Braze: remove private setUserAttributeList; duplicate Braze getCurrentUser flow in onSetUserAttributeList and setAllUserAttributes initial sync. - Localytics: call Localytics.setProfileAttribute directly from onSetUserAttributeList and setAllUserAttributes. Made-with: Cursor * Align onSetUserAttributeList parameter names with BaseAttributeListener Rename Kotlin overrides and call sites to use attributeKey, attributeValueList, and user consistently across kits and test kits. Made-with: Cursor * Document empty onSetUserAttributeList overrides with // not supported Add a consistent comment for no-op kit implementations; align AppsFlyer wording with other kits. Made-with: Cursor * refactor: Route bulk user attribute sync through onSetAllUserAttributes (#691) * Delegate onSetAllUserAttributes to setAllUserAttributes in dual-listener kits AppsFlyer and Braze: forward snapshot maps to AttributeListener.setAllUserAttributes. Singular: align override parameter names with UserAttributeListener and delegate. Made-with: Cursor * Move onSetAllUserAttributes to BaseAttributeListener; route sync via one call - Declare onSetAllUserAttributes on BaseAttributeListener; remove from UserAttributeListener - KitManagerImpl: call BaseAttributeListener.onSetAllUserAttributes only (no duplicate setAllUserAttributes) - AttributeListener-only kits: delegate onSetAllUserAttributes to setAllUserAttributes - AttributeListenerTestKit: align setAllUserAttributes maps with Java API Made-with: Cursor * Hoist FilteredMParticleUser in onUserAttributesReceived Compute getInstance(mpid, provider) once before the supportsAttributeLists branch. Made-with: Cursor * Remove setAllUserAttributes from AttributeListener Drop the method from KitIntegration.AttributeListener; full sync is delivered via BaseAttributeListener.onSetAllUserAttributes. Kits keep setAllUserAttributes as ordinary helpers (no override). Update KitManagerImplTest and AttributeListenerTestKit accordingly. Made-with: Cursor * refactor(kits): inline setAllUserAttributes into onSetAllUserAttributes Remove redundant setAllUserAttributes helpers from kits and AttributeListenerTestKit. Update BaseAttributeListener Javadoc in KitIntegration. Made-with: Cursor * refactor: Rename AttributeListener to ModifyIdentityListener (#692) * refactor: decouple AttributeListener from BaseAttributeListener AttributeListener now only declares identity APIs; kits implement BaseAttributeListener alongside it for user attribute callbacks. Update affected kits, AttributeListenerTestKit, and KitManagerImplTest mocks. Made-with: Cursor * Rename AttributeListener to ModifyIdentityListener Replace KitIntegration.AttributeListener with ModifyIdentityListener for set/remove user identity forwarding. Update KitManagerImpl, affected kits, and rename AttributeListenerTestKit to ModifyIdentityListenerTestKit. Clarify BaseAttributeListener Javadoc links and KitManagerImpl section comment. Made-with: Cursor * Remove BaseAttributeListener; fold into UserAttributeListener Drop the deprecated BaseAttributeListener type and merge its callbacks into UserAttributeListener. KitManagerImpl now forwards user attributes using UserAttributeListener only; incrementUserAttribute calls both increment and setUserAttribute on the same listener. Kits that previously implemented BaseAttributeListener without the extended callbacks now implement UserAttributeListener with no-op onIncrementUserAttribute, onSetUserTag, and onConsentStateUpdated. Update ModifyIdentityListenerTestKit and KitManagerImplTest accordingly. Made-with: Cursor * refactor: KitManagerImpl user-attribute forwarding and UserAttributeListener cleanup (#693) * Add activeKits() helper and unit test Introduce activeKits() to return non-disabled kit integrations from the providers map. Add KitManagerImplTest.testActiveKitsExcludesDisabled to verify disabled kits are omitted. Made-with: Cursor * Refactor KitManagerImpl user-attribute and identity forwarding Use activeKits() for user attribute and identity paths; inline former setUserAttribute helpers to avoid duplicate isDisabled checks. Flatten syncUserIdentities with early returns and drop redundant null check on identities map. Made-with: Cursor * UserAttributeListener: expose kit identity; use activeKits in onUserAttributesReceived Declare getConfiguration() and getName() on UserAttributeListener so callers can access kit metadata consistently. Route onUserAttributesReceived through activeKits() and align variable naming with other active-kit paths. Made-with: Cursor * Remove FilteredMParticleUser from UserAttributeListener callbacks Drop the user parameter from KitIntegration.UserAttributeListener methods; update KitManagerImpl forwarding, instrumented/unit tests, and kit implementations (Adobe, AppsFlyer, Apptentive, Braze, CleverTap, etc.). Made-with: Cursor * Refactor UserAttributeListener forwarding in KitManagerImpl Add getConfiguration() and getName() to UserAttributeListener so callers can use the listener type without casting. Introduce userAttributeListeners() and iterate with variable name listener; keep activeKits() package-visible for tests. Made-with: Cursor * test(appsflyer): align onConsentStateUpdated calls with UserAttributeListener API Remove third argument and unused FilteredMParticleUser mock setup from unit tests. Made-with: Cursor * Fix DataplanBlockingUserTests onRemoveUserAttribute lambda arity UserAttributeListenerTestKit exposes (String?) -> Unit; a two-parameter lambda failed Kotlin type inference in compileDebugAndroidTestKotlin. Made-with: Cursor * Fix Braze kit tests for two-arg onConsentStateUpdated KitIntegration.UserAttributeListener now passes only old and new ConsentState. Drop the removed FilteredMParticleUser argument and unused mock from AppboyKitTests across braze-38 through braze-41. Made-with: Cursor * Fix GA and GA4 kit tests for two-arg onConsentStateUpdated Align GoogleAnalyticsFirebaseKitTest and GoogleAnalyticsFirebaseGA4KitTest with KitIntegration: drop the removed FilteredMParticleUser argument and unused mock from consent tests. Made-with: Cursor * ci: generate CHANGELOG on release draft (#696) * ci: generate CHANGELOG on release draft Run ROKT/rokt-workflows generate-changelog after mavenLocal smoke; use default tag-prefix so semver matches VERSION and GitHub release tags. Made-with: Cursor * ci: pin generate-changelog action to commit SHA Semgrep blocks mutable @main and unpinned third-party actions; use ROKT/rokt-workflows@c5c93e92107c520fb8b8cf71070995abdf4c403f. Made-with: Cursor * refactor: centralize active kit filtering in KitManagerImpl (#697) * refactor: use activeKits in getRoktKitApi Use activeKits() in getRoktKitApi to centralize filtering of disabled kits and remove duplicated disabled checks. Made-with: Cursor * refactor: use activeKits in setWrapperSdkVersion Use activeKits() in setWrapperSdkVersion to centralize disabled-kit filtering and remove duplicate disabled checks. Made-with: Cursor * refactor: use activeKits in kit event forwarding Apply activeKits() in setLocation, logNetworkPerformance, and logCommerceEvent to centralize disabled-kit filtering and remove duplicated disabled checks. Made-with: Cursor * refactor: use activeKits for push and lifecycle forwarding Apply activeKits() in push callbacks, breadcrumb/error forwarding, and selected activity/session listeners to centralize disabled-kit filtering and remove repeated checks. Made-with: Cursor * refactor: use activeKits for identity and referrer callbacks Apply activeKits() in installReferrerUpdated and identity/consent callback forwarding methods to centralize disabled-kit filtering and remove duplicated checks. Made-with: Cursor * address sonar cube comments * refactor: migrate Rokt contracts and facade ownership to rokt-kit (#700) * feat: move Rokt object creation into rokt kit Stop instantiating and storing Rokt inside android-core MParticle, and create it from rokt-kit extensions instead to start decoupling Rokt object ownership from the core SDK. * feat: move Rokt facade and tests into rokt kit Relocate the Rokt facade class and its unit tests from android-core to the rokt kit so Rokt-specific API ownership continues shifting out of core while preserving current behavior and test coverage. * refactor: route Rokt facade calls through resolveRoktKit Use a single helper in the Rokt facade to resolve the kit API for all operations, making the upcoming decoupling from the legacy roktKitApi chain incremental and safer. * refactor: move Rokt request preprocessing into rokt kit helper * refactor: route RoktKit attribute preparation through kit helper * refactor: remove roktKitApi from core kit manager contract * refactor: remove remaining roktKitApi bridge and tests * refactor: move rokt contract types into rokt kit module * refactor: move RoktEvent type into rokt kit module * refactor: move MpRoktEventCallback into rokt kit module * refactor: use native RoktEvent in rokt kit Remove the mParticle RoktEvent wrapper and return native Rokt SDK events directly to simplify the event pipeline and reduce duplicate mapping logic. * refactor: use native unload reasons in rokt callback Remove the mParticle unload reason wrapper and pass Rokt SDK unload reasons through directly to simplify callback handling and eliminate redundant mapping. * refactor: use native rokt callback types Replace MpRoktEventCallback with the native RoktCallback across the rokt kit and tests to remove callback wrappers and simplify callback delegation. * refactor: use native placement options type Replace the local PlacementOptions wrapper with the native Rokt SDK PlacementOptions across the rokt kit and remove the now-redundant conversion layer. * refactor: use native rokt config types Replace mParticle RoktConfig and CacheConfig wrappers with native Rokt SDK config types and remove the now-unnecessary config conversion layer and tests. * refactor: move rokt facade and embedded view types to kits package Relocate Rokt, RoktEmbeddedView, RoktLayoutDimensionCallBack, and RoktTest into com.mparticle.kits to keep kit-owned types co-located and simplify package boundaries. * refactor: replace rokt isEnabled reflection with callback provider Avoid runtime method lookup for isEnabled by injecting an explicit enablement callback and wiring it to core callbacks with a safe opt-out fallback, preserving behavior under obfuscation. * refactor: route Rokt enabled check through kit manager contract Add isEnabled to KitManager and use it from the Rokt facade so enablement is resolved through a stable kit-layer API without reflection or config manager coupling. * chore: remove unused imports in KitManagerImpl tests Clean up stale imports in KitManagerImplTest so android-kit-base ktlint test source checks pass in CI. * fix: resolve rokt and buildSrc lint and ci compatibility issues Replace replaceFirstChar in buildSrc for older Kotlin compatibility and address rokt ktlint violations by suppressing Java-style accessor naming and wrapping long warning messages. * refactor: tighten Rokt accessor API and restore legacy docs Keep only the no-arg public Rokt accessor with explicit start precondition, restore original public method documentation text, and make prepareAttributesAsync internal per review feedback. * refactor: align MParticleRokt package with kit module path Update MParticleRokt package to com.mparticle.kits so declaration matches the file location and resolves package/path review feedback. * refactor: cache MParticleRokt accessor instance Keep a synchronized singleton Rokt instance in MParticleRokt to avoid repeated allocations while preserving the explicit start precondition. * feat: migrate Rokt kit to Rokt SDK 5.x and remove MpRoktEventCallback (#704) * feat: migrate Rokt kit to Rokt SDK 5.x and remove MpRoktEventCallback Bumps com.rokt:roktsdk 4.14.0 → 5.1.0 and adopts the 5.x event-driven API: - Rokt.execute(...) → Rokt.selectPlacements(...) - RoktEvent.id renamed to identifier; SDK-side CartItemInstantPurchase.placementId renamed to identifier - com.rokt.roktsdk.RoktLayout switched to onEvent: (RoktEvent) -> Unit - Drops removed Rokt.RoktCallback / Rokt.RoktInitCallback / Rokt.UnloadReasons and RoktWidgetDimensionCallBack.onMarginChanged Removes the legacy callback surface from the mParticle public API, since 5.x customers consume Rokt.events(identifier): Flow<RoktEvent> instead: - Delete MpRoktEventCallback and UnloadReasons - Drop callbacks param from com.mparticle.Rokt.selectPlacements - Drop mpRoktEventCallback from RoktKitApi, RoktKitApiImpl, KitIntegration.RoktListener, and RoktKit.selectPlacements - Rename RoktKit.runComposableWithCallback to prepareComposableAttributes; RoktLayout composable no longer takes a callback parameter BREAKING CHANGE: MpRoktEventCallback and UnloadReasons are removed and the callbacks parameter has been dropped from Rokt.selectPlacements and the mParticle RoktLayout composable. Use Rokt.events(identifier) to observe placement events as a Flow. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: align mParticle Rokt API naming with Rokt SDK 5.x Renames public API symbols to match Rokt 5.x's vocabulary: - com.mparticle.RoktEvent.*.placementId → identifier on all event classes (OfferEngagement, PositiveEngagement, FirstPositiveEngagement, PlacementInteractive, PlacementReady, PlacementClosed, PlacementCompleted, PlacementFailure, OpenUrl, CartItemInstantPurchase) - Rokt.purchaseFinalized(placementId, ..., status) → (identifier, ..., success); propagated through RoktKitApi, RoktKitApiImpl, KitIntegration.RoktListener, and RoktKit Rename-only — no behavior change. BREAKING CHANGE: RoktEvent.placementId is renamed to identifier and Rokt.purchaseFinalized parameters renamed from (placementId, status) to (identifier, success). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor: drop dead onMarginChanged from RoktLayoutDimensionCallBack Rokt SDK 5.x removed onMarginChanged from RoktWidgetDimensionCallBack; the kit already dropped its override, but mParticle's mirror interface still forced customers to implement an onMarginChanged that never fires. onHeightChanged remains the only method on RoktLayoutDimensionCallBack and is still the way to observe Widget height changes — 5.x exposes no event-based equivalent. BREAKING CHANGE: RoktLayoutDimensionCallBack.onMarginChanged is removed. Customers implementing this interface should drop the override. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: add customBaseURL CNAME support to NetworkOptions (#702) * feat: add customBaseURL CNAME support to NetworkOptions Adds NetworkOptions.Builder.setCustomBaseURL(String) which routes all mParticle endpoint traffic (config, events, identity, alias, audience) through a single HTTPS CNAME host. When set, customBaseURL takes priority over individual domain mappings and rewrites paths to match CDN routing: /config/v4/, /nativeevents/v2/, /identity/v1/, /nativeevents/v1/identity/, /nativeevents/v1/<key>/audience. Also adds R8 keep rules for MParticle$Internal and ConfigManager.getNetworkOptions() so kits can read customBaseURL after minification. The Rokt kit reads NetworkOptions.customBaseURL and forwards it to the Rokt SDK: https://github.com/mparticle-integrations/mparticle-android-integration-rokt/pull/143 Mirrors iOS work from mparticle-apple-sdk#760. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat: pass mParticle CNAME through to Rokt SDK When the integrating app sets a custom CNAME on MParticleOptions via NetworkOptions.customBaseURL, forward it to the Rokt SDK so Rokt traffic routes through the same first-party domain. No-op when customBaseURL is unset, empty, or MParticle is uninitialized. Mirrors the iOS Rokt kit behavior added in mparticle-apple-sdk#760. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: persist customBaseURL across NetworkOptions JSON round-trip NetworkOptions.toJson() and withNetworkOptions(String) did not include customBaseURL, so any value was silently dropped when UploadSettings serialized NetworkOptions to the upload database. Events and alias uploads read back NetworkOptions without customBaseURL and routed to the default mParticle endpoints instead of the partner CNAME. Also: - Extract the customBaseURL/DomainMapping host-resolution branch out of getUrl() into a private resolveHost() helper plus a small ResolvedHost value type, lowering getUrl()'s cyclomatic complexity. - Switch java.net.URL / java.net.MalformedURLException to imports. - Add two androidTest cases covering the round-trip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * Bump Rokt dependency version * fix: only warn on domain-mapping conflict when mapping is non-default NetworkOptionsManager.validateAndResolve auto-populates a default DomainMapping for every endpoint, so the previous check fired the "customBaseURL is set; domain mapping for X is ignored" warning on every getUrl() call for every endpoint — even when the integrator never configured a custom mapping. Compare against the default URL so the warning only fires for genuinely user-configured mappings that conflict with customBaseURL. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci: support alpha beta and release candidate versions (#708) * ci(release): support alpha beta and release candidate versions Add qualified release version handling to the draft workflow so alpha, beta, and release candidate versions can be prepared from the selected branch. Publish workflow releases now run from workstation branches and mark qualified versions as GitHub pre-releases instead of latest stable releases. Document the new release flow and record the workflow capability in the changelog. * fix: support older Kotlin in publish helper * ci: use SDK Gradle wrapper for cross-platform tests * ci: patch cross-platform Gradle settings * ci: update cross-platform javadoc patch * ci: align cross-platform Android plugin version * ci: relax cross-platform JVM target validation * ci: patch cross-platform SDK API usage * ci: normalize cross-platform user attribute lists * ci: remove cross-platform compatibility workarounds * ci: use release-prep branch for draft releases * build(rokt): update Rokt kit dependency stack (#707) * build(rokt): update Rokt kit dependency stack Align the Rokt kit build with the upcoming Rokt SDK alpha by updating Kotlin, Compose, and coroutine dependencies. Pin the Maven artifact id so the kit continues publishing as android-rokt-kit. #agentic * build(rokt): use Rokt SDK 6.0.0 release candidate Point the Rokt kit at the Maven Central release candidate so the kit can compile and test without relying on unpublished alpha artifacts. #agentic * build(rokt): guard publish metadata for standalone builds Only configure the Rokt kit Maven publish metadata when the mparticleMavenPublish extension is available. This keeps standalone kit builds working while preserving the monorepo publish artifact id. #agentic * Prepare release 6.0.0-rc.1 (#709) * chore: prepare release 6.0.0-rc.1 * build(rokt): update Rokt SDK to 6.0.1-rc.1 --------- Co-authored-by: thomson-t <125323226+thomson-t@users.noreply.github.com> Co-authored-by: Thomson Thomas <thomson.thomas@rokt.com> * feat(rokt): add kit API parity access (#711) Add Kotlin MParticle.rokt access so partners can call Rokt kit APIs from the active mParticle instance again. Forward native Rokt SDK Compose events through the kit RoktLayout wrapper and document the Kotlin and Java entry points. * docs: add v6 Rokt migration guidance (#706) docs: add v6 Rokt migration notes Document v6 Rokt migration details so integrators can update imports and type usage after moving Rokt APIs into rokt-kit. * feat: add adjust sample apps and CI example builds (#723) * feat(kits): add adjust sample apps and CI example builds Introduce Kotlin/Java sample apps for adjust-5 and wire a CI-only settings file so example modules stay isolated from kit settings and settings-kits.gradle. * ci: pin build-kits workflow actions to commit SHAs Fix semgrep blocking findings for mutable GitHub Actions tag references. * fix(kits): align Gradle project paths with android- kit names Use explicit android- prefixed includes and projectDir mappings so kit examples, dependencies, and CI matrix tasks resolve the same modules. * revert: restore settings-kits.gradle rename pattern Keep kit registration unchanged and rely on the existing android- rename so example modules and CI matrix paths continue to resolve correctly. * chore(kits): remove Adjust Java sample app Keep only the Kotlin example and drop Java example wiring from CI matrix and kit example settings. * feat: add Kotlin sample apps for all integrated kits (#724) * feat(kits): add Kotlin sample apps for all integrated kits Replicate the Adjust example-app pattern across every kit in settings-kits.gradle, wire them in settings-kit-examples.gradle and kits/matrix.json, and add a generator script. Skip CI example builds for kits that need custom Maven repos or AGP 8.6+. * fix(kits): enable vendor Maven repos in sample app builds Add kit-specific repositories and multidex to example apps that need vendor Maven resolution, and drop skip_example_builds for those kits. * feat: pin kit SDK dependencies to current supported ranges (#725) * feat: pin kit SDK dependencies to current supported ranges * refactor(adobemedia): rename kit to adobemedia-3 and lock to Adobe SDK BOM Adobe's Experience Platform SDK is at major 3.x, so the kit directory now follows the wrapped-SDK-major convention (adobemedia-5 -> adobemedia-3). Replace the mixed per-artifact pins with the Adobe sdk-bom. The legacy sdk-core (deprecated 2024-06-30) and mobileservices (unsupported on Android) artifacts are dropped; modern `core` now arrives via the BOM. The BOM range [3.0.0,4.0.0) auto-tracks the latest 3.x minor/patch, the Gradle equivalent of iOS SPM .upToNextMajor(from: "3.0.0"). Updated matrix.json, settings-kits.gradle, settings-kit-examples.gradle, the example module project ref, and the README install line. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * refactor(adobe): rename adobe-5 to adobe (no SDK, S2S only) and drop adobemedia BOM comments The adobe kit is a server-to-server integration with no Adobe SDK dependency (no com.adobe.* imports), so the wrapped-SDK-major suffix does not apply — renamed adobe-5 -> adobe, matching the no-number convention used by onetrust and rokt. Updated matrix.json, settings-kits.gradle, settings-kit-examples.gradle, and the example module project ref. The published artifact version (android-adobe-kit:5+) is unchanged, consistent with other no-number kits. Also removed the explanatory comments from the adobemedia-3 BOM block. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix: align braze-38 SDK range with its directory major (#730) The kit directory suffix N encodes the wrapped vendor SDK's intended major version, but braze/braze-38 pinned com.braze:android-sdk-ui:[37.0.0,38.0.0) (major 37). Bumped to [38.0.0,39.0.0) to match the braze-38 directory; siblings braze-39/40/41 already align and there is no braze-37 directory. The GA kit (ga-23/ga4-23) major-23 alignment is deferred to a separate PR that also bumps the repo Kotlin toolchain, because firebase-analytics 23.x ships Kotlin 2.1/2.2 metadata that the current Kotlin 2.0.20 compiler cannot read. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * feat: upgrade Kotlin to 2.1.20 across core SDK and kits (#732) * feat: Upgrade Kotlin to 2.1.20 across core SDK and kits * fix: construct kit test config JSON explicitly for Kotlin 2.1 overload resolution * fix: align GA kits with directory major 23 (+ per-kit Kotlin 2.2.20) (#731) * fix: align GA kits with directory major 23 and bump Kotlin to read 23.x metadata The ga-23 and ga4-23 directories encode wrapped firebase-analytics major 23, but both pinned firebase-analytics:[22.1.0,23.0.0) (major 22). Bumped the firebase-analytics and lockstep play-services-measurement-api ranges to [23.0.0,24.0.0). firebase-analytics 23.x ships Kotlin 2.1/2.2 metadata (23.0.0 -> 2.1.0, 23.2.0 -> 2.2.0), which the kits' Kotlin 2.0.20 compiler cannot read, so the range bump alone fails compileReleaseKotlin. Bumped these two kits' ext.kotlin_version to 2.2.20, matching the existing per-kit override pattern already used by urbanairship-20 (2.2.20) and rokt (2.1.20). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci: build ga-23/ga4-23 as isolated kits (Kotlin 2.2.x) firebase-analytics 23.x ships Kotlin 2.1/2.2 metadata that the repo's root Kotlin Gradle plugin (2.0.20) cannot read, so the GA kits cannot compile in the aggregate settings-kits.gradle build. Per-kit ext.kotlin_version has no effect there because the aggregate compiler is fixed by the root buildscript. Follow the established urbanairship-20 isolated-kit pattern so the GA kits are built standalone with their own Kotlin 2.2.20: - Remove ga-23/ga4-23 from kits/matrix.json (no aggregate build-kits jobs). - Comment them out of settings-kits.gradle and remove their example modules from settings-kit-examples.gradle. - Add isolated compatibility (pull-request.yml) and lint/ktlint/test (daily.yml) steps that run `-p kits/ga/ga-23` / `-p kits/ga4/ga4-23`. - Document both kits under "Currently isolated" in ONBOARDING.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Signed-off-by: Nickolas Dimitrakas <nickolas.dimitrakas@rokt.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * fix(braze): correct example app applicationId to match push category (#729) The braze-38/39/40/41 example apps set applicationId to "com.mparticle.com.mparticle.kits.braze.example" (duplicated prefix) while the manifest package and the MPReceiver FCM intent-filter category are "com.mparticle.kits.braze.example". Since the effective package equals the applicationId, the push category no longer matched, so push registration and receipt in the sample apps could fail. Align the applicationId with the package and category across all four tracks. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> * chore: merge main into workstation/6.0-Release (#734) * chore: Update submodules * chore: 5.78.3 (release) ## [5.78.3](https://github.com/mParticle/mparticle-android-sdk/compare/v5.78.2...v5.78.3) (2026-03-11) ### Updates & Maintenance * bump actions/upload-artifact from 6 to 7 ([#649](https://github.com/mParticle/mparticle-android-sdk/issues/649)) ([0a188b1](https://github.com/mParticle/mparticle-android-sdk/commit/0a188b1f88efde471f8d6bff2aa8611b1b4bf956)) * Update submodules ([cbb17d7](https://github.com/mParticle/mparticle-android-sdk/commit/cbb17d7e359d41d8d7577a9516cf7788c7288442)) * chore: Update submodules * chore: 5.78.4 (release) ## [5.78.4](https://github.com/mParticle/mparticle-android-sdk/compare/v5.78.3...v5.78.4) (2026-03-23) ### Updates & Maintenance * Update submodules ([08dab75](https://github.com/mParticle/mparticle-android-sdk/commit/08dab75e3715733f6f5655fbf39fbce16a2e01a2)) * chore: Update submodules * chore: 5.78.5 (release) ## [5.78.5](https://github.com/mParticle/mparticle-android-sdk/compare/v5.78.4...v5.78.5) (2026-03-25) ### Updates & Maintenance * Update submodules ([86d8d97](https://github.com/mParticle/mparticle-android-sdk/commit/86d8d9748a0c7a796dd0b0be6722f92acef301ea)) * fix: increase MPLatch timeout from 5s to 30s (#695) * fix: increase MPLatch timeout from 5s to 30s The 5-second timeout is too short for WebView JS bridge tests running on newer GitHub Actions runner images (ubuntu24/20260309.50+). The MParticleJSInterfaceITest tests consistently fail because JS execution in the emulator WebView doesn't complete within 5 seconds on these environments. Increasing to 30 seconds provides sufficient margin while still catching genuine hangs via the workflow-level timeout-minutes: 15. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: use explicit 30s timeout in JS bridge tests only Instead of increasing the global MPLatch timeout (used by 20+ test files), use an explicit 30-second await in MParticleJSInterfaceITest only. WebView JS execution needs more time on newer CI runner images, but other tests don't need the longer timeout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat: Add max persistence age override option [TRIAGE-608] (#699) * TRIAGE-608: Add max persistence age override option * TRIAGE-608: Update throttl ts on success + tests * TRIAGE-608: Make properties @VisibleForTesting * TRIAGE-608: Fix retry-on-failure throttle logic * feat: add customBaseURL CNAME support to NetworkOptions (#701) * feat: add customBaseURL CNAME support to NetworkOptions Adds NetworkOptions.Builder.setCustomBaseURL(String) which routes all mParticle endpoint traffic (config, events, identity, alias, audience) through a single HTTPS CNAME host. When set, customBaseURL takes priority over individual domain mappings and rewrites paths to match CDN routing: /config/v4/, /nativeevents/v2/, /identity/v1/, /nativeevents/v1/identity/, /nativeevents/v1/<key>/audience. Also adds R8 keep rules for MParticle$Internal and ConfigManager.getNetworkOptions() so kits can read customBaseURL after minification. The Rokt kit reads NetworkOptions.customBaseURL and forwards it to the Rokt SDK: https://github.com/mparticle-integrations/mparticle-android-integration-rokt/pull/143 Mirrors iOS work from mparticle-apple-sdk#760. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: persist customBaseURL across NetworkOptions JSON round-trip NetworkOptions.toJson() and withNetworkOptions(String) did not include customBaseURL, so any value was silently dropped when UploadSettings serialized NetworkOptions to the upload database. Events and alias uploads read back NetworkOptions without customBaseURL and routed to the default mParticle endpoints instead of the partner CNAME. Also: - Extract the customBaseURL/DomainMapping host-resolution branch out of getUrl() into a private resolveHost() helper plus a small ResolvedHost value type, lowering getUrl()'s cyclomatic complexity. - Switch java.net.URL / java.net.MalformedURLException to imports. - Add two androidTest cases covering the round-trip. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(android-core): cover custom base URL upload storage --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: Thomson Thomas <thomson.thomas@rokt.com> * chore: Update submodules * chore: 5.79.0 (release) ## [5.79.0](https://github.com/mParticle/mparticle-android-sdk/compare/v5.78.5...v5.79.0) (2026-05-14) ### Features * add customBaseURL CNAME support to NetworkOptions ([#701](https://github.com/mParticle/mparticle-android-sdk/issues/701)) ([5285149](https://github.com/mParticle/mparticle-android-sdk/commit/5285149118b58cbd5cf4fb90cb58627deb7538b9)), closes [mparticle-apple-sdk#760](https://github.com/mParticle/mparticle-apple-sdk/issues/760) * Add max persistence age override option [TRIAGE-608] ([#699](https://github.com/mParticle/mparticle-android-sdk/issues/699)) ([ca88322](https://github.com/mParticle/mparticle-android-sdk/commit/ca88322ac7ef8649ed111cf28afb81d99cdb271a)) ### Bug Fixes * increase MPLatch timeout from 5s to 30s ([#695](https://github.com/mParticle/mparticle-android-sdk/issues/695)) ([20f723f](https://github.com/mParticle/mparticle-android-sdk/commit/20f723f27cf296c879ceebc9d234edca039ab371)) ### Updates & Maintenance * Update submodules ([59a4a9a](https://github.com/mParticle/mparticle-android-sdk/commit/59a4a9a68e3addfaf5c4eea1afd396889721819d)) * chore: bump trunk-io/trunk-action from 1.2.4 to 1.3.1 (#705) Bumps [trunk-io/trunk-action](https://github.com/trunk-io/trunk-action) from 1.2.4 to 1.3.1. - [Release notes](https://github.com/trunk-io/trunk-action/releases) - [Commits](https://github.com/trunk-io/trunk-action/compare/75699af9e26881e564e9d832ef7dc3af25ec031b...04ba50e7658c81db7356da96657e6e77f220bfa3) --- updated-dependencies: - dependency-name: trunk-io/trunk-action dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Handle legacy persisted domain mappings safely (#703) Co-authored-by: James Newman <james.newman@rokt.com> * fix(ci): pin isolated-kit gradle version to prevent 6.0.0-rc.1 pull (#714) The isolated urbanairship-kit lint/test steps in daily.yml and the kit-compatibility test in pull-request.yml run `./gradlew` from inside the kit dir without `-Pversion=...`. The kit's standalone build.gradle defaults `project.version = '+'`, so its `com.mparticle:android-kit-plugin` dependency resolves to the highest version on Maven Central — now `6.0.0-rc.1` (published 2026-05-22), which renamed/removed kit-base symbols and broke the kit's compile. Mirror the pattern already used in the Sonatype Release job: extract the SDK version via `./gradlew -q properties` and pass it as `-Pversion=...` to every standalone kit invocation, so it resolves the freshly-published mavenLocal artifact instead of the RC. Affected steps: - lint-checks → Run Isolated Kit Lint (urbanairship-kit) - kotlin-lint-checks → Run Isolated Kit Kotlin Lint (urbanairship-kit) - update-kits → Test Isolated Kits (urbanairship-kit) - kit-compatibility-test → Run Isolated Kit Compatibility Tests (urbanairship-kit) The companion defensive fix in mparticle-android-integration-urbanairship pins the kit's standalone `project.version` to `[5.0,6.0)`. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: Update submodules * chore: 5.79.1 (release) ## [5.79.1](https://github.com/mParticle/mparticle-android-sdk/compare/v5.79.0...v5.79.1) (2026-05-27) ### Bug Fixes * **ci:** pin isolated-kit gradle version to prevent 6.0.0-rc.1 pull ([#714](https://github.com/mParticle/mparticle-android-sdk/issues/714)) ([eff10ea](https://github.com/mParticle/mparticle-android-sdk/commit/eff10ead69167f0ea3df248b2bbed089397600cd)) ### Updates & Maintenance * bump trunk-io/trunk-action from 1.2.4 to 1.3.1 ([#705](https://github.com/mParticle/mparticle-android-sdk/issues/705)) ([f4ceca7](https://github.com/mParticle/mparticle-android-sdk/commit/f4ceca7de2c2ba01ea87c98698ef7bb84991b4ab)) * Update submodules ([e435979](https://github.com/mParticle/mparticle-android-sdk/commit/e435979e1e966ef2b318bb29135852f9d55df55a)) * ci: remove cross-platform-tests and semantic PR/branch checks (#712) These checks have been failing on nearly every recent PR. The cross-platform tests are known broken, and the semantic PR title / branch name checks are no longer enforced. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump actions/checkout from 6.0.2 to 6.0.3 (#720) Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3. - [Release notes](https://github.com/actions/checkout/releases) - [Commits](https://github.com/actions/checkout/compare/v6.0.2...v6.0.3) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * chore: Update submodules * chore: 5.79.2 (release) ## [5.79.2](https://github.com/mParticle/mparticle-android-sdk/compare/v5.79.1...v5.79.2) (2026-06-22) ### Updates & Maintenance * bump actions/checkout from 6.0.2 to 6.0.3 ([#720](https://github.com/mParticle/mparticle-android-sdk/issues/720)) ([d904edb](https://github.com/mParticle/mparticle-android-sdk/commit/d904edb0a944a2ce813e7dc31c026f0b2f7ccecb)) * remove cross-platform-tests and semantic PR/branch checks ([#712](https://github.com/mParticle/mparticle-android-sdk/issues/712)) ([6cdacf2](https://github.com/mParticle/mparticle-android-sdk/commit/6cdacf2926e02e2359352dbcf12b4e4bb66236fa)) * Update submodules ([976dd0d](https://github.com/mParticle/mparticle-android-sdk/commit/976dd0d13d6aa27f805a6b06a73d923f1a207e80)) * feat: add device-based consent to override MPID-scoped consent (#726) Enables Inspire-style flows where consent is collected before MPID changes at checkout, so kit forwarding rules and uploads keep the correct consent state. * chore: 5.80.0 (release) ## [5.80.0](https://github.com/mParticle/mparticle-android-sdk/compare/v5.79.2...v5.80.0) (2026-06-25) ### Features * add device-based consent to override MPID-scoped consent ([#726](https://github.com/mParticle/mparticle-android-sdk/issues/726)) ([e92d352](https://github.com/mParticle/mparticle-android-sdk/commit/e92d3522a350be90a1f15eb3b81d5e6f089f1aed)) * chore: normalize CHANGELOG list markers after merge * ci: pin actions/checkout to commit SHA to satisfy security lint * docs: remove duplicate Unreleased changelog section --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: mparticle-automation <developers@mparticle.com> Co-authored-by: Robert Ing <ring@mparticle.com> Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: junias-rokt <junias.ngoyi@rokt.com> Co-authored-by: James Newman <james.newman@rokt.com> Co-authored-by: Thomson Thomas <thomson.thomas@rokt.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ankitsingh08 <ankit.tomar08@gmail.com> * feat: add Rokt Shoppable Ads support (#713) feat(rokt): add Shoppable Ads support Add Rokt kit facade APIs for payment extension registration and Shoppable Ads selection so host apps can wire optional payment providers through mParticle. Forward Shoppable Ads requests through the existing identity confirmation and attribute enrichment pipeline, pass dashboard stripePublishableKey into the Rokt SDK registration config, and cover the behavior with kit and facade tests. * docs: address 6.0 merge review comments (#735) docs: address 6.0 merge review comments (README version, checkout pin comment) * feat(rokt-sdk-plus): add com.rokt:rokt-sdk-plus umbrella artifact (#721) Introduce a single Android dependency that bundles the mParticle core SDK, the mParticle Rokt kit, and the Rokt Payment Extension (Shoppable Ads), mirroring the iOS RoktSDKPlus umbrella. Partners adopting Shoppable Ads can depend on one artifact instead of wiring up core + kit + payment extension by hand. - New rokt-sdk-plus module: thin com.android.library (empty AAR) that api-aggregates android-core, android-rokt-kit, and com.rokt:payment-extension, plus a RoktSdkPlus version constant. The mParticle Rokt kit deliberately omits the payment extension; this umbrella is what adds it on top. - Published as com.rokt:rokt-sdk-plus via an isolated settings-rokt-sdk-plus.gradle so it builds/publishes in its own Gradle invocation with Rokt Maven Central credentials. - Centralize the Rokt SDK / payment extension versions in gradle.properties (roktSdkVersion, roktPaymentExtensionVersion); the Rokt kit now reads roktSdkVersion. - Extend the publish convention plugin with optional POM url/license overrides (backward-compatible) so the com.rokt artifact carries Rokt branding. - release-publish.yml: publish the Rokt kit to mavenLocal so the umbrella resolves its mParticle deps locally (avoiding Maven Central propagation races), then publish the umbrella to Central with the Rokt credentials. The umbrella version tracks the mParticle SDK line; the bundled Rokt artifacts ride their own line. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat: extend Rokt kit Kotlin example for joint SDK testing (#736) * feat: extend Rokt kit Kotlin example for joint SDK testing * fix: use NoActionBar theme and inset-aware layout in Rokt kit example * feat: add runtime credential switching and bottom sheet button to Rokt kit example * feat: build Rokt kit example against rokt-sdk-plus umbrella Depend on the single com.rokt:rokt-sdk-plus umbrella instead of wiring android-core + android-rokt-kit by hand. Bump AGP to 8.9.1 and compileSdk to 36 (required by the payment-extension Compose deps the umbrella pulls in), and pin the mParticle chain to the umbrella version so the kit's dynamic android-kit-base version resolves from Maven Local. --------- Signed-off-by: James Newman <james.newman@rokt.com> Signed-off-by: denischilik <denis.chilik@rokt.com> Signed-off-by: Nickolas Dimitrakas <nickolas.dimitrakas@rokt.com> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: James Newman <james.newman@rokt.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Thomson Thomas <125323226+thomson-t@users.noreply.github.com> Co-authored-by: mParticle Bot User <developers@mparticle.com> Co-authored-by: Thomson Thomas <thomson.thomas@rokt.com> Co-authored-by: Nickolas Dimitrakas <nickolas.dimitrakas@rokt.com> Co-authored-by: Robert Ing <ring@mparticle.com> Co-authored-by: junias-rokt <junias.ngoyi@rokt.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: ankitsingh08 <ankit.tomar08@gmail.com>





Summary
Merges
mainintoworkstation/6.0-Releaseto bring the 6.0 release branch up to date before the final merge back tomain.What main brings in
MParticleOptions.Builder.deviceBasedConsentEnabled(),MParticle.getDeviceConsentState()/setDeviceConsentState()) and related core changes in upload/batch/config handling, plus a new instrumentedUploadServiceTest.actions/checkoutpinned to v6.0.3, removal ofcross-platform-tests.yml).Conflict resolutions
release.yml: kept the 6.0 branch deletions (kits live in-tree now; Rokt release workflows replacerelease.yml).build.gradle: kept 6.0 versioning from theVERSIONfile; dropped main's5.80.0-SNAPSHOTblock.MParticleOptions.java: kept main's new consent APIs and kept the 6.0 removal of deprecatedisAndroidIdDisabled()/androidIdDisabled().MParticleBaseClientImpl.java: kept the 6.0 domain-mapping warning condition (suppresses the false warning when the mapping equals the default URL).ApiVisibilityTest.kt: recounted the public API surface after the merge (66 base − 4 removed on 6.0 + 3 added on main = 65); verified by running the test.daily.yml/pull-request.yml: kept the 6.0 monorepo kit paths, split instrumented jobs, and VERSION-based versioning; adopted main'scheckout@v6.0.3pin; droppedsubmodules: recursive(no submodules on 6.0).CHANGELOG.md: rebuilt as an ordered union (6.0 sections, then main's 5.78.3–5.80.0 sections, then shared history); regenerated at release time anyway.Test plan
./gradlew testpasses locally (core + kit-base, debug and release variants)ApiVisibilityTestverified with recounted public method counttrunk checkclean on changed filesUploadServiceTestand upload/consent core changes)