react-native-iap 14.0.1 → 14.1.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +81 -22
- package/app.plugin.js +1 -1
- package/ios/HybridRnIap.swift +167 -11
- package/ios/ProductStore.swift +10 -0
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- package/lib/module/helpers/subscription.js +9 -1
- package/lib/module/helpers/subscription.js.map +1 -1
- package/lib/module/hooks/useIAP.js +9 -13
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +43 -28
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +24 -16
- package/lib/module/types.js.map +1 -1
- package/lib/module/utils/error.js.map +1 -1
- package/lib/module/utils/type-bridge.js +64 -13
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/typescript/src/helpers/subscription.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +12 -22
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +15 -11
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +58 -58
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/error.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/nitro.json +5 -1
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +13 -4
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JNitroProduct.hpp +40 -36
- package/nitrogen/generated/android/c++/JNitroPurchase.hpp +12 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +12 -9
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +9 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +13 -7
- package/nitrogen/generated/ios/swift/NitroProduct.swift +73 -43
- package/nitrogen/generated/ios/swift/NitroPurchase.swift +35 -2
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/NitroProduct.hpp +41 -37
- package/nitrogen/generated/shared/c++/NitroPurchase.hpp +13 -1
- package/package.json +9 -2
- package/plugin/build/src/withIAP.d.ts +3 -0
- package/plugin/build/src/withIAP.js +81 -0
- package/plugin/build/tsconfig.tsbuildinfo +1 -0
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/helpers/subscription.ts +36 -25
- package/src/hooks/useIAP.ts +188 -201
- package/src/index.ts +377 -356
- package/src/specs/RnIap.nitro.ts +15 -11
- package/src/types.ts +66 -62
- package/src/utils/error.ts +19 -19
- package/src/utils/type-bridge.ts +138 -75
|
@@ -20,6 +20,7 @@ import kotlin.coroutines.resumeWithException
|
|
|
20
20
|
class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientStateListener {
|
|
21
21
|
companion object {
|
|
22
22
|
const val TAG = "RnIap"
|
|
23
|
+
private const val MICROS_PER_UNIT = 1_000_000.0
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
// Get ReactApplicationContext lazily from NitroModules
|
|
@@ -197,13 +198,22 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
197
198
|
val productDetailsParams = BillingFlowParams.ProductDetailsParams.newBuilder()
|
|
198
199
|
.setProductDetails(productDetails)
|
|
199
200
|
|
|
200
|
-
// Add offer token for subscriptions
|
|
201
|
+
// Add offer token for subscriptions (required for SUBS on Play Billing 5+)
|
|
202
|
+
// Prefer developer-provided token, otherwise fall back to the first available offer/base-plan.
|
|
201
203
|
val subscriptionOffers = androidRequest.subscriptionOffers
|
|
204
|
+
var appliedOfferToken: String? = null
|
|
205
|
+
|
|
202
206
|
if (!subscriptionOffers.isNullOrEmpty()) {
|
|
203
207
|
val offer = subscriptionOffers.find { it.sku == sku }
|
|
204
|
-
offer?.offerToken
|
|
208
|
+
appliedOfferToken = offer?.offerToken
|
|
205
209
|
}
|
|
206
|
-
|
|
210
|
+
|
|
211
|
+
if (appliedOfferToken == null && productDetails.productType == BillingClient.ProductType.SUBS) {
|
|
212
|
+
val firstAvailable = productDetails.subscriptionOfferDetails?.firstOrNull()?.offerToken
|
|
213
|
+
appliedOfferToken = firstAvailable
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
appliedOfferToken?.let { productDetailsParams.setOfferToken(it) }
|
|
207
217
|
productDetailsList.add(productDetailsParams.build())
|
|
208
218
|
}
|
|
209
219
|
|
|
@@ -566,6 +576,36 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
566
576
|
Log.d(TAG, "Subscription offer details JSON: $jsonString")
|
|
567
577
|
jsonString
|
|
568
578
|
}
|
|
579
|
+
|
|
580
|
+
// Derive introductory/trial/base period information from subscription offers (if any)
|
|
581
|
+
var derivedIntroValue: Double? = null
|
|
582
|
+
var derivedIntroCycles: Double? = null
|
|
583
|
+
var derivedIntroPeriod: String? = null
|
|
584
|
+
var derivedSubPeriod: String? = null
|
|
585
|
+
var derivedFreeTrialPeriod: String? = null
|
|
586
|
+
|
|
587
|
+
productDetails.subscriptionOfferDetails?.let { offers ->
|
|
588
|
+
// Prefer the first offer; if none, leave as nulls
|
|
589
|
+
val firstOffer = offers.firstOrNull()
|
|
590
|
+
val phases = firstOffer?.pricingPhases?.pricingPhaseList ?: emptyList()
|
|
591
|
+
if (phases.isNotEmpty()) {
|
|
592
|
+
// Base recurring phase: often the last phase (infinite recurrence)
|
|
593
|
+
val basePhase = phases.last()
|
|
594
|
+
derivedSubPeriod = basePhase.billingPeriod
|
|
595
|
+
|
|
596
|
+
// Free trial phase: priceAmountMicros == 0
|
|
597
|
+
val trialPhase = phases.firstOrNull { it.priceAmountMicros == 0L }
|
|
598
|
+
derivedFreeTrialPeriod = trialPhase?.billingPeriod
|
|
599
|
+
|
|
600
|
+
// Introductory paid phase: price > 0 and finite cycles
|
|
601
|
+
val introPhase = phases.firstOrNull { it.priceAmountMicros > 0L && it.billingCycleCount > 0 }
|
|
602
|
+
if (introPhase != null) {
|
|
603
|
+
derivedIntroValue = introPhase.priceAmountMicros / MICROS_PER_UNIT
|
|
604
|
+
derivedIntroCycles = introPhase.billingCycleCount.toDouble()
|
|
605
|
+
derivedIntroPeriod = introPhase.billingPeriod
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
569
609
|
|
|
570
610
|
val nitroProduct = NitroProduct(
|
|
571
611
|
id = productDetails.productId,
|
|
@@ -575,11 +615,12 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
575
615
|
displayName = productDetails.name,
|
|
576
616
|
displayPrice = displayPrice,
|
|
577
617
|
currency = currency,
|
|
578
|
-
price = priceAmountMicros /
|
|
618
|
+
price = priceAmountMicros / MICROS_PER_UNIT,
|
|
579
619
|
platform = "android",
|
|
580
620
|
// iOS fields (null on Android)
|
|
581
|
-
|
|
582
|
-
|
|
621
|
+
typeIOS = null,
|
|
622
|
+
isFamilyShareableIOS = null,
|
|
623
|
+
jsonRepresentationIOS = null,
|
|
583
624
|
subscriptionPeriodUnitIOS = null,
|
|
584
625
|
subscriptionPeriodNumberIOS = null,
|
|
585
626
|
introductoryPriceIOS = null,
|
|
@@ -588,13 +629,13 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
588
629
|
introductoryPriceNumberOfPeriodsIOS = null,
|
|
589
630
|
introductoryPriceSubscriptionPeriodIOS = null,
|
|
590
631
|
// Android fields
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
632
|
+
originalPriceAndroid = productDetails.oneTimePurchaseOfferDetails?.formattedPrice,
|
|
633
|
+
originalPriceAmountMicrosAndroid = productDetails.oneTimePurchaseOfferDetails?.priceAmountMicros?.toDouble(),
|
|
634
|
+
introductoryPriceValueAndroid = derivedIntroValue,
|
|
635
|
+
introductoryPriceCyclesAndroid = derivedIntroCycles,
|
|
636
|
+
introductoryPricePeriodAndroid = derivedIntroPeriod,
|
|
637
|
+
subscriptionPeriodAndroid = derivedSubPeriod,
|
|
638
|
+
freeTrialPeriodAndroid = derivedFreeTrialPeriod,
|
|
598
639
|
subscriptionOfferDetailsAndroid = subscriptionOfferDetailsJson
|
|
599
640
|
)
|
|
600
641
|
|
|
@@ -603,6 +644,19 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
603
644
|
return nitroProduct
|
|
604
645
|
}
|
|
605
646
|
|
|
647
|
+
private fun getPurchaseState(purchaseState: Int): String {
|
|
648
|
+
return when (purchaseState) {
|
|
649
|
+
Purchase.PurchaseState.PURCHASED -> "purchased"
|
|
650
|
+
Purchase.PurchaseState.PENDING -> "pending"
|
|
651
|
+
Purchase.PurchaseState.UNSPECIFIED_STATE -> "unknown"
|
|
652
|
+
else -> "unknown"
|
|
653
|
+
}
|
|
654
|
+
// Note: Android doesn't have direct equivalents for:
|
|
655
|
+
// - "restored" (iOS only - handled through restore purchases flow)
|
|
656
|
+
// - "deferred" (iOS only - parental controls)
|
|
657
|
+
// - "failed" (handled through error callbacks, not purchase state)
|
|
658
|
+
}
|
|
659
|
+
|
|
606
660
|
private fun convertToNitroPurchase(purchase: Purchase): NitroPurchase {
|
|
607
661
|
return NitroPurchase(
|
|
608
662
|
id = purchase.orderId ?: "",
|
|
@@ -610,6 +664,10 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
610
664
|
transactionDate = purchase.purchaseTime.toDouble(),
|
|
611
665
|
purchaseToken = purchase.purchaseToken,
|
|
612
666
|
platform = "android",
|
|
667
|
+
// Common fields
|
|
668
|
+
quantity = purchase.quantity.toDouble(),
|
|
669
|
+
purchaseState = getPurchaseState(purchase.purchaseState),
|
|
670
|
+
isAutoRenewing = purchase.isAutoRenewing,
|
|
613
671
|
// iOS fields
|
|
614
672
|
quantityIOS = null,
|
|
615
673
|
originalTransactionDateIOS = null,
|
|
@@ -695,6 +753,14 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
695
753
|
}
|
|
696
754
|
}
|
|
697
755
|
|
|
756
|
+
// Updated signature to follow spec: returns updated subscriptions
|
|
757
|
+
override fun showManageSubscriptionsIOS(): Promise<Array<NitroPurchase>> {
|
|
758
|
+
return Promise.async {
|
|
759
|
+
// Not supported on Android. Return empty list for iOS-only API.
|
|
760
|
+
emptyArray()
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
|
|
698
764
|
// Receipt validation
|
|
699
765
|
override fun validateReceipt(params: NitroReceiptValidationParams): Promise<Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid> {
|
|
700
766
|
return Promise.async {
|
|
@@ -796,14 +862,7 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
796
862
|
}
|
|
797
863
|
}
|
|
798
864
|
|
|
799
|
-
|
|
800
|
-
return Promise.async {
|
|
801
|
-
throw Exception(BillingUtils.createErrorJson(
|
|
802
|
-
IapErrorCode.E_FEATURE_NOT_SUPPORTED,
|
|
803
|
-
"showManageSubscriptionsIOS is only available on iOS platform"
|
|
804
|
-
))
|
|
805
|
-
}
|
|
806
|
-
}
|
|
865
|
+
|
|
807
866
|
|
|
808
867
|
override fun isEligibleForIntroOfferIOS(groupID: String): Promise<Boolean> {
|
|
809
868
|
return Promise.async {
|
|
@@ -840,4 +899,4 @@ class HybridRnIap : HybridRnIapSpec(), PurchasesUpdatedListener, BillingClientSt
|
|
|
840
899
|
))
|
|
841
900
|
}
|
|
842
901
|
}
|
|
843
|
-
}
|
|
902
|
+
}
|
package/app.plugin.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = require('./plugin/build/withIAP.js')
|
|
1
|
+
module.exports = require('./plugin/build/withIAP.js');
|
package/ios/HybridRnIap.swift
CHANGED
|
@@ -568,7 +568,15 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
568
568
|
|
|
569
569
|
switch entitlement {
|
|
570
570
|
case .verified(let transaction):
|
|
571
|
-
|
|
571
|
+
// Get renewal info if this is a subscription
|
|
572
|
+
var renewalInfo: Product.SubscriptionInfo.RenewalInfo? = nil
|
|
573
|
+
if let subscription = product.subscription,
|
|
574
|
+
let status = try? await subscription.status.first {
|
|
575
|
+
if case .verified(let info) = status.renewalInfo {
|
|
576
|
+
renewalInfo = info
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
return self.convertToNitroPurchase(transaction, product: product, jwsRepresentation: entitlement.jwsRepresentation, renewalInfo: renewalInfo)
|
|
572
580
|
case .unverified:
|
|
573
581
|
let errorJson = ErrorUtils.createErrorJson(
|
|
574
582
|
code: IapErrorCode.transactionValidationFailed,
|
|
@@ -604,7 +612,15 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
604
612
|
|
|
605
613
|
switch latestTransaction {
|
|
606
614
|
case .verified(let transaction):
|
|
607
|
-
|
|
615
|
+
// Get renewal info if this is a subscription
|
|
616
|
+
var renewalInfo: Product.SubscriptionInfo.RenewalInfo? = nil
|
|
617
|
+
if let subscription = product.subscription,
|
|
618
|
+
let status = try? await subscription.status.first {
|
|
619
|
+
if case .verified(let info) = status.renewalInfo {
|
|
620
|
+
renewalInfo = info
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
return self.convertToNitroPurchase(transaction, product: product, jwsRepresentation: latestTransaction.jwsRepresentation, renewalInfo: renewalInfo)
|
|
608
624
|
case .unverified:
|
|
609
625
|
let errorJson = ErrorUtils.createErrorJson(
|
|
610
626
|
code: IapErrorCode.transactionValidationFailed,
|
|
@@ -648,7 +664,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
648
664
|
}
|
|
649
665
|
}
|
|
650
666
|
|
|
651
|
-
func showManageSubscriptionsIOS() throws -> Promise<
|
|
667
|
+
func showManageSubscriptionsIOS() throws -> Promise<[NitroPurchase]> {
|
|
652
668
|
return Promise.async {
|
|
653
669
|
#if !os(tvOS)
|
|
654
670
|
// Get the active window scene
|
|
@@ -664,12 +680,83 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
664
680
|
throw NSError(domain: "RnIap", code: -1, userInfo: [NSLocalizedDescriptionKey: errorJson])
|
|
665
681
|
}
|
|
666
682
|
|
|
667
|
-
//
|
|
683
|
+
// Get current subscription statuses before showing UI
|
|
684
|
+
var beforeStatuses: [String: Bool] = [:]
|
|
685
|
+
var subscriptionSkus = await self.productStore?.getAllSubscriptionProductIds() ?? []
|
|
686
|
+
|
|
687
|
+
// Fallback: If ProductStore is empty, derive SKUs from current entitlements
|
|
688
|
+
if subscriptionSkus.isEmpty {
|
|
689
|
+
var ids = Set<String>()
|
|
690
|
+
for await verification in Transaction.currentEntitlements {
|
|
691
|
+
if case .verified(let t) = verification, t.productType == .autoRenewable {
|
|
692
|
+
ids.insert(t.productID)
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
subscriptionSkus = Array(ids)
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
for sku in subscriptionSkus {
|
|
699
|
+
if let product = await self.fetchProductIfNeeded(sku: sku),
|
|
700
|
+
let status = try? await product.subscription?.status.first {
|
|
701
|
+
var willAutoRenew = false
|
|
702
|
+
if case .verified(let info) = status.renewalInfo {
|
|
703
|
+
willAutoRenew = info.willAutoRenew
|
|
704
|
+
}
|
|
705
|
+
beforeStatuses[sku] = willAutoRenew
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Show the management UI
|
|
668
710
|
try await AppStore.showManageSubscriptions(in: windowScene)
|
|
669
|
-
|
|
711
|
+
|
|
712
|
+
// Wait a bit for changes to propagate
|
|
713
|
+
try? await Task.sleep(nanoseconds: 1_500_000_000) // 1.5 seconds
|
|
714
|
+
|
|
715
|
+
// Check for changes and return updated subscriptions
|
|
716
|
+
var updatedSubscriptions: [NitroPurchase] = []
|
|
717
|
+
|
|
718
|
+
for sku in subscriptionSkus {
|
|
719
|
+
if let product = await self.fetchProductIfNeeded(sku: sku),
|
|
720
|
+
let status = try? await product.subscription?.status.first,
|
|
721
|
+
let result = await product.latestTransaction {
|
|
722
|
+
|
|
723
|
+
// Check current status
|
|
724
|
+
var currentWillAutoRenew = false
|
|
725
|
+
var currentRenewalInfo: Product.SubscriptionInfo.RenewalInfo? = nil
|
|
726
|
+
if case .verified(let info) = status.renewalInfo {
|
|
727
|
+
currentWillAutoRenew = info.willAutoRenew
|
|
728
|
+
currentRenewalInfo = info
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// Check if status changed
|
|
732
|
+
let previousWillAutoRenew = beforeStatuses[sku] ?? false
|
|
733
|
+
if previousWillAutoRenew != currentWillAutoRenew {
|
|
734
|
+
// Status changed, include in result
|
|
735
|
+
do {
|
|
736
|
+
let transaction = try self.checkVerified(result)
|
|
737
|
+
let purchase = self.convertToNitroPurchase(
|
|
738
|
+
transaction,
|
|
739
|
+
product: product,
|
|
740
|
+
jwsRepresentation: result.jwsRepresentation,
|
|
741
|
+
renewalInfo: currentRenewalInfo
|
|
742
|
+
)
|
|
743
|
+
|
|
744
|
+
// Add renewal info as additional data
|
|
745
|
+
// Note: We'll add this info through the purchase token or other field
|
|
746
|
+
// since NitroPurchase doesn't have a dedicated renewal info field
|
|
747
|
+
|
|
748
|
+
updatedSubscriptions.append(purchase)
|
|
749
|
+
} catch {
|
|
750
|
+
// Skip if verification fails
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return updatedSubscriptions
|
|
670
757
|
#else
|
|
671
758
|
let errorJson = ErrorUtils.createErrorJson(
|
|
672
|
-
code: IapErrorCode.
|
|
759
|
+
code: IapErrorCode.serviceError,
|
|
673
760
|
message: "This method is not available on tvOS"
|
|
674
761
|
)
|
|
675
762
|
throw NSError(domain: "RnIap", code: -1, userInfo: [NSLocalizedDescriptionKey: errorJson])
|
|
@@ -866,6 +953,22 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
866
953
|
|
|
867
954
|
// MARK: - Private Helper Methods
|
|
868
955
|
|
|
956
|
+
private func fetchProductIfNeeded(sku: String) async -> Product? {
|
|
957
|
+
// Check if product is already cached
|
|
958
|
+
if let product = await self.productStore?.getProduct(productID: sku) {
|
|
959
|
+
return product
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// Fetch from StoreKit and cache it
|
|
963
|
+
if let products = try? await StoreKit.Product.products(for: [sku]),
|
|
964
|
+
let product = products.first {
|
|
965
|
+
await self.productStore?.addProduct(product)
|
|
966
|
+
return product
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
return nil
|
|
970
|
+
}
|
|
971
|
+
|
|
869
972
|
private func purchaseProduct(
|
|
870
973
|
_ product: Product,
|
|
871
974
|
sku: String,
|
|
@@ -1157,7 +1260,29 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
1157
1260
|
product.id = storeProduct.id
|
|
1158
1261
|
product.title = storeProduct.displayName
|
|
1159
1262
|
product.description = storeProduct.description
|
|
1160
|
-
|
|
1263
|
+
// Map StoreKit type to cross-platform compatible string: "inapp" | "subs"
|
|
1264
|
+
// and set detailed iOS product type
|
|
1265
|
+
#if swift(>=5.7)
|
|
1266
|
+
switch storeProduct.type {
|
|
1267
|
+
case .consumable:
|
|
1268
|
+
product.type = "inapp"
|
|
1269
|
+
product.typeIOS = "consumable"
|
|
1270
|
+
case .nonConsumable:
|
|
1271
|
+
product.type = "inapp"
|
|
1272
|
+
product.typeIOS = "nonConsumable"
|
|
1273
|
+
case .autoRenewable:
|
|
1274
|
+
product.type = "subs"
|
|
1275
|
+
product.typeIOS = "autoRenewableSubscription"
|
|
1276
|
+
case .nonRenewable:
|
|
1277
|
+
product.type = "subs"
|
|
1278
|
+
product.typeIOS = "nonRenewingSubscription"
|
|
1279
|
+
default:
|
|
1280
|
+
product.type = type // fallback to requested filter
|
|
1281
|
+
product.typeIOS = nil
|
|
1282
|
+
}
|
|
1283
|
+
#else
|
|
1284
|
+
product.type = type
|
|
1285
|
+
#endif
|
|
1161
1286
|
product.displayName = storeProduct.displayName
|
|
1162
1287
|
product.displayPrice = storeProduct.displayPrice
|
|
1163
1288
|
product.platform = "ios"
|
|
@@ -1169,8 +1294,11 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
1169
1294
|
product.price = NSDecimalNumber(decimal: storeProduct.price).doubleValue
|
|
1170
1295
|
|
|
1171
1296
|
// iOS specific fields
|
|
1172
|
-
product.
|
|
1173
|
-
|
|
1297
|
+
product.isFamilyShareableIOS = storeProduct.isFamilyShareable
|
|
1298
|
+
|
|
1299
|
+
// Set JSON representation
|
|
1300
|
+
product.jsonRepresentationIOS = String(data: storeProduct.jsonRepresentation, encoding: .utf8)
|
|
1301
|
+
?? storeProduct.jsonRepresentation.base64EncodedString()
|
|
1174
1302
|
|
|
1175
1303
|
// Subscription information
|
|
1176
1304
|
if let subscription = storeProduct.subscription {
|
|
@@ -1205,7 +1333,25 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
1205
1333
|
}
|
|
1206
1334
|
}
|
|
1207
1335
|
|
|
1208
|
-
private func
|
|
1336
|
+
private func getPurchaseState(_ transaction: Transaction) -> String {
|
|
1337
|
+
// Map StoreKit 2 transaction states to our unified PurchaseState enum
|
|
1338
|
+
if transaction.revocationDate != nil {
|
|
1339
|
+
return "failed"
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// Check if transaction needs finishing (pending)
|
|
1343
|
+
// In StoreKit 2, transactions are automatically finished unless we handle them manually
|
|
1344
|
+
// We consider a transaction as "purchased" once it's verified
|
|
1345
|
+
|
|
1346
|
+
// Note: StoreKit 2 doesn't have direct equivalents for all states
|
|
1347
|
+
// - "restored" is handled separately through restore purchases flow
|
|
1348
|
+
// - "deferred" happens with parental controls but isn't exposed in Transaction
|
|
1349
|
+
// - "pending" isn't directly available in StoreKit 2
|
|
1350
|
+
|
|
1351
|
+
return "purchased"
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
private func convertToNitroPurchase(_ transaction: Transaction, product: StoreKit.Product, jwsRepresentation: String? = nil, renewalInfo: Product.SubscriptionInfo.RenewalInfo? = nil) -> NitroPurchase {
|
|
1209
1355
|
var purchase = NitroPurchase()
|
|
1210
1356
|
|
|
1211
1357
|
// Basic fields
|
|
@@ -1214,6 +1360,16 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
1214
1360
|
purchase.transactionDate = transaction.purchaseDate.timeIntervalSince1970 * 1000 // Convert to milliseconds
|
|
1215
1361
|
purchase.platform = "ios"
|
|
1216
1362
|
|
|
1363
|
+
// Common fields
|
|
1364
|
+
purchase.quantity = Double(transaction.purchasedQuantity)
|
|
1365
|
+
purchase.purchaseState = getPurchaseState(transaction)
|
|
1366
|
+
// For iOS, check renewal info first if available, otherwise fall back to expiration date check
|
|
1367
|
+
if let renewalInfo = renewalInfo {
|
|
1368
|
+
purchase.isAutoRenewing = renewalInfo.willAutoRenew
|
|
1369
|
+
} else {
|
|
1370
|
+
purchase.isAutoRenewing = (product.type == .autoRenewable && transaction.expirationDate != nil && transaction.expirationDate! > Date())
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1217
1373
|
// iOS specific fields
|
|
1218
1374
|
purchase.quantityIOS = Double(transaction.purchasedQuantity)
|
|
1219
1375
|
|
|
@@ -1323,4 +1479,4 @@ class PaymentObserver: NSObject, SKPaymentTransactionObserver {
|
|
|
1323
1479
|
// Return false to defer the payment
|
|
1324
1480
|
return false
|
|
1325
1481
|
}
|
|
1326
|
-
}
|
|
1482
|
+
}
|
package/ios/ProductStore.swift
CHANGED
|
@@ -23,6 +23,16 @@ actor ProductStore {
|
|
|
23
23
|
return self.products[productID]
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
func getAllSubscriptionProductIds() -> [String] {
|
|
27
|
+
return products.values.compactMap { product in
|
|
28
|
+
// Check if the product is a subscription
|
|
29
|
+
if product.subscription != nil {
|
|
30
|
+
return product.id
|
|
31
|
+
}
|
|
32
|
+
return nil
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
26
36
|
func removeAll() {
|
|
27
37
|
products.removeAll()
|
|
28
38
|
}
|
|
@@ -20,13 +20,21 @@ export const getActiveSubscriptions = async subscriptionIds => {
|
|
|
20
20
|
return true;
|
|
21
21
|
}).map(purchase => {
|
|
22
22
|
const iosPurchase = purchase;
|
|
23
|
+
const androidPurchase = purchase;
|
|
23
24
|
return {
|
|
24
25
|
productId: purchase.productId,
|
|
25
26
|
isActive: true,
|
|
26
27
|
// If it's in availablePurchases, it's active
|
|
28
|
+
// Backend validation fields
|
|
29
|
+
transactionId: purchase.transactionId || purchase.id,
|
|
30
|
+
purchaseToken: androidPurchase.purchaseToken || androidPurchase.purchaseTokenAndroid || iosPurchase.purchaseToken,
|
|
31
|
+
transactionDate: purchase.transactionDate,
|
|
32
|
+
// Platform-specific fields
|
|
27
33
|
expirationDateIOS: iosPurchase.expirationDateIOS ? new Date(iosPurchase.expirationDateIOS) : undefined,
|
|
28
|
-
autoRenewingAndroid:
|
|
34
|
+
autoRenewingAndroid: androidPurchase.autoRenewingAndroid ?? androidPurchase.isAutoRenewing,
|
|
35
|
+
// deprecated - use isAutoRenewing instead
|
|
29
36
|
environmentIOS: iosPurchase.environmentIOS,
|
|
37
|
+
// Convenience fields
|
|
30
38
|
willExpireSoon: false,
|
|
31
39
|
// Would need to calculate based on expiration date
|
|
32
40
|
daysUntilExpirationIOS: iosPurchase.expirationDateIOS ? Math.ceil((iosPurchase.expirationDateIOS - Date.now()) / (1000 * 60 * 60 * 24)) : undefined
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["getAvailablePurchases","getActiveSubscriptions","subscriptionIds","purchases","subscriptions","filter","purchase","length","includes","productId","map","iosPurchase","isActive","expirationDateIOS","Date","undefined","autoRenewingAndroid","environmentIOS","willExpireSoon","daysUntilExpirationIOS","Math","ceil","now","error","console","hasActiveSubscriptions","activeSubscriptions"],"sourceRoot":"../../../src","sources":["helpers/subscription.ts"],"mappings":";;AAAA,
|
|
1
|
+
{"version":3,"names":["getAvailablePurchases","getActiveSubscriptions","subscriptionIds","purchases","subscriptions","filter","purchase","length","includes","productId","map","iosPurchase","androidPurchase","isActive","transactionId","id","purchaseToken","purchaseTokenAndroid","transactionDate","expirationDateIOS","Date","undefined","autoRenewingAndroid","isAutoRenewing","environmentIOS","willExpireSoon","daysUntilExpirationIOS","Math","ceil","now","error","console","hasActiveSubscriptions","activeSubscriptions"],"sourceRoot":"../../../src","sources":["helpers/subscription.ts"],"mappings":";;AAAA,SAAQA,qBAAqB,QAAO,aAAK;AAOzC;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,sBAAsB,GAAG,MACpCC,eAA0B,IACQ;EAClC,IAAI;IACF;IACA,MAAMC,SAAS,GAAG,MAAMH,qBAAqB,CAAC,CAAC;;IAE/C;IACA,MAAMI,aAAa,GAAGD,SAAS,CAC5BE,MAAM,CAAEC,QAAQ,IAAK;MACpB;MACA,IAAIJ,eAAe,IAAIA,eAAe,CAACK,MAAM,GAAG,CAAC,EAAE;QACjD,OAAOL,eAAe,CAACM,QAAQ,CAACF,QAAQ,CAACG,SAAS,CAAC;MACrD;MACA,OAAO,IAAI;IACb,CAAC,CAAC,CACDC,GAAG,CAAEJ,QAAQ,IAAyB;MACrC,MAAMK,WAAW,GAAGL,QAAuB;MAC3C,MAAMM,eAAe,GAAGN,QAA2B;MACnD,OAAO;QACLG,SAAS,EAAEH,QAAQ,CAACG,SAAS;QAC7BI,QAAQ,EAAE,IAAI;QAAE;QAChB;QACAC,aAAa,EAAER,QAAQ,CAACQ,aAAa,IAAIR,QAAQ,CAACS,EAAE;QACpDC,aAAa,EACXJ,eAAe,CAACI,aAAa,IAAIJ,eAAe,CAACK,oBAAoB,IAAIN,WAAW,CAACK,aAAa;QACpGE,eAAe,EAAEZ,QAAQ,CAACY,eAAe;QACzC;QACAC,iBAAiB,EAAER,WAAW,CAACQ,iBAAiB,GAC5C,IAAIC,IAAI,CAACT,WAAW,CAACQ,iBAAiB,CAAC,GACvCE,SAAS;QACbC,mBAAmB,EAAEV,eAAe,CAACU,mBAAmB,IAAIV,eAAe,CAACW,cAAc;QAAE;QAC5FC,cAAc,EAAEb,WAAW,CAACa,cAAc;QAC1C;QACAC,cAAc,EAAE,KAAK;QAAE;QACvBC,sBAAsB,EAAEf,WAAW,CAACQ,iBAAiB,GACjDQ,IAAI,CAACC,IAAI,CACP,CAACjB,WAAW,CAACQ,iBAAiB,GAAGC,IAAI,CAACS,GAAG,CAAC,CAAC,KAAK,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CACrE,CAAC,GACDR;MACN,CAAC;IACH,CAAC,CAAC;IAEJ,OAAOjB,aAAa;EACtB,CAAC,CAAC,OAAO0B,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,qCAAqC,EAAEA,KAAK,CAAC;IAC3D,MAAMA,KAAK;EACb;AACF,CAAC;;AAGD;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,sBAAsB,GAAG,MACpC9B,eAA0B,IACL;EACrB,IAAI;IACF,MAAM+B,mBAAmB,GAAG,MAAMhC,sBAAsB,CAACC,eAAe,CAAC;IACzE,OAAO+B,mBAAmB,CAAC1B,MAAM,GAAG,CAAC;EACvC,CAAC,CAAC,OAAOuB,KAAK,EAAE;IACdC,OAAO,CAACD,KAAK,CAAC,uCAAuC,EAAEA,KAAK,CAAC;IAC7D,OAAO,KAAK;EACd;AACF,CAAC","ignoreList":[]}
|
|
@@ -145,16 +145,6 @@ export function useIAP(options) {
|
|
|
145
145
|
throw error;
|
|
146
146
|
}
|
|
147
147
|
}, [clearCurrentPurchase, clearCurrentPurchaseError]);
|
|
148
|
-
const refreshSubscriptionStatus = useCallback(async productId => {
|
|
149
|
-
try {
|
|
150
|
-
if (subscriptionsRefState.current.some(sub => sub.id === productId)) {
|
|
151
|
-
await getSubscriptionsInternal([productId]);
|
|
152
|
-
await getAvailablePurchasesInternal();
|
|
153
|
-
}
|
|
154
|
-
} catch (error) {
|
|
155
|
-
console.warn('Failed to refresh subscription status:', error);
|
|
156
|
-
}
|
|
157
|
-
}, [getAvailablePurchasesInternal, getSubscriptionsInternal]);
|
|
158
148
|
const restorePurchases = useCallback(async () => {
|
|
159
149
|
try {
|
|
160
150
|
if (Platform.OS === 'ios') {
|
|
@@ -181,8 +171,14 @@ export function useIAP(options) {
|
|
|
181
171
|
subscriptionsRef.current.purchaseUpdate = purchaseUpdatedListener(async purchase => {
|
|
182
172
|
setCurrentPurchaseError(undefined);
|
|
183
173
|
setCurrentPurchase(purchase);
|
|
184
|
-
|
|
185
|
-
|
|
174
|
+
|
|
175
|
+
// Always refresh subscription state after a purchase event
|
|
176
|
+
try {
|
|
177
|
+
await getActiveSubscriptionsInternal();
|
|
178
|
+
await getAvailablePurchasesInternal();
|
|
179
|
+
} catch (e) {
|
|
180
|
+
// Non-fatal: UI will still update from event data
|
|
181
|
+
console.warn('[useIAP] post-purchase refresh failed:', e);
|
|
186
182
|
}
|
|
187
183
|
if (optionsRef.current?.onPurchaseSuccess) {
|
|
188
184
|
optionsRef.current.onPurchaseSuccess(purchase);
|
|
@@ -205,7 +201,7 @@ export function useIAP(options) {
|
|
|
205
201
|
});
|
|
206
202
|
}
|
|
207
203
|
}
|
|
208
|
-
}, [
|
|
204
|
+
}, [getActiveSubscriptionsInternal, getAvailablePurchasesInternal]);
|
|
209
205
|
useEffect(() => {
|
|
210
206
|
initIapWithSubscriptions();
|
|
211
207
|
const currentSubscriptions = subscriptionsRef.current;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["useCallback","useEffect","useState","useRef","Platform","endConnection","initConnection","purchaseErrorListener","purchaseUpdatedListener","promotedProductListenerIOS","getAvailablePurchases","finishTransaction","finishTransactionInternal","requestPurchase","requestPurchaseInternal","fetchProducts","validateReceipt","validateReceiptInternal","getActiveSubscriptions","hasActiveSubscriptions","syncIOS","requestPromotedProductIOS","buyPromotedProductIOS","useIAP","options","connected","setConnected","products","setProducts","promotedProductsIOS","subscriptions","setSubscriptions","availablePurchases","setAvailablePurchases","currentPurchase","setCurrentPurchase","promotedProductIOS","setPromotedProductIOS","currentPurchaseError","setCurrentPurchaseError","promotedProductIdIOS","activeSubscriptions","setActiveSubscriptions","optionsRef","mergeWithDuplicateCheck","existingItems","newItems","getKey","merged","forEach","newItem","isDuplicate","some","existingItem","push","current","subscriptionsRef","subscriptionsRefState","clearCurrentPurchase","undefined","clearCurrentPurchaseError","getProductsInternal","skus","result","type","prevProducts","product","id","error","console","getSubscriptionsInternal","prevSubscriptions","subscription","fetchProductsInternal","params","getAvailablePurchasesInternal","getActiveSubscriptionsInternal","subscriptionIds","hasActiveSubscriptionsInternal","purchase","isConsumable","err","productId","requestPurchaseWithReset","requestObj","
|
|
1
|
+
{"version":3,"names":["useCallback","useEffect","useState","useRef","Platform","endConnection","initConnection","purchaseErrorListener","purchaseUpdatedListener","promotedProductListenerIOS","getAvailablePurchases","finishTransaction","finishTransactionInternal","requestPurchase","requestPurchaseInternal","fetchProducts","validateReceipt","validateReceiptInternal","getActiveSubscriptions","hasActiveSubscriptions","syncIOS","requestPromotedProductIOS","buyPromotedProductIOS","useIAP","options","connected","setConnected","products","setProducts","promotedProductsIOS","subscriptions","setSubscriptions","availablePurchases","setAvailablePurchases","currentPurchase","setCurrentPurchase","promotedProductIOS","setPromotedProductIOS","currentPurchaseError","setCurrentPurchaseError","promotedProductIdIOS","activeSubscriptions","setActiveSubscriptions","optionsRef","mergeWithDuplicateCheck","existingItems","newItems","getKey","merged","forEach","newItem","isDuplicate","some","existingItem","push","current","subscriptionsRef","subscriptionsRefState","clearCurrentPurchase","undefined","clearCurrentPurchaseError","getProductsInternal","skus","result","type","prevProducts","product","id","error","console","getSubscriptionsInternal","prevSubscriptions","subscription","fetchProductsInternal","params","getAvailablePurchasesInternal","getActiveSubscriptionsInternal","subscriptionIds","hasActiveSubscriptionsInternal","purchase","isConsumable","err","productId","requestPurchaseWithReset","requestObj","restorePurchases","OS","catch","onSyncError","warn","sku","androidOptions","initIapWithSubscriptions","purchaseUpdate","e","onPurchaseSuccess","purchaseError","onPurchaseError","onPromotedProductIOS","currentSubscriptions","remove","getProducts","getSubscriptions"],"sourceRoot":"../../../src","sources":["hooks/useIAP.ts"],"mappings":"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","ignoreList":[]}
|