Subscriptions Guide
Add auto-renewing subscriptions to your B4X app. Same cross-platform API for Google Play and App Store. Read the Getting Started guide first if you haven't set up the library yet.
Create subscriptions in the store
Before writing any code, create your subscription products in the store console:
Android: Google Play Console → Your app → Monetize → Subscriptions → Create subscription. Add a base plan (e.g. monthly-plan) with your pricing and billing period. See the Android App Setup guide for details.
iOS: App Store Connect → Your app → Subscriptions → Create a Subscription Group (e.g. "Premium") → Add subscriptions within the group. Configure duration, price, and localisation. See the iOS App Setup guide for details.
Use the same Product ID across both platforms (e.g. premium_monthly) so your code works unchanged on Android and iOS. The library handles platform detection automatically.
Android: add Google Play Billing to your manifest
In B4A, go to Project → Manifest Editor and add:
CreateResourceFromFile(Macro, GooglePlayBilling.GooglePlayBilling)Without this, purchases will fail on Android. iOS requires no manifest changes.
Add subscription products
After initializing the library, register your subscription plans:
' Add subscription plans
PurchaseManager.AddSubscription("premium_monthly", "monthly-plan", _
"Monthly Premium", "Full access, billed monthly", "Monthly")
PurchaseManager.AddSubscription("premium_yearly", "yearly-plan", _
"Yearly Premium", "Full access, billed yearly — save 40%", "Yearly")ProductId — must match what you created in the store (e.g. premium_monthly)
BasePlanId — the base plan ID from Google Play Console (ignored on iOS)
Title — displayed on the subscription screen
Description — short description shown below the title
BillingPeriod — display label (e.g. "Monthly", "Yearly", "Weekly")
Set policy properties
Apple requires a visible privacy policy and terms of service on subscription screens. The library includes built-in templates — set these properties so they display your details correctly:
' Set these before showing any subscription screen PurchaseManager.PolicyCompanyName = "My Company" PurchaseManager.PolicyEmailAddress = "[email protected]" PurchaseManager.PolicyEffectiveDate = "January 1, 2025"
If left empty, the built-in templates use these fallbacks (and a warning is logged in the IDE on each app start):
| Property | Fallback when empty |
|---|---|
| PolicyCompanyName | "This company" |
| PolicyEmailAddress | mailto link replaced with plain text "contact us." |
| PolicyEffectiveDate | A default date set in the library (updated each release) |
You can also supply your own policy URLs or HTML via CustomPrivacyPolicySubscription and CustomTermsOfService instead of using the built-in templates. To use the built-in templates as a starting point, call ExportPrivacyPolicySubscription or ExportTermsOfService to output the rendered HTML to the IDE log.
Show the subscription screen
One line to show the built-in subscription screen with plan cards, pricing, and store payment flow:
Wait For (PurchaseManager.ShowSubscriptionPurchase) Complete (Success As Boolean)
The user picks a plan, completes payment through the native store UI, and the receipt is validated server-side. You get back True if the subscription was activated successfully.
Private Sub btnSubscribe_Click
Wait For (PurchaseManager.ShowSubscriptionPurchase) Complete (Success As Boolean)
If Success Then
Log("Subscribed! Plan: " & PurchaseManager.GetActiveSubscriptionId)
UpdateUIForSubscriber
End If
End SubCheck subscription status
Check whether the user has an active subscription anywhere in your app. This reads from the local cache — it's instant, no network call:
If PurchaseManager.IsSubscriptionActive Then
' User is subscribed — show premium content
Log("Active plan: " & PurchaseManager.GetActiveSubscriptionId)
Log("Expires: " & DateTime.Date(PurchaseManager.GetSubscriptionExpiryDate))
Else
' No active subscription — show upgrade prompt
End IfCall CheckStatus on app start or page appear to load the latest cached status (and trigger a background refresh if the cache has expired):
PurchaseManager.CheckStatus
If PurchaseManager.IsSubscriptionActive Then
' Active (from cache)
End IfIf you need an immediate live validation (e.g. a manual "Refresh Status" button), use ValidateNow — this bypasses the cache and costs 1 credit:
Wait For (PurchaseManager.ValidateNow) Complete (Success As Boolean)
If Success And PurchaseManager.IsSubscriptionActive Then
' Confirmed active — live from server
End IfRenewals and cancellations
You don't need to handle renewals or cancellations manually. The library re-validates subscription status with the server every 24 hours while the app is in use:
• Renewal — status stays active automatically. No code needed.
• Cancellation — access continues until the billing period ends, then IsSubscriptionActive returns False on the next validation.
• Grace period — if the store grants a grace period (payment retry), the subscription remains active during that window.
Customize the subscription screen (optional)
Add feature cards and theming to make the subscription screen match your app:
' Add feature highlights shown on the subscription screen
PurchaseManager.AddFeature("🎨", "Premium Themes", "Access all premium themes")
PurchaseManager.AddFeature("🚀", "Advanced Features", "Unlock powerful tools")
PurchaseManager.AddFeature("☁️", "Cloud Sync", "Sync across all your devices")
' Optional: custom colors (Primary, Secondary, Accent, Background1, Background2)
PurchaseManager.SetThemeColors(0xFF6200EE, 0xFF03DAC5, 0xFFBB86FC, 0xFF121212, 0xFF1E1E1E)
' Optional: override the app name on the subscription screen
PurchaseManager.DisplayAppName = "My App Pro"Custom UI (optional)
If you want to build your own subscription screen instead of using the built-in one, use PurchaseSubscription to trigger the purchase directly:
' Purchase a specific plan directly (for custom UI)
Wait For (PurchaseManager.PurchaseSubscription("premium_monthly", "monthly-plan")) _
Complete (Success As Boolean)
If Success Then
Log("Subscription activated!")
End IfThis skips the built-in screen and goes straight to the native store payment flow for the specified plan.
Restore subscriptions
If a user reinstalls the app or switches devices, restore their subscription:
Wait For (PurchaseManager.RestoreSubscriptions) Complete (Success As Boolean)
If Success Then
Log("Subscription restored!")
End IfApple requires a visible "Restore Purchases" option. The built-in b4xlib screens include one automatically. If you build your own custom purchase UI, make sure to add a restore button that calls RestoreSubscriptions.
Complete example
Putting it all together — a typical subscription setup:
Private PurchaseManager As B4XPurchaseManager
Private Const BILLING_KEY As String = "MIIBIjANBgkq..." ' Google Play license key (ignored on iOS)
Private Const APP_ID As String = "my-app"
Private Const API_KEY As String = "bpm_your_key_here"
Private Sub B4XPage_Created (Root1 As B4XView)
Root = Root1
Root.LoadLayout("MainPage")
' Initialize
PurchaseManager.Initialize(Root, BILLING_KEY, APP_ID, API_KEY)
PurchaseManager.DisplayAppName = "My App"
' Policy properties for built-in privacy policy & terms
PurchaseManager.PolicyCompanyName = "My Company"
PurchaseManager.PolicyEmailAddress = "[email protected]"
PurchaseManager.PolicyEffectiveDate = "January 1, 2025"
' Add features shown on the subscription screen
PurchaseManager.AddFeature("🎨", "Premium Themes", "Access all premium themes")
PurchaseManager.AddFeature("🚀", "Advanced Features", "Unlock powerful tools")
' Add subscription plans
PurchaseManager.AddSubscription("premium_monthly", "monthly-plan", _
"Monthly Premium", "Full access, billed monthly", "Monthly")
PurchaseManager.AddSubscription("premium_yearly", "yearly-plan", _
"Yearly Premium", "Full access, billed yearly — save 40%", "Yearly")
' Check status on launch
PurchaseManager.CheckStatus
If PurchaseManager.IsSubscriptionActive Then
UpdateUIForSubscriber
End If
End Sub
Private Sub B4XPage_Appear
' Re-check on each page appear (catches renewals/cancellations)
PurchaseManager.CheckStatus
If PurchaseManager.IsSubscriptionActive Then
UpdateUIForSubscriber
End If
End Sub
Private Sub btnSubscribe_Click
Wait For (PurchaseManager.ShowSubscriptionPurchase) Complete (Success As Boolean)
If Success Then
UpdateUIForSubscriber
End If
End Sub
Private Sub btnRestore_Click
Wait For (PurchaseManager.RestoreSubscriptions) Complete (Success As Boolean)
If Success Then
UpdateUIForSubscriber
End If
End Sub
Private Sub UpdateUIForSubscriber
btnSubscribe.Visible = False
lblStatus.Text = "Premium active until " & _
DateTime.Date(PurchaseManager.GetSubscriptionExpiryDate)
End Sub