KMP-IAP 1.0.0-rc.4 marks a major milestone with the OpenIAP monorepo conversion and introduces Alternative Billing support for both iOS and Android platforms.
๐ View the 1.0.0-rc.4 release
๐ฏ Major Changesโ
OpenIAP Monorepo Conversionโ
KMP-IAP now fully integrates with the OpenIAP monorepo, centralizing all in-app purchase implementations under one standardized specification. This conversion brings:
- Unified dependency management through
openiap-versions.json - 100% OpenIAP specification compliance across all platforms
- Centralized version control for iOS, Android, and GraphQL types
- Simplified maintenance with single source of truth
Current OpenIAP versions:
- openiap-apple: 1.2.26 (iOS StoreKit wrapper with external purchase support)
- openiap-google: 1.3.2 (Android BillingClient wrapper with alternative billing)
- openiap-gql: 1.2.2 (GraphQL type definitions)
All native SDKs are now maintained in the OpenIAP monorepo, ensuring consistent APIs and behavior across platforms.
๐ New Featuresโ
iOS Alternative Billing (StoreKit External Purchase)โ
Three new APIs for managing external purchases on iOS:
canPresentExternalPurchaseNoticeIOS()- Check if the notice sheet is available (iOS 18.2+)presentExternalPurchaseNoticeSheetIOS()- Present a notice before redirecting to external purchase (iOS 18.2+)presentExternalPurchaseLinkIOS(url)- Open external purchase link in Safari (iOS 16.0+)
iOS Configuration Required:
Info.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<!-- Countries where external purchases are supported -->
<key>SKExternalPurchase</key>
<array>
<string>kr</string>
<string>nl</string>
<string>de</string>
</array>
</dict>
</plist>
Entitlements (iosApp.entitlements):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.storekit.external-purchase</key>
<true/>
<key>com.apple.developer.storekit.external-purchase-link</key>
<true/>
</dict>
</plist>
Usage Example:
import io.github.hyochan.kmpiap.kmpIapInstance
// Redirect user to external purchase website
val result = kmpIapInstance.presentExternalPurchaseLinkIOS(
url = "https://your-site.com/checkout"
)
if (result.success) {
println("User redirected to external website")
} else {
println("Error: ${result.error}")
}
Android Alternative Billingโ
Three new APIs for Google Play Alternative Billing flow:
checkAlternativeBillingAvailabilityAndroid()- Check if alternative billing is available for the usershowAlternativeBillingDialogAndroid()- Show Google's required information dialogcreateAlternativeBillingTokenAndroid()- Generate reporting token after successful payment
Configuration Support:
import io.github.hyochan.kmpiap.kmpIapInstance
import io.github.hyochan.kmpiap.openiap.AlternativeBillingModeAndroid
import io.github.hyochan.kmpiap.openiap.InitConnectionConfig
// Initialize with alternative billing mode
val config = InitConnectionConfig(
alternativeBillingModeAndroid = AlternativeBillingModeAndroid.UserChoice
// Or: AlternativeBillingModeAndroid.AlternativeOnly
)
val connected = kmpIapInstance.initConnection(config)
Two Billing Modes:
UserChoice- Users choose between Google Play billing (30% fee) or your payment system (lower fee)AlternativeOnly- Only your payment system is available (Google Play billing disabled)
User Choice Mode Example:
import io.github.hyochan.kmpiap.kmpIapInstance
import kotlinx.coroutines.flow.collect
// Initialize with user-choice mode
val config = InitConnectionConfig(
alternativeBillingModeAndroid = AlternativeBillingModeAndroid.UserChoice
)
kmpIapInstance.initConnection(config)
// Listen for when user selects alternative billing
scope.launch {
kmpIapInstance.userChoiceBillingListener.collect { details ->
println("User selected alternative billing")
println("Products: ${details.products}")
// Process payment in your system, then report token to Google
processPaymentAndReportToken(details)
}
}
Alternative Only Mode Example:
// Step 1: Check availability
val isAvailable = kmpIapInstance.checkAlternativeBillingAvailabilityAndroid()
// Step 2: Show Google's information dialog
val userAccepted = kmpIapInstance.showAlternativeBillingDialogAndroid()
if (userAccepted) {
// Step 3: Process payment in your system, then create token
val token = kmpIapInstance.createAlternativeBillingTokenAndroid()
// Step 4: Report token to Google Play backend within 24 hours
reportTokenToGooglePlay(token)
}
๐จ Alternative Billing Demo Screenโ
A complete alternative billing demo screen has been added to the example app:
- Platform-specific flows - Demonstrates iOS and Android alternative billing patterns
- Billing mode toggle (Android) - Switch between
AlternativeOnlyandUserChoicewith auto-reconnect - External URL input (iOS) - Configure and test external purchase links
- Real-time results - View purchase flow status and responses
- Step-by-step guidance - Visual flow diagrams for both platforms
Navigate to example/composeApp/src/commonMain/kotlin/dev/hyo/martie/screens/AlternativeBillingScreen.kt to explore the implementation.
๐ Bug Fixes & Improvementsโ
Serialization Error Fixโ
Fixed a critical serialization issue in AvailablePurchasesScreen where PurchaseIOS and PurchaseAndroid objects couldn't be serialized directly. Now uses the Purchase.toJson() method for proper JSON serialization.
Before:
// This would throw SerializationException
val jsonString = json.encodeToString(purchase)
After:
// Uses the built-in toJson() method
val purchaseMap = purchase.toJson()
val jsonString = buildJsonString(purchaseMap)
iOS Subscription Enhancementsโ
Added renewalInfoIOS field to activeSubscription (openiap-apple 1.2.24+), providing access to subscription renewal information including:
- Auto-renew status
- Expiration reason
- Grace period status
- Offer information
โ ๏ธ Platform Requirementsโ
iOSโ
- Minimum Version: iOS 16.0+ for external purchase links, iOS 18.2+ for notice sheet
- App Store Connect: Must request and receive approval for external purchase entitlements
- Provisioning Profile: Must include StoreKit external purchase entitlements
- See StoreKit External Purchase documentation
Androidโ
- Google Play Console: Must be approved for alternative billing program
- Token Reporting: Must report tokens to Google within 24 hours
- Backend Integration: Server-side validation and reporting required
- See Google Play Alternative Billing documentation
๐ฆ Installationโ
Gradle (Kotlin DSL)โ
// shared/build.gradle.kts
kotlin {
sourceSets {
commonMain.dependencies {
implementation("io.github.hyochan:kmp-iap:1.0.0-rc.4")
}
}
}
Gradle (Groovy)โ
// shared/build.gradle
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'io.github.hyochan:kmp-iap:1.0.0-rc.4'
}
}
}
}
Version Catalog (libs.versions.toml)โ
[versions]
kmp-iap = "1.0.0-rc.4"
[libraries]
kmp-iap = { module = "io.github.hyochan:kmp-iap", version.ref = "kmp-iap" }
Then sync your Gradle project.
๐จ Important Notesโ
For iOS Developersโ
Alternative billing on iOS requires explicit approval from Apple. During development:
- Configure entitlements and Info.plist as shown above
- Test regular IAP flows without external purchase features
- When ready for production, follow Apple's approval process for external purchase entitlements
For Android Developersโ
Alternative billing on Android requires:
- Approval from Google Play Console for the alternative billing program
- Backend integration to report tokens within 24 hours
- Proper error handling for users not eligible for alternative billing
No Breaking Changes: All changes are additive. Existing apps will continue to work without modifications.
๐ Documentation Updatesโ
This release includes comprehensive documentation:
- Alternative Billing Guide - Complete guide for implementing alternative billing
- Alternative Billing Example - Full code examples for both platforms
- Core Methods - Alternative Billing APIs - API reference
- OpenIAP Specification - Official specification and terminology
