expo-helium 3.0.15 → 3.0.16
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/ios/HeliumPaywallSdkModule.swift +76 -45
- package/package.json +1 -1
|
@@ -33,12 +33,31 @@ struct HasEntitlementResult: Record {
|
|
|
33
33
|
var hasEntitlement: Bool? = nil
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
// Singleton to manage purchase state that survives module deallocation
|
|
37
|
+
private class PurchaseStateManager {
|
|
38
|
+
static let shared = PurchaseStateManager()
|
|
39
|
+
|
|
40
|
+
// Always keep reference to the current module
|
|
41
|
+
var currentModule: HeliumPaywallSdkModule?
|
|
42
|
+
|
|
43
|
+
// Store active operations
|
|
44
|
+
var activePurchaseContinuation: CheckedContinuation<HeliumPaywallTransactionStatus, Never>?
|
|
45
|
+
var activeRestoreContinuation: CheckedContinuation<Bool, Never>?
|
|
46
|
+
var currentProductId: String?
|
|
47
|
+
|
|
48
|
+
private init() {}
|
|
49
|
+
|
|
50
|
+
func clearPurchase() {
|
|
51
|
+
activePurchaseContinuation = nil
|
|
52
|
+
currentProductId = nil
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
func clearRestore() {
|
|
56
|
+
activeRestoreContinuation = nil
|
|
57
|
+
}
|
|
58
|
+
}
|
|
41
59
|
|
|
60
|
+
public class HeliumPaywallSdkModule: Module {
|
|
42
61
|
// Each module class must implement the definition function. The definition consists of components
|
|
43
62
|
// that describes the module's functionality and behavior.
|
|
44
63
|
// See https://docs.expo.dev/modules/module-api for more details about available components.
|
|
@@ -48,6 +67,10 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
48
67
|
// The module will be accessible from `requireNativeModule('HeliumPaywallSdk')` in JavaScript.
|
|
49
68
|
Name("HeliumPaywallSdk")
|
|
50
69
|
|
|
70
|
+
OnCreate {
|
|
71
|
+
PurchaseStateManager.shared.currentModule = self
|
|
72
|
+
}
|
|
73
|
+
|
|
51
74
|
// Sets constant properties on the module. Can take a dictionary or a closure that returns a dictionary.
|
|
52
75
|
// Constants([
|
|
53
76
|
// "PI": Double.pi
|
|
@@ -80,7 +103,7 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
80
103
|
|
|
81
104
|
let useDefaultDelegate = config["useDefaultDelegate"] as? Bool ?? false
|
|
82
105
|
|
|
83
|
-
let delegateEventHandler: (HeliumEvent) -> Void = {
|
|
106
|
+
let delegateEventHandler: (HeliumEvent) -> Void = { event in
|
|
84
107
|
var eventDict = event.toDictionary()
|
|
85
108
|
// Add deprecated fields for backwards compatibility
|
|
86
109
|
if let paywallName = eventDict["paywallName"] {
|
|
@@ -95,47 +118,52 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
95
118
|
if let buttonName = eventDict["buttonName"] {
|
|
96
119
|
eventDict["ctaName"] = buttonName
|
|
97
120
|
}
|
|
98
|
-
|
|
121
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("onHeliumPaywallEvent", eventDict)
|
|
99
122
|
}
|
|
100
123
|
|
|
101
124
|
// Create delegate with closures that send events to JavaScript
|
|
102
125
|
let internalDelegate = InternalDelegate(
|
|
103
126
|
eventHandler: delegateEventHandler,
|
|
104
|
-
purchaseHandler: {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
if let existingContinuation = self.purchaseContinuation {
|
|
127
|
+
purchaseHandler: { productId in
|
|
128
|
+
// First check singleton for orphaned continuation and clean it up
|
|
129
|
+
if let existingContinuation = PurchaseStateManager.shared.activePurchaseContinuation {
|
|
108
130
|
existingContinuation.resume(returning: .cancelled)
|
|
109
|
-
|
|
110
|
-
|
|
131
|
+
PurchaseStateManager.shared.clearPurchase()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Get current module from singleton
|
|
135
|
+
guard let module = PurchaseStateManager.shared.currentModule else {
|
|
136
|
+
return .failed(PurchaseError.purchaseFailed(errorMsg: "Module not active!"))
|
|
111
137
|
}
|
|
112
138
|
|
|
113
139
|
return await withCheckedContinuation { continuation in
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
self.purchaseContinuation = continuation
|
|
140
|
+
PurchaseStateManager.shared.activePurchaseContinuation = continuation
|
|
141
|
+
PurchaseStateManager.shared.currentProductId = productId
|
|
117
142
|
|
|
118
143
|
// Send event to JavaScript
|
|
119
|
-
|
|
144
|
+
module.sendEvent("onDelegateActionEvent", [
|
|
120
145
|
"type": "purchase",
|
|
121
146
|
"productId": productId
|
|
122
147
|
])
|
|
123
148
|
}
|
|
124
149
|
},
|
|
125
|
-
restoreHandler: {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if let existingContinuation = self.restoreContinuation {
|
|
150
|
+
restoreHandler: {
|
|
151
|
+
// Check for orphaned continuation in singleton
|
|
152
|
+
if let existingContinuation = PurchaseStateManager.shared.activeRestoreContinuation {
|
|
129
153
|
existingContinuation.resume(returning: false)
|
|
130
|
-
|
|
154
|
+
PurchaseStateManager.shared.clearRestore()
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// Get current module from singleton
|
|
158
|
+
guard let module = PurchaseStateManager.shared.currentModule else {
|
|
159
|
+
return false
|
|
131
160
|
}
|
|
132
161
|
|
|
133
162
|
return await withCheckedContinuation { continuation in
|
|
134
|
-
|
|
135
|
-
self.restoreContinuation = continuation
|
|
163
|
+
PurchaseStateManager.shared.activeRestoreContinuation = continuation
|
|
136
164
|
|
|
137
165
|
// Send event to JavaScript
|
|
138
|
-
|
|
166
|
+
module.sendEvent("onDelegateActionEvent", [
|
|
139
167
|
"type": "restore"
|
|
140
168
|
])
|
|
141
169
|
}
|
|
@@ -179,8 +207,9 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
179
207
|
}
|
|
180
208
|
|
|
181
209
|
// Function for JavaScript to provide purchase result
|
|
182
|
-
Function("handlePurchaseResult") {
|
|
183
|
-
guard let continuation =
|
|
210
|
+
Function("handlePurchaseResult") { (statusString: String, errorMsg: String?) in
|
|
211
|
+
guard let continuation = PurchaseStateManager.shared.activePurchaseContinuation else {
|
|
212
|
+
print("WARNING: handlePurchaseResult called with no active continuation")
|
|
184
213
|
return
|
|
185
214
|
}
|
|
186
215
|
|
|
@@ -197,21 +226,23 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
197
226
|
default: status = .failed(PurchaseError.unknownStatus(status: lowercasedStatus))
|
|
198
227
|
}
|
|
199
228
|
|
|
200
|
-
// Clear
|
|
201
|
-
|
|
202
|
-
self?.currentProductId = nil
|
|
229
|
+
// Clear singleton state
|
|
230
|
+
PurchaseStateManager.shared.clearPurchase()
|
|
203
231
|
|
|
204
232
|
// Resume the continuation with the status
|
|
205
233
|
continuation.resume(returning: status)
|
|
206
234
|
}
|
|
207
235
|
|
|
208
236
|
// Function for JavaScript to provide restore result
|
|
209
|
-
Function("handleRestoreResult") {
|
|
210
|
-
guard let continuation =
|
|
237
|
+
Function("handleRestoreResult") { (success: Bool) in
|
|
238
|
+
guard let continuation = PurchaseStateManager.shared.activeRestoreContinuation else {
|
|
239
|
+
print("WARNING: handleRestoreResult called with no active continuation")
|
|
211
240
|
return
|
|
212
241
|
}
|
|
213
242
|
|
|
214
|
-
|
|
243
|
+
// Clear singleton state
|
|
244
|
+
PurchaseStateManager.shared.clearRestore()
|
|
245
|
+
|
|
215
246
|
continuation.resume(returning: success)
|
|
216
247
|
}
|
|
217
248
|
|
|
@@ -219,23 +250,23 @@ public class HeliumPaywallSdkModule: Module {
|
|
|
219
250
|
Helium.shared.presentUpsell(
|
|
220
251
|
trigger: trigger,
|
|
221
252
|
eventHandlers: PaywallEventHandlers.withHandlers(
|
|
222
|
-
onOpen: {
|
|
223
|
-
|
|
253
|
+
onOpen: { event in
|
|
254
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
224
255
|
},
|
|
225
|
-
onClose: {
|
|
226
|
-
|
|
256
|
+
onClose: { event in
|
|
257
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
227
258
|
},
|
|
228
|
-
onDismissed: {
|
|
229
|
-
|
|
259
|
+
onDismissed: { event in
|
|
260
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
230
261
|
},
|
|
231
|
-
onPurchaseSucceeded: {
|
|
232
|
-
|
|
262
|
+
onPurchaseSucceeded: { event in
|
|
263
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
233
264
|
},
|
|
234
|
-
onOpenFailed: {
|
|
235
|
-
|
|
265
|
+
onOpenFailed: { event in
|
|
266
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
236
267
|
},
|
|
237
|
-
onCustomPaywallAction: {
|
|
238
|
-
|
|
268
|
+
onCustomPaywallAction: { event in
|
|
269
|
+
PurchaseStateManager.shared.currentModule?.sendEvent("paywallEventHandlers", event.toDictionary())
|
|
239
270
|
}
|
|
240
271
|
),
|
|
241
272
|
customPaywallTraits: convertMarkersToBooleans(customPaywallTraits),
|