Skip to content

feat(billing): auto-wire native Play/StoreKit client — commonMain-only consumer integration - #126

Merged
therajanmaurya merged 1 commit into
MobileByteLabs:developmentfrom
therajanmaurya:development
Jul 25, 2026
Merged

feat(billing): auto-wire native Play/StoreKit client — commonMain-only consumer integration#126
therajanmaurya merged 1 commit into
MobileByteLabs:developmentfrom
therajanmaurya:development

Conversation

@therajanmaurya

@therajanmaurya therajanmaurya commented Jul 25, 2026

Copy link
Copy Markdown
Collaborator

Auto-wire native billing — consumers integrate in commonMain only

Makes the native in-app-purchase client resolve per platform automatically, so a consumer gets real Google Play Billing on Android with ZERO androidMain wiring — just PayCraft.initialize(apiKey) from commonMain. Previously consumers had to load paycraftPlayBillingModule + supply an activityProvider in their Application (a platform-specific bootstrap leak that defeats the KMP one-line-setup goal, and that left web checkout as the Android default → the anti-steering Play-policy violation that flagged com.sensei.social).

How

  • platformDefaultNativeBillingClient() — new expect (commonMain) + actual per platform:
    • Android → the real PlayBillingNativeClient (Play Billing v8), auto-wired from the Application context + foreground Activity.
    • iOS / JVM / JS / WasmJS → null → web checkout (iOS StoreKit2 stays an explicit opt-in since it needs the app's Swift bridge).
  • PayCraftModule now binds single<NativeBillingClient> { platformDefaultNativeBillingClient() ?: WebCheckoutNativeBillingClient() } (was hard-coded WebCheckout).
  • PayCraftInitializer (the existing androidx-startup Initializer that already captures the Application context) now ALSO registers foreground-Activity tracking, so launchBillingFlow resolves the resumed Activity with no consumer plumbing.
  • PayCraftPlatform.android gains applicationContextOrNull() + WeakReference-based currentActivityOrNull() / startActivityTracking().

paycraftPlayBillingModule / paycraftStoreKit2BillingModule remain as explicit overrides (custom activityProvider, or a consumer who disabled the Initializer).

Verified

BUILD SUCCESSFUL compiling androidMain + iosSimulatorArm64 + jvm + js + wasmJs, and a new jvmTest asserts the web-platform fallback (platformDefaultNativeBillingClient() == null → WebCheckout).

Follow-up (separate)

Publish as 2.3.0, then reels-downloader drops its explicit AndroidApp.kt wiring and just bumps the version.

Summary by CodeRabbit

  • New Features

    • Android now automatically detects the active foreground screen for billing flows.
    • Android uses native in-app billing by default when available.
    • Added platform-aware billing selection across Android, iOS, web, desktop, and JVM.
  • Bug Fixes

    • Web, desktop, and iOS environments now reliably fall back to web checkout when native billing is unavailable.
  • Tests

    • Added coverage confirming JVM environments use web checkout fallback.

…ytelabs/paycraft/PayCraftInitializer.kt cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt
@vercel

vercel Bot commented Jul 25, 2026

Copy link
Copy Markdown

@therajanmaurya is attempting to deploy a commit to the MobileByteLabs' projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 25, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 07f0e40f-7804-4bc4-b906-b1ea008ac7ce

📥 Commits

Reviewing files that changed from the base of the PR and between 590170f and e8f3fc0.

📒 Files selected for processing (10)
  • cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt
  • cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt
  • cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.android.kt
  • cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.kt
  • cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt
  • cmp-paycraft/src/iosMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.ios.kt
  • cmp-paycraft/src/jsMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.js.kt
  • cmp-paycraft/src/jvmMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.jvm.kt
  • cmp-paycraft/src/jvmTest/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClientJvmTest.kt
  • cmp-paycraft/src/wasmJsMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.wasmJs.kt

📝 Walkthrough

Walkthrough

Changes

Native billing auto-wiring

Layer / File(s) Summary
Platform billing contract
cmp-paycraft/src/commonMain/..., cmp-paycraft/src/iosMain/..., cmp-paycraft/src/jsMain/..., cmp-paycraft/src/jvmMain/..., cmp-paycraft/src/wasmJsMain/...
Defines a nullable platform billing factory; non-Android targets return null.
Android activity-aware billing
cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt, cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt, cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClient.android.kt
Tracks the resumed Android Activity through lifecycle callbacks and constructs Play Billing with the application context and current Activity provider.
Billing DI resolution
cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt, cmp-paycraft/src/jvmTest/kotlin/com/mobilebytelabs/paycraft/billing/PlatformNativeBillingClientJvmTest.kt
Selects the platform billing client when available, otherwise uses web checkout; tests the JVM null default.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Startup as PayCraftInitializer
  participant Platform as PayCraftPlatform
  participant Billing as PlayBillingNativeClient
  Startup->>Platform: Start Activity lifecycle tracking
  Platform->>Platform: Store resumed Activity weak reference
  Billing->>Platform: Request application context and Activity
  Platform-->>Billing: Provide Android billing inputs
Loading
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@therajanmaurya
therajanmaurya marked this pull request as ready for review July 25, 2026 09:41
@therajanmaurya
therajanmaurya merged commit 095369f into MobileByteLabs:development Jul 25, 2026
6 of 8 checks passed
therajanmaurya added a commit that referenced this pull request Aug 2, 2026
* fix(dashboard): surface Google Play + App Store on the Providers list (#123)

The store-sync credential pages (/providers/google-play, /providers/app-store)
shipped in 2.2.0 but were never linked from the Providers index (only web PSPs
render there), so they were unreachable. Adds an 'In-app billing (native app
stores)' section with Connect/Manage cards + live connection status.

* fix(dashboard): surface store sync in products UI (bulk + badges + Re-sync feedback) (#124)

* fix(dashboard): surface Google Play + App Store on the Providers list (#123)

The store-sync credential pages (/providers/google-play, /providers/app-store)
shipped in 2.2.0 but were never linked from the Providers index (only web PSPs
render there), so they were unreachable. Adds an 'In-app billing (native app
stores)' section with Connect/Manage cards + live connection status.

* fix(dashboard): surface store sync in products UI (bulk + badges + Re-sync)

Closes the two store-sync UI gaps from 2.2.0:
- Bulk 'sync-to-providers' now includes Google Play + App Store.
- Products table shows Play / App Store badges; per-product Re-sync panel +
  unsynced banner + sync panel surface store connection/results.
Matches the /sync route snake_case keys (google_play/app_store). tsc clean.

* chore(source): update .github/workflows/deploy-cloud.yml dashboard/app/api/products/[id]/sync/route.ts dashboard/app/api/products/sync-to-providers/route.ts

* chore(source): update dashboard/__tests__/lib/googleplay-product-sync.test.ts dashboard/app/api/products/[id]/sync/route.ts dashboard/app/api/products/sync-to-providers/route.ts

* chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt (#126)

* chore(release): bump paycraft 2.2.0 → 2.3.0 (commonMain-only native billing) (#127)

* chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftInitializer.kt cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/PayCraftPlatform.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/di/PayCraftModule.kt

* chore(source): update gradle.properties

* feat paywall currency fix native store price and usd fallback (#128)

* chore: initialize session branch — feat paywall currency fix native store price and usd fallback

* chore(source): update cmp-paycraft/src/androidMain/kotlin/com/mobilebytelabs/paycraft/billing/PlayBillingNativeClient.android.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CurrencyResolver.kt cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/PayCraft.kt

* fix(billing): resolve CI blockers on native-billing PR — Android getBillingConfig + ktlint

- PlayBillingNativeClient.android: billing-ktx v8 has no suspend getBillingConfig extension;
  rewrite storefrontCountry() with the callback getBillingConfigAsync wrapped in
  suspendCancellableCoroutine (fixes 'unresolved reference getBillingConfig' + type inference)
- PayCraft.kt: drop leading underscore on two purely-private vars (nativePricesBySku,
  currentSuite) that have no matching public member — ktlint standard:backing-property-naming
  was aborting spotless with an AssertionError
- spotless reformat of touched files

Verified green locally: spotlessCheck, :cmp-paycraft:compileAndroidMain,
:cmp-paycraft:compileKotlinIosSimulatorArm64 (native StoreKit2), :cmp-paycraft:jvmTest.

* chore: initialize session branch — chore(paycraft): reconcile + close v2 production-readiness epic (OBE by 2.3.x)

* chore(source): update .gitignore CHANGELOG.md cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CurrencyResolver.kt

* chore(source): update cmp-paycraft/src/commonMain/kotlin/com/mobilebytelabs/paycraft/CountryDetector.kt

* chore: initialize session branch — fix(auth): multi-tenant login callback redirect + ship platform-provider epic dashboard

* chore(source): update dashboard/app/auth/callback/route.ts supabase/.temp/cli-latest

---------

Co-authored-by: MobileByteSensei Community <mobilebytesensei@gmail.com>
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