Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions packages/apple/Sources/Models/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,17 @@ public enum FetchProductsResult {
case subscriptions([ProductSubscription]?)
}

/// Pre-order details for one-time purchase products (Android)
/// Available in Google Play Billing Library 8.1.0+
public struct PreorderDetailsAndroid: Codable {
/// Pre-order presale end time in milliseconds since epoch.
/// This is when the presale period ends and the product will be released.
public var preorderPresaleEndTimeMillis: String
/// Pre-order release time in milliseconds since epoch.
/// This is when the product will be available to users who pre-ordered.
public var preorderReleaseTimeMillis: String
}

public struct PricingPhaseAndroid: Codable {
public var billingCycleCount: Int
public var billingPeriod: String
Expand Down Expand Up @@ -407,6 +418,9 @@ public struct ProductAndroid: Codable, ProductCommon {

public struct ProductAndroidOneTimePurchaseOfferDetail: Codable {
public var formattedPrice: String
/// Pre-order details for products available for pre-order (Android)
/// Available in Google Play Billing Library 8.1.0+
public var preorderDetailsAndroid: PreorderDetailsAndroid?
public var priceAmountMicros: String
public var priceCurrencyCode: String
}
Expand Down Expand Up @@ -488,6 +502,12 @@ public struct PurchaseAndroid: Codable, PurchaseCommon {
public var ids: [String]?
public var isAcknowledgedAndroid: Bool?
public var isAutoRenewing: Bool
/// Whether the subscription is suspended (Android)
/// A suspended subscription means the user's payment method failed and they need to fix it.
/// Users should be directed to the subscription center to resolve the issue.
/// Do NOT grant entitlements for suspended subscriptions.
/// Available in Google Play Billing Library 8.1.0+
public var isSuspendedAndroid: Bool?
public var obfuscatedAccountIdAndroid: String?
public var obfuscatedProfileIdAndroid: String?
public var packageNameAndroid: String?
Expand Down
32 changes: 31 additions & 1 deletion packages/docs/src/pages/docs/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,18 @@ function Types() {
For one-time purchases. Contains:{' '}
<code>formattedPrice</code>,{' '}
<code>priceAmountMicros</code> (divide by 1,000,000),{' '}
<code>priceCurrencyCode</code>
<code>priceCurrencyCode</code>,{' '}
<code>preorderDetailsAndroid</code> (for pre-order
products, contains <code>preorderPresaleEndTimeMillis</code>{' '}
and <code>preorderReleaseTimeMillis</code> -{' '}
<a
href="https://developer.android.com/google/play/billing/release-notes#8-1-0"
target="_blank"
rel="noopener noreferrer"
>
Billing Library 8.1.0+
</a>
)
</td>
</tr>
<tr>
Expand Down Expand Up @@ -1167,6 +1178,25 @@ function Types() {
</td>
<td>Obfuscated profile ID you provided</td>
</tr>
<tr>
<td>
<code>isSuspendedAndroid</code>
</td>
<td>
Whether the subscription is suspended due to payment
failure. Suspended subscriptions should NOT grant
entitlements - direct users to the subscription center
to resolve payment issues. (
<a
href="https://developer.android.com/google/play/billing/release-notes#8-1-0"
target="_blank"
rel="noopener noreferrer"
>
Billing Library 8.1.0+
</a>
)
</td>
</tr>
</tbody>
</table>
</>
Expand Down
153 changes: 146 additions & 7 deletions packages/docs/src/pages/docs/updates/notes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,93 @@ function Notes() {
<section>
<h2>📝 API & Terminology Changes</h2>

<div
style={{
background: 'var(--bg-secondary)',
border: '1px solid var(--border-color)',
borderRadius: '0.5rem',
padding: '1rem',
marginBottom: '1.5rem',
}}
>
<h4 style={{ marginTop: 0, color: 'var(--text-primary)' }}>
📅 openiap-google v1.3.11 / openiap-gql v1.3.1 -{' '}
<a
href="https://developer.android.com/google/play/billing/release-notes#8-1-0"
target="_blank"
rel="noopener noreferrer"
>
Google Play Billing 8.1.0
</a>{' '}
Support
</h4>
<p>
<strong>Google Play Billing Library Upgrade:</strong>
</p>
<ul>
<li>
<strong>
<a
href="https://developer.android.com/google/play/billing/release-notes#8-1-0"
target="_blank"
rel="noopener noreferrer"
>
Billing Library 8.0.0 → 8.1.0
</a>
</strong>{' '}
- Upgraded to latest Google Play Billing Library
</li>
<li>
<strong>minSdk 21 → 23</strong> - Minimum SDK increased to Android
6.0 (Marshmallow) as required by Billing Library 8.1.0
</li>
<li>
<strong>Kotlin 2.0.21 → 2.2.0</strong> - Upgraded Kotlin version
for compatibility
</li>
</ul>
<p>
<strong>New Features:</strong>
</p>
<ul>
<li>
<strong>isSuspendedAndroid</strong> - New field on{' '}
<code>PurchaseAndroid</code> to detect suspended subscriptions due
to payment failures. Suspended subscriptions should NOT grant
entitlements - direct users to the subscription center to resolve
payment issues.
</li>
<li>
<strong>PreorderDetailsAndroid</strong> - New type for pre-order
products. Contains <code>preorderPresaleEndTimeMillis</code> and{' '}
<code>preorderReleaseTimeMillis</code> for scheduling pre-order
availability.
</li>
</ul>
<CodeBlock language="kotlin">
{`// Handling suspended subscriptions
val purchase = getAvailablePurchases()
if (purchase.isSuspendedAndroid == true) {
// ❌ Do NOT grant entitlements
// ✅ Direct user to subscription center
showMessage("Payment issue detected. Please update your payment method.")
deepLinkToSubscriptions()
}

// Pre-order details
val product = fetchProducts(skus)
product.oneTimePurchaseOfferDetailsAndroid?.preorderDetailsAndroid?.let {
val releaseTime = it.preorderReleaseTimeMillis.toLong()
val presaleEndTime = it.preorderPresaleEndTimeMillis.toLong()
}`}
</CodeBlock>
<p>
See:{' '}
<a href="/docs/types#purchase-platform">Purchase Platform Fields</a>
, <a href="/docs/types#product-platform">Product Platform Fields</a>
</p>
</div>
Comment thread
coderabbitai[bot] marked this conversation as resolved.

<div
style={{
background: 'var(--bg-secondary)',
Expand All @@ -38,7 +125,8 @@ function Notes() {
<li>
<strong>Purchase.platform → Purchase.store</strong> - The{' '}
<code>platform</code> field is deprecated. Use <code>store</code>{' '}
instead which returns <code>'apple'</code> or <code>'google'</code>.
instead which returns <code>'apple'</code> or{' '}
<code>'google'</code>.
</li>
<li>
<strong>requestPurchase props</strong> - The <code>ios</code> and{' '}
Expand Down Expand Up @@ -102,7 +190,9 @@ purchase.platform // deprecated`}
</h4>
<p>
Starting from <strong>openiap v1.2.6</strong>, the{' '}
<code style={{ textDecoration: 'line-through' }}>validateReceipt</code>{' '}
<code style={{ textDecoration: 'line-through' }}>
validateReceipt
</code>{' '}
API is deprecated in favor of <code>verifyPurchase</code>.
</p>
<p>
Expand Down Expand Up @@ -177,7 +267,9 @@ purchase.platform // deprecated`}
</ul>
<p style={{ margin: 0 }}>
See:{' '}
<a href="/docs/features/external-purchase">External Purchase Guide</a>
<a href="/docs/features/external-purchase">
External Purchase Guide
</a>
</p>
</div>
</section>
Expand Down Expand Up @@ -226,7 +318,11 @@ purchase.platform // deprecated`}
</li>
</ul>
<p>
See: <a href="/docs/features/external-purchase">External Purchase Guide</a>,{' '}
See:{' '}
<a href="/docs/features/external-purchase">
External Purchase Guide
</a>
,{' '}
<a href="/docs/events#user-choice-billing-event-android">
User Choice Billing Event
</a>
Expand Down Expand Up @@ -418,16 +514,24 @@ const testProduct = await fetchProducts(['your_real_product_id'])
</thead>
<tbody>
<tr>
<td>v7.x</td>
<td>v8.x</td>
<td>✅ Current</td>
<td>TBD</td>
<td>
Latest recommended version (requires minSdk 23, Kotlin 2.2.0)
</td>
</tr>
<tr>
<td>v7.x</td>
<td>✅ Supported</td>
<td>August 31, 2025</td>
<td>Latest recommended version</td>
<td>User Choice Billing support</td>
</tr>
<tr>
<td>v6.x</td>
<td>✅ Supported</td>
<td>August 31, 2025</td>
<td>Minimum required version</td>
<td>Alternative Billing support</td>
</tr>
<tr>
<td>v5.x</td>
Expand All @@ -448,6 +552,41 @@ const testProduct = await fetchProducts(['your_real_product_id'])
<section>
<h2>🆕 Recent Updates</h2>

<h3>
<a
href="https://developer.android.com/google/play/billing/release-notes#8-1-0"
target="_blank"
rel="noopener noreferrer"
>
Google Play Billing Library v8.1
</a>{' '}
(November 2025)
</h3>
<p style={{ fontSize: '0.875rem', color: 'var(--text-secondary)' }}>
Released November 6, 2025
</p>
<ul>
<li>
<strong>Suspended Subscriptions</strong> -{' '}
<code>Purchase.isSuspended()</code> to detect payment failures
</li>
<li>
<strong>Pre-order Products</strong> - <code>PreorderDetails</code>{' '}
for one-time purchase pre-orders
</li>
<li>
<strong>minSdk 23</strong> - Minimum SDK increased to Android 6.0
</li>
<li>
<strong>Kotlin 2.2.0</strong> - Requires Kotlin 2.2.0 or higher
</li>
<li>
<strong>Deprecated API</strong> -{' '}
<code>setSubscriptionReplacementMode()</code> deprecated in favor of{' '}
<code>SubscriptionProductReplacementParams</code>
</li>
</ul>
Comment thread
coderabbitai[bot] marked this conversation as resolved.

<h3>Google Play Billing Library v7 (May 2024)</h3>
<p style={{ fontSize: '0.875rem', color: 'var(--text-secondary)' }}>
Released at Google I/O 2024
Expand Down
4 changes: 2 additions & 2 deletions packages/google/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
plugins {
id("com.android.library") version "8.5.0" apply false
id("com.android.application") version "8.5.0" apply false
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.0.21" apply false
id("org.jetbrains.kotlin.android") version "2.2.0" apply false
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0" apply false
Comment on lines +4 to +5
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Jetpack Compose compiler extension versions support Kotlin 2.2.0 compatibility matrix

💡 Result:

Short answer: for Kotlin 2.2.0 you must use the Compose compiler that matches the Kotlin version — i.e. the Compose Compiler Gradle plugin version 2.2.0 (or the corresponding kotlin-compose-compiler plugin artifact 2.2.0 if not using the Gradle plugin). [1][2][3]

References:

  • Compose ⇄ Kotlin compatibility map (Kotlin 2.0+ → use Compose Compiler Gradle plugin). [1]
  • Compose Compiler Gradle plugin docs (plugin version = Kotlin version; example use with 2.0.0). [2]
  • Kotlin migration / Compose compiler docs (compiler moved into Kotlin repo; use matching 2.x compiler or kotlin-compose-compiler-plugin artifacts). [3]

🏁 Script executed:

cat -n packages/google/build.gradle.kts

Repository: hyodotdev/openiap

Length of output: 2164


Ensure Compose compiler version is set to 2.2.0 to match Kotlin 2.2.0

The Kotlin plugins are correctly aligned at 2.2.0. However, the Compose compiler version must also be 2.2.0—since Kotlin 2.0+, the Compose compiler is bundled in the Kotlin repository and versions must match. Verify that your COMPOSE_COMPILER_VERSION gradle property is set to 2.2.0 (lines 41-42 reference this property).

🤖 Prompt for AI Agents
In packages/google/build.gradle.kts around lines 4-5, the Kotlin plugin versions
are set to 2.2.0 but the Compose compiler Gradle property referenced later must
match; update the COMPOSE_COMPILER_VERSION Gradle property to "2.2.0" (or add it
if missing) so the Compose compiler version aligns with Kotlin 2.2.0, and ensure
any usages or references (e.g., lines 41-42) read that property.

id("com.vanniktech.maven.publish") version "0.29.0" apply false
}

Expand Down
4 changes: 3 additions & 1 deletion packages/google/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,7 @@ POM_DEVELOPER_ID=hyochan
POM_DEVELOPER_NAME=hyo.dev

# Compose versions (shown on Gradle sync)
# Note: Since Kotlin 2.0+, Compose compiler is bundled with Kotlin
# COMPOSE_COMPILER_VERSION should match the Kotlin version
COMPOSE_UI_VERSION=1.6.8
COMPOSE_COMPILER_VERSION=1.5.14
COMPOSE_COMPILER_VERSION=2.2.0
8 changes: 4 additions & 4 deletions packages/google/openiap/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ android {
compileSdk = 34

defaultConfig {
minSdk = 21
minSdk = 23

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
Expand Down Expand Up @@ -86,8 +86,8 @@ dependencies {
// - Horizon flavor uses Meta Horizon Billing Compatibility Library

// Play flavor: Google Play Billing API (compile + runtime)
add("playCompileOnly", "com.android.billingclient:billing-ktx:8.0.0")
add("playApi", "com.android.billingclient:billing-ktx:8.0.0")
add("playCompileOnly", "com.android.billingclient:billing-ktx:8.1.0")
add("playApi", "com.android.billingclient:billing-ktx:8.1.0")

// Horizon flavor: Meta Horizon Platform SDK and Billing Compatibility Library (compile + runtime)
add("horizonCompileOnly", "com.meta.horizon.platform.ovr:android-platform-sdk:77.0.1")
Expand All @@ -112,7 +112,7 @@ dependencies {
testImplementation("junit:junit:4.13.2")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.9.0")
// Add Google Play Billing for tests (all flavors need it for OpenIapErrorTest)
testImplementation("com.android.billingclient:billing-ktx:8.0.0")
testImplementation("com.android.billingclient:billing-ktx:8.1.0")

androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
Expand Down
Loading
Loading