react-native-iap 14.3.5-rc.1 → 14.3.6
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/NitroIap.podspec +1 -1
- package/README.md +1 -1
- package/android/CMakeLists.txt +4 -0
- package/android/build.gradle +2 -2
- package/android/src/main/cpp/cpp-adapter.cpp +8 -0
- package/android/src/main/java/com/margelo/nitro/iap/HybridRnIap.kt +93 -51
- package/ios/HybridRnIap.swift +38 -30
- package/lib/module/hooks/useIAP.js +6 -39
- package/lib/module/hooks/useIAP.js.map +1 -1
- package/lib/module/index.js +54 -55
- package/lib/module/index.js.map +1 -1
- package/lib/module/types.js +1 -1
- package/lib/module/utils/type-bridge.js.map +1 -1
- package/lib/typescript/src/hooks/useIAP.d.ts +4 -8
- package/lib/typescript/src/hooks/useIAP.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +8 -7
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts +2 -1
- package/lib/typescript/src/specs/RnIap.nitro.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +141 -146
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/utils/type-bridge.d.ts.map +1 -1
- package/nitrogen/generated/android/NitroIap+autolinking.cmake +9 -4
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.cpp +32 -5
- package/nitrogen/generated/android/c++/JHybridRnIapSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JIapPlatform.hpp +59 -0
- package/nitrogen/generated/android/c++/JPurchase.cpp +26 -0
- package/nitrogen/generated/android/c++/JPurchase.hpp +80 -0
- package/nitrogen/generated/android/c++/JPurchaseAndroid.hpp +140 -0
- package/nitrogen/generated/android/c++/JPurchaseIOS.hpp +194 -0
- package/nitrogen/generated/android/c++/JPurchaseOfferIOS.hpp +61 -0
- package/nitrogen/generated/android/c++/JPurchaseState.hpp +71 -0
- package/nitrogen/generated/android/c++/JRequestPurchaseResult.hpp +89 -0
- package/nitrogen/generated/android/c++/JVariant_PurchaseAndroid_PurchaseIOS.cpp +26 -0
- package/nitrogen/generated/android/c++/JVariant_PurchaseAndroid_PurchaseIOS.hpp +80 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/HybridRnIapSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/IapPlatform.kt +21 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Purchase.kt +42 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseAndroid.kt +77 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseIOS.kt +116 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseOfferIOS.kt +35 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/PurchaseState.kt +25 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/RequestPurchaseResult.kt +32 -0
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/iap/Variant_PurchaseAndroid_PurchaseIOS.kt +42 -0
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.cpp +13 -5
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Bridge.hpp +186 -25
- package/nitrogen/generated/ios/NitroIap-Swift-Cxx-Umbrella.hpp +18 -0
- package/nitrogen/generated/ios/c++/HybridRnIapSpecSwift.hpp +20 -2
- package/nitrogen/generated/ios/swift/Func_void_RequestPurchaseResult.swift +47 -0
- package/nitrogen/generated/ios/swift/HybridRnIapSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridRnIapSpec_cxx.swift +7 -7
- package/nitrogen/generated/ios/swift/IapPlatform.swift +40 -0
- package/nitrogen/generated/ios/swift/Purchase.swift +18 -0
- package/nitrogen/generated/ios/swift/PurchaseAndroid.swift +399 -0
- package/nitrogen/generated/ios/swift/PurchaseIOS.swift +768 -0
- package/nitrogen/generated/ios/swift/PurchaseOfferIOS.swift +57 -0
- package/nitrogen/generated/ios/swift/PurchaseState.swift +56 -0
- package/nitrogen/generated/ios/swift/RequestPurchaseResult.swift +148 -0
- package/nitrogen/generated/ios/swift/Variant_PurchaseAndroid_PurchaseIOS.swift +18 -0
- package/nitrogen/generated/shared/c++/HybridRnIapSpec.hpp +4 -1
- package/nitrogen/generated/shared/c++/IapPlatform.hpp +76 -0
- package/nitrogen/generated/shared/c++/PurchaseAndroid.hpp +138 -0
- package/nitrogen/generated/shared/c++/PurchaseIOS.hpp +193 -0
- package/nitrogen/generated/shared/c++/PurchaseOfferIOS.hpp +75 -0
- package/nitrogen/generated/shared/c++/PurchaseState.hpp +92 -0
- package/nitrogen/generated/shared/c++/RequestPurchaseResult.hpp +78 -0
- package/package.json +5 -4
- package/plugin/build/withIAP.js +1 -1
- package/plugin/src/withIAP.ts +1 -1
- package/plugin/tsconfig.tsbuildinfo +1 -1
- package/src/hooks/useIAP.ts +17 -59
- package/src/index.ts +73 -77
- package/src/specs/RnIap.nitro.ts +4 -1
- package/src/types.ts +168 -178
- package/src/utils/type-bridge.ts +3 -1
- package/lib/index.d.ts +0 -8
- package/lib/index.js +0 -36
- package/lib/specs/RnIap.nitro.d.ts +0 -7
- package/lib/specs/RnIap.nitro.js +0 -1
package/NitroIap.podspec
CHANGED
package/README.md
CHANGED
|
@@ -94,7 +94,7 @@ Add the OpenIAP Google library to your `android/app/build.gradle` dependencies:
|
|
|
94
94
|
|
|
95
95
|
```gradle
|
|
96
96
|
dependencies {
|
|
97
|
-
implementation "io.github.hyochan.openiap:openiap-google:1.1.
|
|
97
|
+
implementation "io.github.hyochan.openiap:openiap-google:1.1.10"
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
package/android/CMakeLists.txt
CHANGED
|
@@ -13,6 +13,10 @@ add_library(${PACKAGE_NAME} SHARED
|
|
|
13
13
|
src/main/cpp/cpp-adapter.cpp
|
|
14
14
|
)
|
|
15
15
|
|
|
16
|
+
# Ensure Android/iOS preprocessor macros from the NDK do not clash with
|
|
17
|
+
# the generated enum values in Nitrogen headers (IapPlatform.hpp).
|
|
18
|
+
target_compile_options(${PACKAGE_NAME} PRIVATE -UANDROID -UIOS)
|
|
19
|
+
|
|
16
20
|
# Add Nitrogen specs :)
|
|
17
21
|
include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/NitroIap+autolinking.cmake)
|
|
18
22
|
|
package/android/build.gradle
CHANGED
|
@@ -156,8 +156,8 @@ dependencies {
|
|
|
156
156
|
// Kotlin coroutines
|
|
157
157
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.9.0'
|
|
158
158
|
|
|
159
|
-
// OpenIAP Google (v1.1.
|
|
160
|
-
implementation 'io.github.hyochan.openiap:openiap-google:1.1.
|
|
159
|
+
// OpenIAP Google (v1.1.10)
|
|
160
|
+
implementation 'io.github.hyochan.openiap:openiap-google:1.1.10'
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
configurations.all {
|
|
@@ -4,15 +4,15 @@ import android.util.Log
|
|
|
4
4
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
5
5
|
import com.margelo.nitro.NitroModules
|
|
6
6
|
import com.margelo.nitro.core.Promise
|
|
7
|
-
import dev.hyo.openiap.OpenIapError
|
|
7
|
+
import dev.hyo.openiap.OpenIapError as OpenIAPError
|
|
8
8
|
import dev.hyo.openiap.OpenIapModule
|
|
9
9
|
import dev.hyo.openiap.listener.OpenIapPurchaseErrorListener
|
|
10
10
|
import dev.hyo.openiap.listener.OpenIapPurchaseUpdateListener
|
|
11
|
+
import dev.hyo.openiap.models.DeepLinkOptions
|
|
11
12
|
import dev.hyo.openiap.models.OpenIapProduct
|
|
12
13
|
import dev.hyo.openiap.models.OpenIapPurchase
|
|
13
|
-
import dev.hyo.openiap.models.DeepLinkOptions
|
|
14
14
|
import dev.hyo.openiap.models.ProductRequest
|
|
15
|
-
import dev.hyo.openiap.models.
|
|
15
|
+
import dev.hyo.openiap.models.OpenIapRequestPurchaseProps
|
|
16
16
|
import dev.hyo.openiap.models.OpenIapSerialization
|
|
17
17
|
import kotlinx.coroutines.Dispatchers
|
|
18
18
|
import kotlinx.coroutines.withContext
|
|
@@ -68,8 +68,8 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
68
68
|
.onFailure { Log.e(TAG, "Failed to forward purchase update", it) }
|
|
69
69
|
})
|
|
70
70
|
openIap.addPurchaseErrorListener(OpenIapPurchaseErrorListener { e ->
|
|
71
|
-
val code =
|
|
72
|
-
val message = e.message ?:
|
|
71
|
+
val code = OpenIAPError.toCode(e)
|
|
72
|
+
val message = e.message ?: OpenIAPError.defaultMessage(code)
|
|
73
73
|
runCatching {
|
|
74
74
|
sendPurchaseError(
|
|
75
75
|
NitroPurchaseResult(
|
|
@@ -88,12 +88,23 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
88
88
|
val deferred = initDeferred!!
|
|
89
89
|
try {
|
|
90
90
|
val ok = runCatching { openIap.initConnection() }.getOrElse { err ->
|
|
91
|
-
val error =
|
|
92
|
-
throw Exception(
|
|
91
|
+
val error = OpenIAPError.InitConnection()
|
|
92
|
+
throw Exception(
|
|
93
|
+
toErrorJson(
|
|
94
|
+
error = error,
|
|
95
|
+
debugMessage = err.message,
|
|
96
|
+
messageOverride = err.message
|
|
97
|
+
)
|
|
98
|
+
)
|
|
93
99
|
}
|
|
94
100
|
if (!ok) {
|
|
95
|
-
val error =
|
|
96
|
-
throw Exception(
|
|
101
|
+
val error = OpenIAPError.InitConnection()
|
|
102
|
+
throw Exception(
|
|
103
|
+
toErrorJson(
|
|
104
|
+
error = error,
|
|
105
|
+
messageOverride = "Failed to initialize connection"
|
|
106
|
+
)
|
|
107
|
+
)
|
|
97
108
|
}
|
|
98
109
|
isInitialized = true
|
|
99
110
|
deferred.complete(true)
|
|
@@ -125,7 +136,7 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
125
136
|
Log.d(TAG, "fetchProducts (OpenIAP) skus=${skus.joinToString()} type=$type")
|
|
126
137
|
|
|
127
138
|
if (skus.isEmpty()) {
|
|
128
|
-
throw Exception(toErrorJson(
|
|
139
|
+
throw Exception(toErrorJson(OpenIAPError.EmptySkuList))
|
|
129
140
|
}
|
|
130
141
|
|
|
131
142
|
initConnection().await()
|
|
@@ -141,17 +152,19 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
141
152
|
|
|
142
153
|
// Purchase methods
|
|
143
154
|
// Purchase methods (Unified)
|
|
144
|
-
override fun requestPurchase(request: NitroPurchaseRequest): Promise<
|
|
155
|
+
override fun requestPurchase(request: NitroPurchaseRequest): Promise<RequestPurchaseResult> {
|
|
145
156
|
return Promise.async {
|
|
157
|
+
val defaultResult = RequestPurchaseResult(null, null)
|
|
158
|
+
|
|
146
159
|
val androidRequest = request.android ?: run {
|
|
147
160
|
// Programming error: no Android params provided
|
|
148
|
-
sendPurchaseError(toErrorResult(
|
|
149
|
-
return@async
|
|
161
|
+
sendPurchaseError(toErrorResult(OpenIAPError.DeveloperError))
|
|
162
|
+
return@async defaultResult
|
|
150
163
|
}
|
|
151
164
|
|
|
152
165
|
if (androidRequest.skus.isEmpty()) {
|
|
153
|
-
sendPurchaseError(toErrorResult(
|
|
154
|
-
return@async
|
|
166
|
+
sendPurchaseError(toErrorResult(OpenIAPError.EmptySkuList))
|
|
167
|
+
return@async defaultResult
|
|
155
168
|
}
|
|
156
169
|
|
|
157
170
|
try {
|
|
@@ -160,14 +173,14 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
160
173
|
|
|
161
174
|
val missing = androidRequest.skus.firstOrNull { !productTypeBySku.containsKey(it) }
|
|
162
175
|
if (missing != null) {
|
|
163
|
-
sendPurchaseError(toErrorResult(
|
|
164
|
-
return@async
|
|
176
|
+
sendPurchaseError(toErrorResult(OpenIAPError.SkuNotFound(missing), missing))
|
|
177
|
+
return@async defaultResult
|
|
165
178
|
}
|
|
166
179
|
val typeStr = androidRequest.skus.firstOrNull()?.let { productTypeBySku[it] } ?: "inapp"
|
|
167
180
|
val typeEnum = ProductRequest.ProductRequestType.fromString(typeStr)
|
|
168
181
|
|
|
169
182
|
val result = openIap.requestPurchase(
|
|
170
|
-
|
|
183
|
+
OpenIapRequestPurchaseProps(
|
|
171
184
|
skus = androidRequest.skus.toList(),
|
|
172
185
|
obfuscatedAccountIdAndroid = androidRequest.obfuscatedAccountIdAndroid,
|
|
173
186
|
obfuscatedProfileIdAndroid = androidRequest.obfuscatedProfileIdAndroid,
|
|
@@ -180,8 +193,17 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
180
193
|
runCatching { sendPurchaseUpdate(convertToNitroPurchase(p)) }
|
|
181
194
|
.onFailure { Log.e(TAG, "Failed to forward PURCHASE_UPDATED", it) }
|
|
182
195
|
}
|
|
196
|
+
|
|
197
|
+
defaultResult
|
|
183
198
|
} catch (e: Exception) {
|
|
184
|
-
sendPurchaseError(
|
|
199
|
+
sendPurchaseError(
|
|
200
|
+
toErrorResult(
|
|
201
|
+
error = OpenIAPError.PurchaseFailed(),
|
|
202
|
+
debugMessage = e.message,
|
|
203
|
+
messageOverride = e.message
|
|
204
|
+
)
|
|
205
|
+
)
|
|
206
|
+
defaultResult
|
|
185
207
|
}
|
|
186
208
|
}
|
|
187
209
|
}
|
|
@@ -215,7 +237,7 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
215
237
|
NitroPurchaseResult(
|
|
216
238
|
responseCode = -1.0,
|
|
217
239
|
debugMessage = "Missing purchaseToken",
|
|
218
|
-
code =
|
|
240
|
+
code = OpenIAPError.toCode(OpenIAPError.DeveloperError),
|
|
219
241
|
message = "Missing purchaseToken",
|
|
220
242
|
purchaseToken = null
|
|
221
243
|
)
|
|
@@ -226,13 +248,13 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
226
248
|
try {
|
|
227
249
|
initConnection().await()
|
|
228
250
|
} catch (e: Exception) {
|
|
229
|
-
val err =
|
|
251
|
+
val err = OpenIAPError.InitConnection()
|
|
230
252
|
return@async Variant_Boolean_NitroPurchaseResult.Second(
|
|
231
253
|
NitroPurchaseResult(
|
|
232
254
|
responseCode = -1.0,
|
|
233
255
|
debugMessage = e.message,
|
|
234
|
-
code =
|
|
235
|
-
message = err.message,
|
|
256
|
+
code = OpenIAPError.toCode(err),
|
|
257
|
+
message = e.message?.takeIf { it.isNotBlank() } ?: err.message,
|
|
236
258
|
purchaseToken = purchaseToken
|
|
237
259
|
)
|
|
238
260
|
)
|
|
@@ -254,14 +276,14 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
254
276
|
)
|
|
255
277
|
)
|
|
256
278
|
} catch (e: Exception) {
|
|
257
|
-
val err =
|
|
279
|
+
val err = OpenIAPError.BillingError()
|
|
258
280
|
Variant_Boolean_NitroPurchaseResult.Second(
|
|
259
281
|
NitroPurchaseResult(
|
|
260
282
|
responseCode = -1.0,
|
|
261
283
|
debugMessage = e.message,
|
|
262
|
-
code =
|
|
263
|
-
message = err.message,
|
|
264
|
-
purchaseToken =
|
|
284
|
+
code = OpenIAPError.toCode(err),
|
|
285
|
+
message = e.message?.takeIf { it.isNotBlank() } ?: err.message,
|
|
286
|
+
purchaseToken = null
|
|
265
287
|
)
|
|
266
288
|
)
|
|
267
289
|
}
|
|
@@ -356,7 +378,7 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
356
378
|
var subscriptionPeriodAndroid: String? = null
|
|
357
379
|
var freeTrialPeriodAndroid: String? = null
|
|
358
380
|
|
|
359
|
-
if (product.type == OpenIapProduct.ProductType.
|
|
381
|
+
if (product.type == OpenIapProduct.ProductType.InApp) {
|
|
360
382
|
product.oneTimePurchaseOfferDetailsAndroid?.let { otp ->
|
|
361
383
|
originalPriceAndroid = otp.formattedPrice
|
|
362
384
|
// priceAmountMicros is a string; parse to number if possible
|
|
@@ -428,8 +450,8 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
428
450
|
private fun convertToNitroPurchase(purchase: OpenIapPurchase): NitroPurchase {
|
|
429
451
|
// Map OpenIAP purchase state back to legacy numeric Android state for compatibility
|
|
430
452
|
val purchaseStateAndroidNumeric = when (purchase.purchaseState) {
|
|
431
|
-
OpenIapPurchase.PurchaseState.
|
|
432
|
-
OpenIapPurchase.PurchaseState.
|
|
453
|
+
OpenIapPurchase.PurchaseState.Purchased -> 1.0
|
|
454
|
+
OpenIapPurchase.PurchaseState.Pending -> 2.0
|
|
433
455
|
else -> 0.0 // UNSPECIFIED/UNKNOWN/other
|
|
434
456
|
}
|
|
435
457
|
return NitroPurchase(
|
|
@@ -465,14 +487,14 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
465
487
|
// iOS-specific method - not supported on Android
|
|
466
488
|
override fun getStorefrontIOS(): Promise<String> {
|
|
467
489
|
return Promise.async {
|
|
468
|
-
throw Exception(toErrorJson(
|
|
490
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
469
491
|
}
|
|
470
492
|
}
|
|
471
493
|
|
|
472
494
|
// iOS-specific method - not supported on Android
|
|
473
495
|
override fun getAppTransactionIOS(): Promise<String?> {
|
|
474
496
|
return Promise.async {
|
|
475
|
-
throw Exception(toErrorJson(
|
|
497
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
476
498
|
}
|
|
477
499
|
}
|
|
478
500
|
|
|
@@ -558,7 +580,7 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
558
580
|
try {
|
|
559
581
|
// For Android, we need the androidOptions to be provided
|
|
560
582
|
val androidOptions = params.androidOptions
|
|
561
|
-
?: throw Exception(toErrorJson(
|
|
583
|
+
?: throw Exception(toErrorJson(OpenIAPError.DeveloperError))
|
|
562
584
|
|
|
563
585
|
// Android receipt validation would typically involve server-side validation
|
|
564
586
|
// using Google Play Developer API. Here we provide a simplified implementation
|
|
@@ -595,7 +617,15 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
595
617
|
Variant_NitroReceiptValidationResultIOS_NitroReceiptValidationResultAndroid.Second(result)
|
|
596
618
|
|
|
597
619
|
} catch (e: Exception) {
|
|
598
|
-
|
|
620
|
+
val debugMessage = e.message
|
|
621
|
+
val error = OpenIAPError.InvalidReceipt()
|
|
622
|
+
throw Exception(
|
|
623
|
+
toErrorJson(
|
|
624
|
+
error = error,
|
|
625
|
+
debugMessage = debugMessage,
|
|
626
|
+
messageOverride = "Receipt validation failed: ${debugMessage ?: "unknown reason"}"
|
|
627
|
+
)
|
|
628
|
+
)
|
|
599
629
|
}
|
|
600
630
|
}
|
|
601
631
|
}
|
|
@@ -603,31 +633,31 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
603
633
|
// iOS-specific methods - Not applicable on Android, return appropriate defaults
|
|
604
634
|
override fun subscriptionStatusIOS(sku: String): Promise<Array<NitroSubscriptionStatus>?> {
|
|
605
635
|
return Promise.async {
|
|
606
|
-
throw Exception(toErrorJson(
|
|
636
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
607
637
|
}
|
|
608
638
|
}
|
|
609
639
|
|
|
610
640
|
override fun currentEntitlementIOS(sku: String): Promise<NitroPurchase?> {
|
|
611
641
|
return Promise.async {
|
|
612
|
-
throw Exception(toErrorJson(
|
|
642
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
613
643
|
}
|
|
614
644
|
}
|
|
615
645
|
|
|
616
646
|
override fun latestTransactionIOS(sku: String): Promise<NitroPurchase?> {
|
|
617
647
|
return Promise.async {
|
|
618
|
-
throw Exception(toErrorJson(
|
|
648
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
619
649
|
}
|
|
620
650
|
}
|
|
621
651
|
|
|
622
652
|
override fun getPendingTransactionsIOS(): Promise<Array<NitroPurchase>> {
|
|
623
653
|
return Promise.async {
|
|
624
|
-
throw Exception(toErrorJson(
|
|
654
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
625
655
|
}
|
|
626
656
|
}
|
|
627
657
|
|
|
628
658
|
override fun syncIOS(): Promise<Boolean> {
|
|
629
659
|
return Promise.async {
|
|
630
|
-
throw Exception(toErrorJson(
|
|
660
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
631
661
|
}
|
|
632
662
|
}
|
|
633
663
|
|
|
@@ -635,49 +665,61 @@ class HybridRnIap : HybridRnIapSpec() {
|
|
|
635
665
|
|
|
636
666
|
override fun isEligibleForIntroOfferIOS(groupID: String): Promise<Boolean> {
|
|
637
667
|
return Promise.async {
|
|
638
|
-
throw Exception(toErrorJson(
|
|
668
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
639
669
|
}
|
|
640
670
|
}
|
|
641
671
|
|
|
642
672
|
override fun getReceiptDataIOS(): Promise<String> {
|
|
643
673
|
return Promise.async {
|
|
644
|
-
throw Exception(toErrorJson(
|
|
674
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
645
675
|
}
|
|
646
676
|
}
|
|
647
677
|
|
|
648
678
|
override fun isTransactionVerifiedIOS(sku: String): Promise<Boolean> {
|
|
649
679
|
return Promise.async {
|
|
650
|
-
throw Exception(toErrorJson(
|
|
680
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
651
681
|
}
|
|
652
682
|
}
|
|
653
683
|
|
|
654
684
|
override fun getTransactionJwsIOS(sku: String): Promise<String?> {
|
|
655
685
|
return Promise.async {
|
|
656
|
-
throw Exception(toErrorJson(
|
|
686
|
+
throw Exception(toErrorJson(OpenIAPError.NotSupported))
|
|
657
687
|
}
|
|
658
688
|
}
|
|
659
689
|
|
|
660
690
|
// ---------------------------------------------------------------------
|
|
661
691
|
// OpenIAP error helpers: unify error codes/messages from library
|
|
662
692
|
// ---------------------------------------------------------------------
|
|
663
|
-
private fun toErrorJson(
|
|
664
|
-
|
|
665
|
-
|
|
693
|
+
private fun toErrorJson(
|
|
694
|
+
error: OpenIAPError,
|
|
695
|
+
productId: String? = null,
|
|
696
|
+
debugMessage: String? = null,
|
|
697
|
+
messageOverride: String? = null
|
|
698
|
+
): String {
|
|
699
|
+
val code = OpenIAPError.toCode(error)
|
|
700
|
+
val message = messageOverride?.takeIf { it.isNotBlank() }
|
|
701
|
+
?: error.message.ifEmpty { OpenIAPError.defaultMessage(code) }
|
|
666
702
|
return BillingUtils.createErrorJson(
|
|
667
703
|
code = code,
|
|
668
704
|
message = message,
|
|
669
705
|
responseCode = -1,
|
|
670
|
-
debugMessage = error.message,
|
|
706
|
+
debugMessage = debugMessage ?: error.message,
|
|
671
707
|
productId = productId
|
|
672
708
|
)
|
|
673
709
|
}
|
|
674
710
|
|
|
675
|
-
private fun toErrorResult(
|
|
676
|
-
|
|
677
|
-
|
|
711
|
+
private fun toErrorResult(
|
|
712
|
+
error: OpenIAPError,
|
|
713
|
+
productId: String? = null,
|
|
714
|
+
debugMessage: String? = null,
|
|
715
|
+
messageOverride: String? = null
|
|
716
|
+
): NitroPurchaseResult {
|
|
717
|
+
val code = OpenIAPError.toCode(error)
|
|
718
|
+
val message = messageOverride?.takeIf { it.isNotBlank() }
|
|
719
|
+
?: error.message.ifEmpty { OpenIAPError.defaultMessage(code) }
|
|
678
720
|
return NitroPurchaseResult(
|
|
679
721
|
responseCode = -1.0,
|
|
680
|
-
debugMessage = error.message,
|
|
722
|
+
debugMessage = debugMessage ?: error.message,
|
|
681
723
|
code = code,
|
|
682
724
|
message = message,
|
|
683
725
|
purchaseToken = null
|
package/ios/HybridRnIap.swift
CHANGED
|
@@ -164,7 +164,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
164
164
|
} catch {
|
|
165
165
|
// Surface as event and keep flags consistent
|
|
166
166
|
let err = self.createPurchaseErrorResult(
|
|
167
|
-
code: OpenIapError.
|
|
167
|
+
code: OpenIapError.InitConnection,
|
|
168
168
|
message: error.localizedDescription,
|
|
169
169
|
productId: nil
|
|
170
170
|
)
|
|
@@ -198,29 +198,30 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
func requestPurchase(request: NitroPurchaseRequest) throws -> Promise<
|
|
201
|
+
func requestPurchase(request: NitroPurchaseRequest) throws -> Promise<RequestPurchaseResult> {
|
|
202
202
|
return Promise.async {
|
|
203
|
+
let defaultResult = RequestPurchaseResult(purchase: nil, purchases: nil)
|
|
203
204
|
guard let iosRequest = request.ios else {
|
|
204
205
|
let error = self.createPurchaseErrorResult(
|
|
205
|
-
code: OpenIapError.
|
|
206
|
+
code: OpenIapError.UserError,
|
|
206
207
|
message: "No iOS request provided"
|
|
207
208
|
)
|
|
208
209
|
self.sendPurchaseError(error, productId: nil)
|
|
209
|
-
return
|
|
210
|
+
return defaultResult
|
|
210
211
|
}
|
|
211
212
|
do {
|
|
212
213
|
// Event-first behavior: don't reject Promise on connection issues
|
|
213
214
|
guard self.isInitialized else {
|
|
214
215
|
#if DEBUG
|
|
215
|
-
print("[HybridRnIap] requestPurchase while not initialized; sending
|
|
216
|
+
print("[HybridRnIap] requestPurchase while not initialized; sending InitConnection")
|
|
216
217
|
#endif
|
|
217
218
|
let err = self.createPurchaseErrorResult(
|
|
218
|
-
code: OpenIapError.
|
|
219
|
+
code: OpenIapError.InitConnection,
|
|
219
220
|
message: "IAP store connection not initialized",
|
|
220
221
|
productId: iosRequest.sku
|
|
221
222
|
)
|
|
222
223
|
self.sendPurchaseError(err, productId: iosRequest.sku)
|
|
223
|
-
return
|
|
224
|
+
return defaultResult
|
|
224
225
|
}
|
|
225
226
|
// Delegate purchase to OpenIAP. It emits success/error events which we bridge above.
|
|
226
227
|
let props = OpenIapRequestPurchaseProps(
|
|
@@ -238,15 +239,17 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
238
239
|
}
|
|
239
240
|
)
|
|
240
241
|
_ = try await OpenIapModule.shared.requestPurchase(props)
|
|
242
|
+
return defaultResult
|
|
241
243
|
} catch {
|
|
242
244
|
// Ensure an error reaches JS even if OpenIAP threw before emitting.
|
|
243
245
|
// Use simple de-duplication window to avoid double-emitting.
|
|
244
246
|
let err = self.createPurchaseErrorResult(
|
|
245
|
-
code: OpenIapError.
|
|
247
|
+
code: OpenIapError.ServiceError,
|
|
246
248
|
message: error.localizedDescription,
|
|
247
249
|
productId: iosRequest.sku
|
|
248
250
|
)
|
|
249
251
|
self.sendPurchaseErrorDedup(err, productId: iosRequest.sku)
|
|
252
|
+
return defaultResult
|
|
250
253
|
}
|
|
251
254
|
}
|
|
252
255
|
}
|
|
@@ -261,7 +264,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
261
264
|
return purchases.map { self.convertOpenIapPurchaseToNitroPurchase($0) }
|
|
262
265
|
} catch {
|
|
263
266
|
// Propagate OpenIAP error or map to network error
|
|
264
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
267
|
+
throw OpenIapError.make(code: OpenIapError.NetworkError)
|
|
265
268
|
}
|
|
266
269
|
}
|
|
267
270
|
}
|
|
@@ -275,7 +278,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
275
278
|
return .first(ok)
|
|
276
279
|
} catch {
|
|
277
280
|
let tid = iosParams.transactionId
|
|
278
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
281
|
+
throw OpenIapError.make(code: OpenIapError.PurchaseError, message: "Transaction not found: \(tid)")
|
|
279
282
|
}
|
|
280
283
|
}
|
|
281
284
|
}
|
|
@@ -296,7 +299,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
296
299
|
)
|
|
297
300
|
return .first(mapped)
|
|
298
301
|
} catch {
|
|
299
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
302
|
+
throw OpenIapError.make(code: OpenIapError.ReceiptFailed, message: error.localizedDescription)
|
|
300
303
|
}
|
|
301
304
|
}
|
|
302
305
|
}
|
|
@@ -308,7 +311,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
308
311
|
do {
|
|
309
312
|
return try await OpenIapModule.shared.getStorefrontIOS()
|
|
310
313
|
} catch {
|
|
311
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
314
|
+
throw OpenIapError.make(code: OpenIapError.ServiceError, message: error.localizedDescription)
|
|
312
315
|
}
|
|
313
316
|
}
|
|
314
317
|
}
|
|
@@ -384,7 +387,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
384
387
|
return ok
|
|
385
388
|
} catch {
|
|
386
389
|
// Fallback with explicit error for simulator or unsupported cases
|
|
387
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
390
|
+
throw OpenIapError.make(code: OpenIapError.FeatureNotSupported)
|
|
388
391
|
}
|
|
389
392
|
}
|
|
390
393
|
}
|
|
@@ -443,12 +446,13 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
443
446
|
return Promise.async {
|
|
444
447
|
try self.ensureConnection()
|
|
445
448
|
do {
|
|
446
|
-
|
|
447
|
-
|
|
449
|
+
let purchase = try await OpenIapModule.shared.currentEntitlementIOS(sku: sku)
|
|
450
|
+
if let purchase {
|
|
451
|
+
return self.convertOpenIapPurchaseToNitroPurchase(purchase)
|
|
448
452
|
}
|
|
449
|
-
return
|
|
453
|
+
return Optional<NitroPurchase>.none
|
|
450
454
|
} catch {
|
|
451
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
455
|
+
throw OpenIapError.make(code: OpenIapError.SkuNotFound, productId: sku)
|
|
452
456
|
}
|
|
453
457
|
}
|
|
454
458
|
}
|
|
@@ -457,12 +461,13 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
457
461
|
return Promise.async {
|
|
458
462
|
try self.ensureConnection()
|
|
459
463
|
do {
|
|
460
|
-
|
|
461
|
-
|
|
464
|
+
let purchase = try await OpenIapModule.shared.latestTransactionIOS(sku: sku)
|
|
465
|
+
if let purchase {
|
|
466
|
+
return self.convertOpenIapPurchaseToNitroPurchase(purchase)
|
|
462
467
|
}
|
|
463
|
-
return
|
|
468
|
+
return Optional<NitroPurchase>.none
|
|
464
469
|
} catch {
|
|
465
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
470
|
+
throw OpenIapError.make(code: OpenIapError.SkuNotFound, productId: sku)
|
|
466
471
|
}
|
|
467
472
|
}
|
|
468
473
|
}
|
|
@@ -484,7 +489,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
484
489
|
let ok = try await OpenIapModule.shared.syncIOS()
|
|
485
490
|
return ok
|
|
486
491
|
} catch {
|
|
487
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
492
|
+
throw OpenIapError.make(code: OpenIapError.ServiceError, message: error.localizedDescription)
|
|
488
493
|
}
|
|
489
494
|
}
|
|
490
495
|
}
|
|
@@ -498,7 +503,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
498
503
|
let purchases = try await OpenIapModule.shared.getAvailablePurchases(OpenIapPurchaseOptions(alsoPublishToEventListenerIOS: false, onlyIncludeActiveItemsIOS: true))
|
|
499
504
|
return purchases.map { self.convertOpenIapPurchaseToNitroPurchase($0) }
|
|
500
505
|
} catch {
|
|
501
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
506
|
+
throw OpenIapError.make(code: OpenIapError.ServiceError, message: error.localizedDescription)
|
|
502
507
|
}
|
|
503
508
|
}
|
|
504
509
|
}
|
|
@@ -515,9 +520,9 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
515
520
|
if let receipt = try await OpenIapModule.shared.getReceiptDataIOS() {
|
|
516
521
|
return receipt
|
|
517
522
|
}
|
|
518
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
523
|
+
throw OpenIapError.make(code: OpenIapError.ReceiptFailed)
|
|
519
524
|
} catch {
|
|
520
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
525
|
+
throw OpenIapError.make(code: OpenIapError.ReceiptFailed, message: error.localizedDescription)
|
|
521
526
|
}
|
|
522
527
|
}
|
|
523
528
|
}
|
|
@@ -532,8 +537,11 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
532
537
|
func getTransactionJwsIOS(sku: String) throws -> Promise<String?> {
|
|
533
538
|
return Promise.async {
|
|
534
539
|
try self.ensureConnection()
|
|
535
|
-
do {
|
|
536
|
-
|
|
540
|
+
do {
|
|
541
|
+
let jws = try await OpenIapModule.shared.getTransactionJwsIOS(sku: sku)
|
|
542
|
+
return jws
|
|
543
|
+
} catch {
|
|
544
|
+
throw OpenIapError.make(code: OpenIapError.TransactionValidationFailed, message: "Can't find transaction for sku \(sku)")
|
|
537
545
|
}
|
|
538
546
|
}
|
|
539
547
|
}
|
|
@@ -602,7 +610,7 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
602
610
|
|
|
603
611
|
private func ensureConnection() throws {
|
|
604
612
|
guard isInitialized else {
|
|
605
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
613
|
+
throw OpenIapError.make(code: OpenIapError.InitConnection, message: "Connection not initialized. Call initConnection() first.")
|
|
606
614
|
}
|
|
607
615
|
}
|
|
608
616
|
|
|
@@ -720,13 +728,13 @@ class HybridRnIap: HybridRnIapSpec {
|
|
|
720
728
|
// because the TS spec marks them as Android-only.
|
|
721
729
|
func getStorefrontAndroid() throws -> Promise<String> {
|
|
722
730
|
return Promise.async {
|
|
723
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
731
|
+
throw OpenIapError.make(code: OpenIapError.FeatureNotSupported)
|
|
724
732
|
}
|
|
725
733
|
}
|
|
726
734
|
|
|
727
735
|
func deepLinkToSubscriptionsAndroid(options: NitroDeepLinkOptionsAndroid) throws -> Promise<Void> {
|
|
728
736
|
return Promise.async {
|
|
729
|
-
throw OpenIapError.make(code: OpenIapError.
|
|
737
|
+
throw OpenIapError.make(code: OpenIapError.FeatureNotSupported)
|
|
730
738
|
}
|
|
731
739
|
}
|
|
732
740
|
}
|