Skip to content

docs(kmp): add the KMP SDK section - #259

Merged
DreamingInBinary merged 10 commits into
mainfrom
jordan/sw-5718-kmp-docs
Aug 14, 2026
Merged

docs(kmp): add the KMP SDK section#259
DreamingInBinary merged 10 commits into
mainfrom
jordan/sw-5718-kmp-docs

Conversation

@DreamingInBinary

Copy link
Copy Markdown
Contributor

Adds content/docs/kmp for the Superwall KMP SDK (0.1.1, beta), registered under the ---SDKs--- group in the root meta.json. Closes SW-5718.

Every page carries a beta warning, per Jake's "put beta in the docs … nothing gets launched till it's documented."

Pre-flight checks

  • Maven Central: published. com.superwall.sdk:superwall-kmp:0.1.1 returns 200 from repo1.maven.org (lastUpdated 20260810130716), with platform artifacts for android, iosarm64, iossimulatorarm64, iosx64. The search.maven.org Solr index returns nothing — index lag only, not a resolution problem. Worth knowing, since a search-based check would have looked like the Web SDK trap repeating.
  • SPM half is real too. The 0.1.1 SuperwallKMPBridge.xcframework.zip release asset (9,963,736 bytes) has SHA-256 eec4f35…13e2f, matching Package.swift:59 and the published .checksum asset exactly.
  • Release vs main: identical. The 0.1.1 annotated tag object (b5c56c4) points at commit 8727bcf, which is main; both 0.1.1..main and main..0.1.1 are empty. These docs describe the 0.1.1 release, which is also HEAD.

Structure

Follows the Web SDK precedent: standalone pages, registration limited to the root meta.json.

Pages deliberately do not <include> content/shared/**. plugins/remark-sdk-filter.ts:14 matches only /(ios|android|expo|flutter)/, so on a /kmp/ page the filter no-ops and every platform's :::ios / :::android block would render at once. Adding kmp to that regex instead would strip the shared pages to near-empty, since no :::kmp blocks exist.

Verified against source, not assumed from the Android docs

Ian's "basically one-to-one" held for the API surface but not the integration story. Divergences found and documented:

Claim Evidence
KMP declares SuperwallPaywallActivity itself — no manifest edits needed, unlike the Android SDK's install page superwall-kmp/src/androidMain/AndroidManifest.xml; superwall-android superwall/src/main/AndroidManifest.xml declares only 3 permissions, no activities
minSdk 26, not the Android SDK's 23 gradle/libs.versions.toml:5 vs superwall-android superwall/build.gradle.kts:34
No Context param; Superwall.androidSetup(application) is the escape hatch if the startup provider is stripped androidMain/.../SuperwallInitializer.kt, androidMain/.../AndroidSetup.kt:37
Debug/preview activities declared in neither library manifest both manifests above; DebugViewActivity is internal at superwall-android debug/DebugView.kt:917
iOS needs isStatic = true — compile-only cinterop, so a missing bridge is a link error at app build time, not a runtime failure superwall-kmp/build.gradle.kts:75-84 uses compilerOpts, not linkerOpts; Package.swift header
handleSuperwallDeepLink is genuinely iOS-only androidMain/.../adapters/DelegateAdapter.kt:38-39,255-257; absent from superwall-android delegate/SuperwallDelegate.kt
consume is Android; iOS echoes the token back commonMain/Superwall.kt:523
IntegrationAttribute.FIREBASE_INSTALLATION_ID is iOS-only commonMain/models/events/IntegrationAttribute.kt:39; skip site AndroidSuperwallBridge.kt:305-315

⚠️ The SDK's own KDoc is stale — please confirm

Four members carry @platform iOS / "pending upstream support in superwall-android" annotations that no longer hold. The Android bridge calls the real native APIs, and superwall-android 2.8.0 has all of them:

Member Stale KDoc Android reality Native API
getCustomerInfo() Superwall.kt:390-391 "synthesized minimal value" AndroidSuperwallBridge.kt:383 real call Superwall.kt:281
getEntitlementsByProductIds() Superwall.kt:341 "local-filters" AndroidSuperwallBridge.kt:363 real call store/Entitlements.kt:213
customerInfoDidChange SuperwallDelegate.kt:167 DelegateAdapter.kt:246-253 wired delegate/SuperwallDelegate.kt:49
customerInfoFlow Superwall.kt:381 fed via DelegateMultiplexer.kt:115-121

The bridge's own comments call the old stubs "obsolete" (AndroidSuperwallBridge.kt:59,61,380) — the caveats were describing the Flutter host's behavior. The docs describe the working behavior and flag the discrepancy. The rot is wider: StreamHolder.kt:47-48 and commonMain/internal/SuperwallBridge.kt:127,136,282,295 carry the same stale notes. Also README.md:79 claims minSdk 26 "matching the native superwall-android SDK", but that SDK is 23.

Claim audit

A clean-context reviewer audited every falsifiable claim against the KMP and superwall-android sources. Findings verified independently before fixing (commit 4695d7a):

  1. transactionBackgroundView was wrongly listed iOS-onlysuperwall-android has it (PaywallOptions.kt:109,138) and the KMP mapper wires it (OptionsMapper.kt:87-91). The page had copied a stale KDoc marker.
  2. Two genuinely iOS-only options were missing from the "complete list": shouldShowWebRestorationAlert, shouldShowWebPurchaseConfirmationAlert (OptionsMapper.kt:94-96). Neither has an "iOS only" KDoc marker, which is why they were missed.
  3. Threading over-claimed. Logger.log calls handleLog inline before the shouldPrint check (superwall-android logger/Logger.kt:50), and track() adds no dispatcher hop (analytics/internal/Tracking.kt:37) — so both run on the caller's thread, main included. Now documented as not guaranteed rather than "background".
  4. subscriptionStatusFlow does not force main. It is a bare MutableStateFlow (StreamHolder.kt:41-42); a StateFlow delivers on the collector's context. Reworded to say collect from a main-dispatched scope. The SDK KDoc makes the same loose claim.

One reviewer finding was declined: icon="History" is valid — an explicit key in src/lib/grid-icons.ts:121, not a PascalCase fallback.

Changelog verified byte-identical to upstream CHANGELOG.md apart from frontmatter, per repo convention. All 15 internal links and both anchors resolve.

Verification

  • bun run build:cf — exit 0, all 13 KMP pages prerendered, no KMP errors or warnings
  • bun test — 64 pass, 0 fail
  • git diff --check — clean
  • Every page checked on the local preview

Not done here

  • kmp is not registered in src/lib/sdk-navigation.ts, search.shared.ts, sdk-options.ts, llms.ts, or sitemap.ts — so no search facet, SDK-selector entry, llms.txt, or sitemap entry. unity and web are equally absent (SdkSlug is ios | android | flutter | expo | react-native), so this is a pre-existing gap across three sections, not a KMP regression. Closing it changes shared app behavior for all three and belongs in its own PR.
  • No icon in content/docs/kmp/meta.json — there is no Kotlin/KMP mark in grid-icons.ts, and the Web SDK ships the same way.
  • In-app paywall previews on Android are not verified end-to-end. The docs give the manifest snippet and say plainly that the path is unverified.
  • .claude/launch.json will conflict with jordan/sw-5720-web-sdk-docs, which adds the same file. Trivial to resolve.

🤖 Generated with Claude Code

DreamingInBinary and others added 3 commits August 11, 2026 15:51
Adds content/docs/kmp for the Superwall KMP SDK (0.1.1, beta), registered
under the SDKs group in the root meta.json.

Pages are written standalone rather than reusing content/shared, because
remark-sdk-filter only matches (ios|android|expo|flutter) — a /kmp/ page
would no-op the filter and render every platform's blocks at once.

Behavior is verified against the KMP source rather than ported blindly from
the Android docs; the notable divergences (library-declared paywall activity,
minSdk 26, the isStatic requirement, the SPM bridge, delegate threading) are
documented in guides/platform-differences.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
A clean-context claim audit against the KMP and superwall-android sources
turned up four wrong or incomplete claims, all verified independently before
changing anything:

- transactionBackgroundView was listed iOS-only. superwall-android has it
  (PaywallOptions.kt:109,138) and the KMP mapper wires it
  (OptionsMapper.kt:87-91) — the docs had copied a stale KDoc marker.
- shouldShowWebRestorationAlert and shouldShowWebPurchaseConfirmationAlert
  are genuinely iOS-only and were missing from the "complete list". Neither
  carries an "iOS only" KDoc marker, which is why they were missed.
- handleLog and handleSuperwallEvent were stated as unconditionally
  background on Android. Logger.log calls handleLog inline before the
  shouldPrint check, and track() adds no dispatcher hop, so both run on the
  caller's thread — main included. Now documented as not guaranteed.
- subscriptionStatusFlow was said to emit on main. It is a bare
  MutableStateFlow; a StateFlow delivers on the collector's context.

Also documents the manifest-merger conflict that hits apps migrating from
the standalone Android SDK, which declares the same activity with a
different theme.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Final cleanup pass. The temporary yellow review containers are converted to
the proper MDX callout components; the wrapped prose is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Aug 11, 2026

Copy link
Copy Markdown

SW-5718

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 11, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
superwall-docs e84a039 Commit Preview URL

Branch Preview URL
Aug 14 2026, 08:02 PM

DreamingInBinary and others added 7 commits August 12, 2026 13:41
Adds the Xcode "Add Package Dependencies" screenshot to the iOS half of the
install page — the only purely visual step in the section, and the one most
likely to be done wrong.

Lives under content/docs/images/kmp/ rather than a per-section images folder,
since copy-docs-images.cjs only mirrors content/docs/images/** into public/.

The screenshot shows Xcode's default Dependency Rule (Up to Next Major), so a
note under it explains why to pin Exact Version while the SDK is in beta: the
bridge binary and the Kotlin klib ship from one tag, and SPM drifting ahead of
the version the shared module was built against is what breaks the link step.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The 'Getting the right API key' section assumed the reader knew what
expect/actual meant and named mechanisms instead of showing one. Rewritten
to state the actual situation (two dashboard apps, two keys, one shared
call site) and show the expect/actual pattern as code. The install page's
version of the same advice now links there instead of repeating it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@DreamingInBinary
DreamingInBinary merged commit f9903fb into main Aug 14, 2026
2 checks passed
@DreamingInBinary
DreamingInBinary deleted the jordan/sw-5718-kmp-docs branch August 14, 2026 20:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant