Adapty SDK 4.1.0: contract 4.1 and the 4.1 natives on both platforms - #30
Merged
Conversation
yauch-dev
marked this pull request as draft
August 15, 2026 19:33
x401om
marked this pull request as ready for review
August 20, 2026 14:18
Contract 4.1.0 and native AdaptySDK-iOS 4.1.0. Android stays on the 4.0.x natives until its 4.1 release, mirroring the Flutter plugin's cut, so this version is marked not-for-publishing in the changelog. - UpdateAttribution -> UpdateExternalAttribution with source -> provider, and AppliedAttributionSources -> AppliedExternalAttributionProviders, matching the native rename; no deprecated aliases, and the profile member's wire key stays - AdaptyConfiguration.Builder.AdaptyAttributionEnabled, off and unsent by default - MakePromotedPurchase, AdaptyPromotedProduct and IAdaptyEventListener.OnReceivePromotedPurchase for App Store promoted purchases; the pinned native completes them itself and does not emit the event yet, so the API is wired for the release that does - a product request writes its offer identifier nested as subscription.offer.offer_identifier, through an envelope DTO shared by the paywall and promoted product requests; the flat key is gone - AdaptyFlow carries ui_schema to the renderer as an opaque JObject, pinned by the flow-full round trip - the demo's iOS fallback stub moves to format 11, which native 4.1 requires; verified on a simulator together with a StoreKit-config purchase, the profile update event, and flow rendering - 4.1.0-dev.1 in the version fields, changelog with the migration link, README pins, and MIGRATION-v4.0-to-v4.1.md
Symptoms before causes (the fallback section now opens with the error the user actually sees), reassurance where the reader would worry (an Android build does not break, an empty handler is a valid choice), and the reasoning behind the missing deprecated aliases instead of the bare fact.
The native dependency is pinned exactVersion 4.1.0, so a future native release that starts forwarding didReceivePromotedPurchase cannot slip into a build on its own — the handler fires only once an SDK release moves the pin. The migration guide claimed otherwise; the changelog copies said it vaguely enough to mislead. Review finding P2.
The Android 4.1.0 release landed and the previous commit pinned it — crossplatform, android-sdk, android-ui and the rebuilt wrapper AAR — but it moved only the build files, so everything that described the pin still described the iOS-only snapshot it used to be. This finishes the bump. - The version is 4.1.0, not 4.1.0-dev.1, and the not-for-publishing gate is gone with the condition that raised it. package.json, the runtime constant and the pinned doc links move together; PackageManifestTests holds the first two to each other. - The Android fallback stub in StreamingAssets was still format 10, which the 4.1 native rejects: the demo would have failed activation on Android at SetFallback. Both stubs are format 11 now, and the changelog and migration guide ask for both files rather than the iOS one. - Adapty Attribution turning opt-in is a breaking change for anyone reading installation details, on both platforms: 4.0 collected them unconditionally, 4.1 collects nothing until the configuration asks. It was documented as "ignoring it changes nothing", which was true only while Android stayed on 4.0.x. It now has its own migration step. - Android 4.1 stopped surfacing NoPurchasesToRestore — RestorePurchases completes with the profile instead — and iOS never sent it, so the member documents itself as unreachable at these pins rather than as Android-only behaviour. - Re-checked against the 4.1.0 natives, no change needed: the error code set is the same on both platforms (iOS AdaptyError.swift is byte-identical to 4.0.2, Android only annotated 1004), and obfuscated_profile_id is still implemented by nobody, as AGENTS asks on every native bump. 4.0.0-beta.2 is never published: its changes ship as part of 4.1.0, and its changelog section says so and points at the 4.1.0 tag.
x401om
force-pushed
the
feature/sdk-4.1-update
branch
from
August 20, 2026 14:27
d6cbc16 to
5a73d15
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Moves the SDK to cross-platform contract 4.1.0 and the 4.1.0 natives on both platforms:
AdaptySDK-iOS 4.1.0 and, since the Android 4.1.0 release landed, crossplatform 4.1.0 /
android-sdk 4.1.0 / android-ui 4.1.0 with the bundled unity-wrapper AAR rebuilt at 4.1.0. The
version is 4.1.0 — the iOS-only snapshot this PR started as, and the not-for-publishing gate it
carried, are gone with the condition that raised them.
Breaking
UpdateAttribution→UpdateExternalAttribution(source→provider),AdaptyProfile.AppliedAttributionSources→AppliedExternalAttributionProviders— matching thenative 4.1 rename, no deprecated aliases. Wire key of the profile member unchanged.
IAdaptyEventListenergainedOnReceivePromotedPurchase(AdaptyPromotedProduct)— a deliberateabstract add, no default implementation: the iOS default is silently purchase, which should not
hide in a default.
installation details only when the configuration asks; the 4.0 natives collected them
unconditionally. So
OnInstallationDetailsSuccessstops firing andGetCurrentInstallationStatusstops reportingDetermineduntil the app setsSetAdaptyAttributionEnabled(true)— on both platforms. It has its own migration step.SetFallback, on bothplatforms:
DecodingFailed(adapty_code: 2006) on iOS,WrongParam(adapty_code: 3001) onAndroid. Both demo stubs are format 11 and the guide tells users to re-download both files.
Added
Adapty.MakePromotedPurchase+AdaptyPromotedProduct(App Store promoted purchases, iOS only).Note: the pinned native completes promoted purchases itself and does not emit the event yet
(
AdaptyPluginDelegatekeeps the default implementation behind a TODO at tag 4.1.0); the listenermethod starts firing only once a future SDK release moves the exact pin to a native that reports
them.
AdaptyConfiguration.Builder.AdaptyAttributionEnabled(+SetAdaptyAttributionEnabled), off andunsent by default — see the breaking entry above for what that now costs.
subscription.offer.offer_identifierthrough
AdaptySubscriptionOfferRequest, shared by the paywall and promoted DTOs; the flat key isno longer written (natives read both, the contract documents only the nested form).
AdaptyFlowcarriesui_schema(UIBuilder 5.1 custom layouts) to the renderer as an opaqueprivate
JObject— round-trip only, not public API.MIGRATION-v4.0-to-v4.1.md, README pins and the changelog section (both copies, entry-set insync).
Re-checked against the 4.1.0 natives, no change needed
AdaptyError.swiftis byte-identicalbetween 4.0.2 and 4.1.0, and Android only added a
@Deprecatedannotation to 1004. The onebehavioural change is that Android 4.1 no longer surfaces
NoPurchasesToRestore—RestorePurchasescompletes with the current profile — and iOS never sent it, so the member isdocumented as unreachable at these pins instead of as Android-only.
obfuscated_profile_idis still declared in the contract and implemented by nobody, iOS included,which is what AGENTS asks to confirm on every native bump.
preloadFlows/preloadOnboardingsand thecustomLayoutIdargument that Android 4.1 added arenot in the cross-platform contract, so there is nothing for this SDK to expose.
payload_datablob and drops thereadable
offernode, so writing the offer identifier nested only is safe there.Deliberately not in this PR
release/4.1.1exists upstream (one commit — the visionOS buildrestore — and the version bump) but is not tagged or released, and an exact SwiftPM pin needs the
tag. Moving to 4.1.1 is a follow-up once iOS ships it; it changes no API this SDK touches.
type: "code"while both iOS and this SDKhandle it — pre-existing, a question for the contract owners.
Testing
#if UNITY_IOSgate on the promoted product'sis_family_shareable, now aligned with the paywallproduct. The final commit changes no wire format, so the pass was not re-run for it.
activation (fallback format 11 accepted),
GetFlow calm10+ products, a purchase through the newnested offer envelope (intro offer applied,
[Environment: Xcode]), profile update arriving viadid_load_latest_profile(Premium: true),UpdateExternalAttribution, and full-screen flowrendering by native UIBuilder 5.1.
device. It is on the release-branch checklist: activation with the format 11 stub,
GetFlow+products, a purchase,
UpdateExternalAttribution, and installation details behind the new flag.