react-native-iap 14.5.0 → 14.6.0-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.
Files changed (105) hide show
  1. package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +173 -7
  2. package/ios/HybridRnIap.swift +24 -0
  3. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  4. package/ios/reactnativeiap.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  5. package/lib/module/index.js +166 -0
  6. package/lib/module/index.js.map +1 -1
  7. package/lib/module/types.js +93 -0
  8. package/lib/module/types.js.map +1 -1
  9. package/lib/module/utils/type-bridge.js +2 -1
  10. package/lib/module/utils/type-bridge.js.map +1 -1
  11. package/lib/typescript/src/index.d.ts +124 -0
  12. package/lib/typescript/src/index.d.ts.map +1 -1
  13. package/lib/typescript/src/specs/RnIap.nitro.d.ts +125 -1
  14. package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
  15. package/lib/typescript/src/types.d.ts +227 -15
  16. package/lib/typescript/src/types.d.ts.map +1 -1
  17. package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
  18. package/nitrogen/generated/android/c++/JBillingProgramAndroid.hpp +62 -0
  19. package/nitrogen/generated/android/c++/JExternalLinkLaunchModeAndroid.hpp +62 -0
  20. package/nitrogen/generated/android/c++/JExternalLinkTypeAndroid.hpp +62 -0
  21. package/nitrogen/generated/android/c++/JFunc_void_NitroProduct.hpp +13 -0
  22. package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +100 -0
  23. package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +4 -0
  24. package/nitrogen/generated/android/c++/JNitroBillingProgramAvailabilityResultAndroid.hpp +62 -0
  25. package/nitrogen/generated/android/c++/JNitroBillingProgramReportingDetailsAndroid.hpp +63 -0
  26. package/nitrogen/generated/android/c++/JNitroDiscountAmountAndroid.hpp +61 -0
  27. package/nitrogen/generated/android/c++/JNitroDiscountDisplayInfoAndroid.hpp +64 -0
  28. package/nitrogen/generated/android/c++/JNitroLaunchExternalLinkParamsAndroid.hpp +75 -0
  29. package/nitrogen/generated/android/c++/JNitroLimitedQuantityInfoAndroid.hpp +61 -0
  30. package/nitrogen/generated/android/c++/JNitroOneTimePurchaseOfferDetail.hpp +70 -3
  31. package/nitrogen/generated/android/c++/JNitroPreorderDetailsAndroid.hpp +61 -0
  32. package/nitrogen/generated/android/c++/JNitroProduct.hpp +35 -5
  33. package/nitrogen/generated/android/c++/JNitroPurchase.hpp +7 -3
  34. package/nitrogen/generated/android/c++/JNitroRentalDetailsAndroid.hpp +62 -0
  35. package/nitrogen/generated/android/c++/JNitroValidTimeWindowAndroid.hpp +61 -0
  36. package/nitrogen/generated/android/c++/JPurchaseAndroid.hpp +5 -1
  37. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/BillingProgramAndroid.kt +22 -0
  38. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/ExternalLinkLaunchModeAndroid.kt +22 -0
  39. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/ExternalLinkTypeAndroid.kt +22 -0
  40. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +16 -0
  41. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroBillingProgramAvailabilityResultAndroid.kt +39 -0
  42. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroBillingProgramReportingDetailsAndroid.kt +39 -0
  43. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroDiscountAmountAndroid.kt +39 -0
  44. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroDiscountDisplayInfoAndroid.kt +39 -0
  45. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroLaunchExternalLinkParamsAndroid.kt +45 -0
  46. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroLimitedQuantityInfoAndroid.kt +39 -0
  47. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroOneTimePurchaseOfferDetail.kt +30 -3
  48. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPreorderDetailsAndroid.kt +39 -0
  49. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroProduct.kt +2 -2
  50. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroPurchase.kt +6 -3
  51. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroRentalDetailsAndroid.kt +39 -0
  52. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/NitroValidTimeWindowAndroid.kt +39 -0
  53. package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseAndroid.kt +5 -2
  54. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.cpp +16 -0
  55. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +232 -18
  56. package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +36 -0
  57. package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +66 -0
  58. package/nitrogen/generated/ios/swift/BillingProgramAndroid.swift +44 -0
  59. package/nitrogen/generated/ios/swift/ExternalLinkLaunchModeAndroid.swift +44 -0
  60. package/nitrogen/generated/ios/swift/ExternalLinkTypeAndroid.swift +44 -0
  61. package/nitrogen/generated/ios/swift/Func_void_NitroBillingProgramAvailabilityResultAndroid.swift +47 -0
  62. package/nitrogen/generated/ios/swift/Func_void_NitroBillingProgramReportingDetailsAndroid.swift +47 -0
  63. package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +4 -0
  64. package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +68 -0
  65. package/nitrogen/generated/ios/swift/NitroBillingProgramAvailabilityResultAndroid.swift +46 -0
  66. package/nitrogen/generated/ios/swift/NitroBillingProgramReportingDetailsAndroid.swift +46 -0
  67. package/nitrogen/generated/ios/swift/NitroDiscountAmountAndroid.swift +46 -0
  68. package/nitrogen/generated/ios/swift/NitroDiscountDisplayInfoAndroid.swift +70 -0
  69. package/nitrogen/generated/ios/swift/NitroLaunchExternalLinkParamsAndroid.swift +68 -0
  70. package/nitrogen/generated/ios/swift/NitroLimitedQuantityInfoAndroid.swift +46 -0
  71. package/nitrogen/generated/ios/swift/NitroOneTimePurchaseOfferDetail.swift +211 -2
  72. package/nitrogen/generated/ios/swift/NitroPreorderDetailsAndroid.swift +46 -0
  73. package/nitrogen/generated/ios/swift/NitroProduct.swift +26 -7
  74. package/nitrogen/generated/ios/swift/NitroPurchase.swift +31 -1
  75. package/nitrogen/generated/ios/swift/NitroRentalDetailsAndroid.swift +65 -0
  76. package/nitrogen/generated/ios/swift/NitroValidTimeWindowAndroid.swift +46 -0
  77. package/nitrogen/generated/ios/swift/PurchaseAndroid.swift +32 -2
  78. package/nitrogen/generated/shared/c++/BillingProgramAndroid.hpp +80 -0
  79. package/nitrogen/generated/shared/c++/ExternalLinkLaunchModeAndroid.hpp +80 -0
  80. package/nitrogen/generated/shared/c++/ExternalLinkTypeAndroid.hpp +80 -0
  81. package/nitrogen/generated/shared/c++/HybridRnIapSpec.cpp +4 -0
  82. package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +16 -0
  83. package/nitrogen/generated/shared/c++/NitroBillingProgramAvailabilityResultAndroid.hpp +80 -0
  84. package/nitrogen/generated/shared/c++/NitroBillingProgramReportingDetailsAndroid.hpp +81 -0
  85. package/nitrogen/generated/shared/c++/NitroDiscountAmountAndroid.hpp +79 -0
  86. package/nitrogen/generated/shared/c++/NitroDiscountDisplayInfoAndroid.hpp +81 -0
  87. package/nitrogen/generated/shared/c++/NitroLaunchExternalLinkParamsAndroid.hpp +95 -0
  88. package/nitrogen/generated/shared/c++/NitroLimitedQuantityInfoAndroid.hpp +79 -0
  89. package/nitrogen/generated/shared/c++/NitroOneTimePurchaseOfferDetail.hpp +55 -3
  90. package/nitrogen/generated/shared/c++/NitroPreorderDetailsAndroid.hpp +79 -0
  91. package/nitrogen/generated/shared/c++/NitroProduct.hpp +6 -5
  92. package/nitrogen/generated/shared/c++/NitroPurchase.hpp +6 -2
  93. package/nitrogen/generated/shared/c++/NitroRentalDetailsAndroid.hpp +80 -0
  94. package/nitrogen/generated/shared/c++/NitroValidTimeWindowAndroid.hpp +79 -0
  95. package/nitrogen/generated/shared/c++/PurchaseAndroid.hpp +5 -1
  96. package/openiap-versions.json +2 -2
  97. package/package.json +1 -1
  98. package/plugin/build/src/withIAP.d.ts +3 -0
  99. package/plugin/build/src/withIAP.js +81 -0
  100. package/plugin/build/tsconfig.tsbuildinfo +1 -0
  101. package/plugin/tsconfig.tsbuildinfo +1 -1
  102. package/src/index.ts +218 -0
  103. package/src/specs/RnIap.nitro.ts +161 -1
  104. package/src/types.ts +243 -15
  105. package/src/utils/type-bridge.ts +1 -0
@@ -31,6 +31,11 @@ import dev.hyo.openiap.InitConnectionConfig as OpenIapInitConnectionConfig
31
31
  import dev.hyo.openiap.listener.OpenIapPurchaseErrorListener
32
32
  import dev.hyo.openiap.listener.OpenIapPurchaseUpdateListener
33
33
  import dev.hyo.openiap.listener.OpenIapUserChoiceBillingListener
34
+ import dev.hyo.openiap.BillingProgramAndroid as OpenIapBillingProgramAndroid
35
+ import dev.hyo.openiap.LaunchExternalLinkParamsAndroid as OpenIapLaunchExternalLinkParams
36
+ import dev.hyo.openiap.ExternalLinkLaunchModeAndroid as OpenIapExternalLinkLaunchMode
37
+ import dev.hyo.openiap.ExternalLinkTypeAndroid as OpenIapExternalLinkType
38
+ import dev.hyo.openiap.store.OpenIapStore
34
39
  import kotlinx.coroutines.Dispatchers
35
40
  import kotlinx.coroutines.withContext
36
41
  import kotlinx.coroutines.CompletableDeferred
@@ -815,20 +820,59 @@ class HybridRnIap : HybridRnIapSpec() {
815
820
  is ProductAndroid -> product.subscriptionOfferDetailsAndroid.orEmpty()
816
821
  else -> emptyList()
817
822
  }
818
- val oneTimeOffer = when (product) {
823
+ val oneTimeOffers = when (product) {
819
824
  is ProductSubscriptionAndroid -> product.oneTimePurchaseOfferDetailsAndroid
820
825
  is ProductAndroid -> product.oneTimePurchaseOfferDetailsAndroid
821
826
  else -> null
822
827
  }
823
828
 
824
829
  val subscriptionOffersJson = subscriptionOffers.takeIf { it.isNotEmpty() }?.let { serializeSubscriptionOffers(it) }
825
- val oneTimeOfferNitro = oneTimeOffer?.let { otp ->
830
+ val oneTimeOffersNitro = oneTimeOffers?.map { otp ->
826
831
  NitroOneTimePurchaseOfferDetail(
827
832
  formattedPrice = otp.formattedPrice,
828
833
  priceAmountMicros = otp.priceAmountMicros,
829
- priceCurrencyCode = otp.priceCurrencyCode
834
+ priceCurrencyCode = otp.priceCurrencyCode,
835
+ offerId = otp.offerId,
836
+ offerToken = otp.offerToken,
837
+ offerTags = otp.offerTags.toTypedArray(),
838
+ fullPriceMicros = otp.fullPriceMicros,
839
+ discountDisplayInfo = otp.discountDisplayInfo?.let { discount ->
840
+ NitroDiscountDisplayInfoAndroid(
841
+ percentageDiscount = discount.percentageDiscount?.toDouble(),
842
+ discountAmount = discount.discountAmount?.let { amount ->
843
+ NitroDiscountAmountAndroid(
844
+ discountAmountMicros = amount.discountAmountMicros,
845
+ formattedDiscountAmount = amount.formattedDiscountAmount
846
+ )
847
+ }
848
+ )
849
+ },
850
+ validTimeWindow = otp.validTimeWindow?.let { window ->
851
+ NitroValidTimeWindowAndroid(
852
+ startTimeMillis = window.startTimeMillis,
853
+ endTimeMillis = window.endTimeMillis
854
+ )
855
+ },
856
+ limitedQuantityInfo = otp.limitedQuantityInfo?.let { info ->
857
+ NitroLimitedQuantityInfoAndroid(
858
+ maximumQuantity = info.maximumQuantity.toDouble(),
859
+ remainingQuantity = info.remainingQuantity.toDouble()
860
+ )
861
+ },
862
+ preorderDetailsAndroid = otp.preorderDetailsAndroid?.let { preorder ->
863
+ NitroPreorderDetailsAndroid(
864
+ preorderPresaleEndTimeMillis = preorder.preorderPresaleEndTimeMillis,
865
+ preorderReleaseTimeMillis = preorder.preorderReleaseTimeMillis
866
+ )
867
+ },
868
+ rentalDetailsAndroid = otp.rentalDetailsAndroid?.let { rental ->
869
+ NitroRentalDetailsAndroid(
870
+ rentalPeriod = rental.rentalPeriod,
871
+ rentalExpirationPeriod = rental.rentalExpirationPeriod
872
+ )
873
+ }
830
874
  )
831
- }
875
+ }?.toTypedArray()
832
876
 
833
877
  var originalPriceAndroid: String? = null
834
878
  var originalPriceAmountMicrosAndroid: Double? = null
@@ -839,7 +883,7 @@ class HybridRnIap : HybridRnIapSpec() {
839
883
  var freeTrialPeriodAndroid: String? = null
840
884
 
841
885
  if (product.type == ProductType.InApp) {
842
- oneTimeOffer?.let { otp ->
886
+ oneTimeOffers?.firstOrNull()?.let { otp ->
843
887
  originalPriceAndroid = otp.formattedPrice
844
888
  originalPriceAmountMicrosAndroid = otp.priceAmountMicros.toDoubleOrNull()
845
889
  }
@@ -903,7 +947,7 @@ class HybridRnIap : HybridRnIapSpec() {
903
947
  subscriptionPeriodAndroid = subscriptionPeriodAndroid,
904
948
  freeTrialPeriodAndroid = freeTrialPeriodAndroid,
905
949
  subscriptionOfferDetailsAndroid = subscriptionOffersJson,
906
- oneTimePurchaseOfferDetailsAndroid = oneTimeOfferNitro
950
+ oneTimePurchaseOfferDetailsAndroid = oneTimeOffersNitro
907
951
  )
908
952
  }
909
953
 
@@ -957,7 +1001,8 @@ class HybridRnIap : HybridRnIapSpec() {
957
1001
  packageNameAndroid = androidPurchase?.packageNameAndroid,
958
1002
  obfuscatedAccountIdAndroid = androidPurchase?.obfuscatedAccountIdAndroid,
959
1003
  obfuscatedProfileIdAndroid = androidPurchase?.obfuscatedProfileIdAndroid,
960
- developerPayloadAndroid = androidPurchase?.developerPayloadAndroid
1004
+ developerPayloadAndroid = androidPurchase?.developerPayloadAndroid,
1005
+ isSuspendedAndroid = androidPurchase?.isSuspendedAndroid
961
1006
  )
962
1007
  }
963
1008
 
@@ -1341,6 +1386,127 @@ class HybridRnIap : HybridRnIapSpec() {
1341
1386
  }
1342
1387
  }
1343
1388
 
1389
+ // -------------------------------------------------------------------------
1390
+ // Billing Programs API (Android 8.2.0+)
1391
+ // -------------------------------------------------------------------------
1392
+
1393
+ // Create OpenIapStore lazily for Billing Programs API
1394
+ private val openIapStore: OpenIapStore by lazy { OpenIapStore(context) }
1395
+
1396
+ override fun enableBillingProgramAndroid(program: BillingProgramAndroid) {
1397
+ RnIapLog.payload("enableBillingProgramAndroid", mapOf("program" to program.name))
1398
+ try {
1399
+ val openIapProgram = mapBillingProgram(program)
1400
+ openIapStore.enableBillingProgram(openIapProgram)
1401
+ RnIapLog.result("enableBillingProgramAndroid", true)
1402
+ } catch (err: Throwable) {
1403
+ RnIapLog.failure("enableBillingProgramAndroid", err)
1404
+ // enableBillingProgram is void, so we just log the error
1405
+ }
1406
+ }
1407
+
1408
+ override fun isBillingProgramAvailableAndroid(program: BillingProgramAndroid): Promise<NitroBillingProgramAvailabilityResultAndroid> {
1409
+ return Promise.async {
1410
+ RnIapLog.payload("isBillingProgramAvailableAndroid", mapOf("program" to program.name))
1411
+ try {
1412
+ initConnection(null).await()
1413
+ val openIapProgram = mapBillingProgram(program)
1414
+ val result = openIapStore.isBillingProgramAvailable(openIapProgram)
1415
+ val nitroResult = NitroBillingProgramAvailabilityResultAndroid(
1416
+ billingProgram = program,
1417
+ isAvailable = result.isAvailable
1418
+ )
1419
+ RnIapLog.result("isBillingProgramAvailableAndroid", mapOf("isAvailable" to result.isAvailable))
1420
+ nitroResult
1421
+ } catch (err: Throwable) {
1422
+ RnIapLog.failure("isBillingProgramAvailableAndroid", err)
1423
+ val errorType = parseOpenIapError(err)
1424
+ throw OpenIapException(toErrorJson(errorType, debugMessage = err.message))
1425
+ }
1426
+ }
1427
+ }
1428
+
1429
+ override fun createBillingProgramReportingDetailsAndroid(program: BillingProgramAndroid): Promise<NitroBillingProgramReportingDetailsAndroid> {
1430
+ return Promise.async {
1431
+ RnIapLog.payload("createBillingProgramReportingDetailsAndroid", mapOf("program" to program.name))
1432
+ try {
1433
+ initConnection(null).await()
1434
+ val openIapProgram = mapBillingProgram(program)
1435
+ val result = openIapStore.createBillingProgramReportingDetails(openIapProgram)
1436
+ val nitroResult = NitroBillingProgramReportingDetailsAndroid(
1437
+ billingProgram = program,
1438
+ externalTransactionToken = result.externalTransactionToken
1439
+ )
1440
+ RnIapLog.result("createBillingProgramReportingDetailsAndroid", mapOf("hasToken" to true))
1441
+ nitroResult
1442
+ } catch (err: Throwable) {
1443
+ RnIapLog.failure("createBillingProgramReportingDetailsAndroid", err)
1444
+ val errorType = parseOpenIapError(err)
1445
+ throw OpenIapException(toErrorJson(errorType, debugMessage = err.message))
1446
+ }
1447
+ }
1448
+ }
1449
+
1450
+ override fun launchExternalLinkAndroid(params: NitroLaunchExternalLinkParamsAndroid): Promise<Boolean> {
1451
+ return Promise.async {
1452
+ RnIapLog.payload("launchExternalLinkAndroid", mapOf(
1453
+ "billingProgram" to params.billingProgram.name,
1454
+ "launchMode" to params.launchMode.name,
1455
+ "linkType" to params.linkType.name,
1456
+ "linkUri" to params.linkUri
1457
+ ))
1458
+ try {
1459
+ initConnection(null).await()
1460
+
1461
+ val activity = withContext(Dispatchers.Main) {
1462
+ runCatching { context.currentActivity }.getOrNull()
1463
+ } ?: throw OpenIapException(toErrorJson(OpenIAPError.DeveloperError, debugMessage = "Activity not available"))
1464
+
1465
+ val openIapParams = OpenIapLaunchExternalLinkParams(
1466
+ billingProgram = mapBillingProgram(params.billingProgram),
1467
+ launchMode = mapExternalLinkLaunchMode(params.launchMode),
1468
+ linkType = mapExternalLinkType(params.linkType),
1469
+ linkUri = params.linkUri
1470
+ )
1471
+
1472
+ val result = withContext(Dispatchers.Main) {
1473
+ openIapStore.launchExternalLink(activity, openIapParams)
1474
+ }
1475
+ RnIapLog.result("launchExternalLinkAndroid", result)
1476
+ result
1477
+ } catch (err: Throwable) {
1478
+ RnIapLog.failure("launchExternalLinkAndroid", err)
1479
+ val errorType = parseOpenIapError(err)
1480
+ throw OpenIapException(toErrorJson(errorType, debugMessage = err.message))
1481
+ }
1482
+ }
1483
+ }
1484
+
1485
+ // Billing Programs helper functions
1486
+ private fun mapBillingProgram(program: BillingProgramAndroid): OpenIapBillingProgramAndroid {
1487
+ return when (program) {
1488
+ BillingProgramAndroid.UNSPECIFIED -> OpenIapBillingProgramAndroid.Unspecified
1489
+ BillingProgramAndroid.EXTERNAL_CONTENT_LINK -> OpenIapBillingProgramAndroid.ExternalContentLink
1490
+ BillingProgramAndroid.EXTERNAL_OFFER -> OpenIapBillingProgramAndroid.ExternalOffer
1491
+ }
1492
+ }
1493
+
1494
+ private fun mapExternalLinkLaunchMode(mode: ExternalLinkLaunchModeAndroid): OpenIapExternalLinkLaunchMode {
1495
+ return when (mode) {
1496
+ ExternalLinkLaunchModeAndroid.UNSPECIFIED -> OpenIapExternalLinkLaunchMode.Unspecified
1497
+ ExternalLinkLaunchModeAndroid.LAUNCH_IN_EXTERNAL_BROWSER_OR_APP -> OpenIapExternalLinkLaunchMode.LaunchInExternalBrowserOrApp
1498
+ ExternalLinkLaunchModeAndroid.CALLER_WILL_LAUNCH_LINK -> OpenIapExternalLinkLaunchMode.CallerWillLaunchLink
1499
+ }
1500
+ }
1501
+
1502
+ private fun mapExternalLinkType(type: ExternalLinkTypeAndroid): OpenIapExternalLinkType {
1503
+ return when (type) {
1504
+ ExternalLinkTypeAndroid.UNSPECIFIED -> OpenIapExternalLinkType.Unspecified
1505
+ ExternalLinkTypeAndroid.LINK_TO_DIGITAL_CONTENT_OFFER -> OpenIapExternalLinkType.LinkToDigitalContentOffer
1506
+ ExternalLinkTypeAndroid.LINK_TO_APP_DOWNLOAD -> OpenIapExternalLinkType.LinkToAppDownload
1507
+ }
1508
+ }
1509
+
1344
1510
  // -------------------------------------------------------------------------
1345
1511
  // External Purchase (iOS) - Not supported on Android
1346
1512
  // -------------------------------------------------------------------------
@@ -1047,6 +1047,30 @@ class HybridRnIap: HybridRnIapSpec {
1047
1047
  // No-op on iOS
1048
1048
  }
1049
1049
 
1050
+ // MARK: - Billing Programs API (Android 8.2.0+) - Not supported on iOS
1051
+
1052
+ func enableBillingProgramAndroid(program: BillingProgramAndroid) throws {
1053
+ // No-op on iOS - Billing Programs are Android-only
1054
+ }
1055
+
1056
+ func isBillingProgramAvailableAndroid(program: BillingProgramAndroid) throws -> Promise<NitroBillingProgramAvailabilityResultAndroid> {
1057
+ return Promise.async {
1058
+ throw PurchaseError.make(code: .featureNotSupported, message: "Billing Programs API is Android-only")
1059
+ }
1060
+ }
1061
+
1062
+ func createBillingProgramReportingDetailsAndroid(program: BillingProgramAndroid) throws -> Promise<NitroBillingProgramReportingDetailsAndroid> {
1063
+ return Promise.async {
1064
+ throw PurchaseError.make(code: .featureNotSupported, message: "Billing Programs API is Android-only")
1065
+ }
1066
+ }
1067
+
1068
+ func launchExternalLinkAndroid(params: NitroLaunchExternalLinkParamsAndroid) throws -> Promise<Bool> {
1069
+ return Promise.async {
1070
+ throw PurchaseError.make(code: .featureNotSupported, message: "Billing Programs API is Android-only")
1071
+ }
1072
+ }
1073
+
1050
1074
  // MARK: - External Purchase (iOS 16.0+)
1051
1075
 
1052
1076
  func canPresentExternalPurchaseNoticeIOS() throws -> Promise<Bool> {
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ <FileRef
5
+ location = "self:">
6
+ </FileRef>
7
+ </Workspace>
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
@@ -1745,6 +1745,172 @@ export const createAlternativeBillingTokenAndroid = async sku => {
1745
1745
  }
1746
1746
  };
1747
1747
 
1748
+ // ------------------------------
1749
+ // Billing Programs API (Android 8.2.0+)
1750
+ // ------------------------------
1751
+
1752
+ /**
1753
+ * Billing program type for external content links and external offers.
1754
+ * @platform Android
1755
+ * @since Google Play Billing Library 8.2.0+
1756
+ */
1757
+
1758
+ /**
1759
+ * Launch mode for external link flow.
1760
+ * @platform Android
1761
+ * @since Google Play Billing Library 8.2.0+
1762
+ */
1763
+
1764
+ /**
1765
+ * Link type for external link flow.
1766
+ * @platform Android
1767
+ * @since Google Play Billing Library 8.2.0+
1768
+ */
1769
+
1770
+ /**
1771
+ * Parameters for launching an external link (Android 8.2.0+).
1772
+ */
1773
+
1774
+ /**
1775
+ * Result of checking billing program availability (Android 8.2.0+).
1776
+ */
1777
+
1778
+ /**
1779
+ * Reporting details for external transactions (Android 8.2.0+).
1780
+ */
1781
+
1782
+ /**
1783
+ * Enable a billing program before initConnection (Android only).
1784
+ * Must be called BEFORE initConnection() to configure the BillingClient.
1785
+ *
1786
+ * @param program - The billing program to enable (external-content-link or external-offer)
1787
+ * @platform Android
1788
+ * @since Google Play Billing Library 8.2.0+
1789
+ *
1790
+ * @example
1791
+ * ```typescript
1792
+ * // Enable external offers before connecting
1793
+ * enableBillingProgramAndroid('external-offer');
1794
+ * await initConnection();
1795
+ * ```
1796
+ */
1797
+ export const enableBillingProgramAndroid = program => {
1798
+ if (Platform.OS !== 'android') {
1799
+ RnIapConsole.warn('enableBillingProgramAndroid is only supported on Android');
1800
+ return;
1801
+ }
1802
+ try {
1803
+ IAP.instance.enableBillingProgramAndroid(program);
1804
+ } catch (error) {
1805
+ RnIapConsole.error('Failed to enable billing program:', error);
1806
+ }
1807
+ };
1808
+
1809
+ /**
1810
+ * Check if a billing program is available for this user/device (Android only).
1811
+ *
1812
+ * @param program - The billing program to check
1813
+ * @returns Promise with availability result
1814
+ * @platform Android
1815
+ * @since Google Play Billing Library 8.2.0+
1816
+ *
1817
+ * @example
1818
+ * ```typescript
1819
+ * const result = await isBillingProgramAvailableAndroid('external-offer');
1820
+ * if (result.isAvailable) {
1821
+ * // External offers are available for this user
1822
+ * }
1823
+ * ```
1824
+ */
1825
+ export const isBillingProgramAvailableAndroid = async program => {
1826
+ if (Platform.OS !== 'android') {
1827
+ throw new Error('Billing Programs API is only supported on Android');
1828
+ }
1829
+ try {
1830
+ const result = await IAP.instance.isBillingProgramAvailableAndroid(program);
1831
+ return {
1832
+ billingProgram: result.billingProgram,
1833
+ isAvailable: result.isAvailable
1834
+ };
1835
+ } catch (error) {
1836
+ RnIapConsole.error('Failed to check billing program availability:', error);
1837
+ throw error;
1838
+ }
1839
+ };
1840
+
1841
+ /**
1842
+ * Create billing program reporting details for external transactions (Android only).
1843
+ * Used to get the external transaction token needed for reporting to Google.
1844
+ *
1845
+ * @param program - The billing program to create reporting details for
1846
+ * @returns Promise with reporting details including external transaction token
1847
+ * @platform Android
1848
+ * @since Google Play Billing Library 8.2.0+
1849
+ *
1850
+ * @example
1851
+ * ```typescript
1852
+ * const details = await createBillingProgramReportingDetailsAndroid('external-offer');
1853
+ * // Use details.externalTransactionToken to report the transaction
1854
+ * await fetch('/api/report-external-transaction', {
1855
+ * method: 'POST',
1856
+ * body: JSON.stringify({ token: details.externalTransactionToken })
1857
+ * });
1858
+ * ```
1859
+ */
1860
+ export const createBillingProgramReportingDetailsAndroid = async program => {
1861
+ if (Platform.OS !== 'android') {
1862
+ throw new Error('Billing Programs API is only supported on Android');
1863
+ }
1864
+ try {
1865
+ const result = await IAP.instance.createBillingProgramReportingDetailsAndroid(program);
1866
+ return {
1867
+ billingProgram: result.billingProgram,
1868
+ externalTransactionToken: result.externalTransactionToken
1869
+ };
1870
+ } catch (error) {
1871
+ RnIapConsole.error('Failed to create billing program reporting details:', error);
1872
+ throw error;
1873
+ }
1874
+ };
1875
+
1876
+ /**
1877
+ * Launch external link for external offers or app download (Android only).
1878
+ *
1879
+ * @param params - Parameters for launching the external link
1880
+ * @returns Promise<boolean> - true if user accepted, false otherwise
1881
+ * @platform Android
1882
+ * @since Google Play Billing Library 8.2.0+
1883
+ *
1884
+ * @example
1885
+ * ```typescript
1886
+ * const success = await launchExternalLinkAndroid({
1887
+ * billingProgram: 'external-offer',
1888
+ * launchMode: 'launch-in-external-browser-or-app',
1889
+ * linkType: 'link-to-digital-content-offer',
1890
+ * linkUri: 'https://your-website.com/purchase'
1891
+ * });
1892
+ * if (success) {
1893
+ * console.log('User accepted external link');
1894
+ * }
1895
+ * ```
1896
+ */
1897
+ export const launchExternalLinkAndroid = async params => {
1898
+ if (Platform.OS !== 'android') {
1899
+ throw new Error('Billing Programs API is only supported on Android');
1900
+ }
1901
+ try {
1902
+ return await IAP.instance.launchExternalLinkAndroid({
1903
+ billingProgram: params.billingProgram,
1904
+ launchMode: params.launchMode,
1905
+ linkType: params.linkType,
1906
+ linkUri: params.linkUri
1907
+ });
1908
+ } catch (error) {
1909
+ RnIapConsole.error('Failed to launch external link:', error);
1910
+ throw error;
1911
+ }
1912
+ };
1913
+
1748
1914
  // ------------------------------
1749
1915
  // iOS External Purchase
1750
1916
  // ------------------------------