expo-superwall 1.1.4 → 1.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 063189f: Update android version to 2.7.17
8
+
9
+ ## 1.1.5
10
+
11
+ ### Patch Changes
12
+
13
+ - 45be124: Fix purchase events being dropped on cold start when using a custom purchase controller, which left the paywall spinner stuck forever. The native module emitted events through a single static reference that was overwritten by every module instance, so when more than one app context exists (e.g. expo-dev-client's launcher plus the app) the reference could point at an instance whose JS runtime never subscribed and `onPurchase`/`onPurchaseRestore` were silently dropped. Native events are now emitted to every live module instance (tracked weakly) instead of only the most recently created one.
14
+
3
15
  ## 1.1.4
4
16
 
5
17
  ### Patch Changes
@@ -43,7 +43,7 @@ android {
43
43
  }
44
44
 
45
45
  dependencies {
46
- implementation "com.superwall.sdk:superwall-android:2.7.15"
46
+ implementation "com.superwall.sdk:superwall-android:2.7.16"
47
47
  implementation 'com.android.billingclient:billing:8.0.0'
48
48
  implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2'
49
49
  }
@@ -36,12 +36,25 @@ import kotlinx.coroutines.launch
36
36
  import kotlinx.coroutines.future.await
37
37
  import kotlinx.coroutines.runBlocking
38
38
  import android.util.Log
39
+ import java.util.Collections
40
+ import java.util.WeakHashMap
39
41
  import java.util.concurrent.CompletableFuture
40
42
 
41
43
  class SuperwallExpoModule : Module() {
42
44
 
43
45
  companion object {
44
46
  var instance: SuperwallExpoModule? = null
47
+ private val instances = Collections.newSetFromMap(WeakHashMap<SuperwallExpoModule, Boolean>())
48
+
49
+ // Events must reach every live module instance. More than one app context can
50
+ // exist at once (e.g. expo-dev-client's launcher plus the app), and `instance`
51
+ // may point at a module whose JS runtime never subscribed - sending only
52
+ // through it silently drops events like `onPurchase`, leaving the native
53
+ // purchase future incomplete forever.
54
+ fun emitEvent(name: String, body: Map<String, Any?>?) {
55
+ val liveInstances = synchronized(instances) { instances.toList() }
56
+ liveInstances.forEach { it.sendEvent(name, body ?: emptyMap()) }
57
+ }
45
58
  }
46
59
 
47
60
  val scope = CoroutineScope(Dispatchers.Main)
@@ -50,10 +63,7 @@ class SuperwallExpoModule : Module() {
50
63
 
51
64
  init {
52
65
  instance = this
53
- }
54
-
55
- fun emitEvent(name: String, body: Map<String, Any?>?) {
56
- SuperwallExpoModule.instance?.sendEvent(name, body?:emptyMap())
66
+ synchronized(instances) { instances.add(this) }
57
67
  }
58
68
 
59
69
  private val onPaywallPresent = "onPaywallPresent"
@@ -41,7 +41,7 @@ class PurchaseControllerBridge(): PurchaseController {
41
41
  "offerId" to offerId
42
42
  )
43
43
 
44
- SuperwallExpoModule.instance?.emitEvent(
44
+ SuperwallExpoModule.emitEvent(
45
45
  "onPurchase",
46
46
  productData
47
47
  )
@@ -52,7 +52,7 @@ class PurchaseControllerBridge(): PurchaseController {
52
52
  override suspend fun restorePurchases(): RestorationResult {
53
53
  restorePromise = CompletableFuture()
54
54
 
55
- SuperwallExpoModule.instance?.emitEvent("onPurchaseRestore", null)
55
+ SuperwallExpoModule.emitEvent("onPurchaseRestore", null)
56
56
 
57
57
  return restorePromise!!.await()
58
58
  }
@@ -95,7 +95,7 @@ class SuperwallDelegateBridge : SuperwallDelegate {
95
95
  }
96
96
 
97
97
  private fun sendEvent(name: String, body: Map<String, Any?>) {
98
- SuperwallExpoModule.instance?.emitEvent(name, body)
98
+ SuperwallExpoModule.emitEvent(name, body)
99
99
  }
100
100
 
101
101
  override fun willRedeemLink() {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-superwall",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Offical Expo Integration for Superwall",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",
@@ -31,6 +31,7 @@ export declare class PaywallOptions {
31
31
  shouldPreload: boolean;
32
32
  automaticallyDismiss: boolean;
33
33
  transactionBackgroundView: TransactionBackgroundView;
34
+ shouldShowWebPurchaseConfirmationAlert: boolean;
34
35
  onBackPressed?: (paywallInfo: PaywallInfo) => boolean;
35
36
  constructor(init?: Partial<PaywallOptions>);
36
37
  toJson(): object;
@@ -1 +1 @@
1
- {"version":3,"file":"PaywallOptions.d.ts","sourceRoot":"","sources":["../../../../src/compat/lib/PaywallOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAahD;;;;GAIG;AACH,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACxB,KAAK,SAA0B;IAC/B,OAAO,SAA8D;IACrE,gBAAgB,SAAS;IAEzB,MAAM,IAAI,MAAM;CAOjB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,uBAAuB,UAAO;IAC9B,aAAa,EAAE,aAAa,CAAsB;IAClD,8BAA8B,UAAO;IACrC,aAAa,UAAQ;IACrB,oBAAoB,UAAO;IAC3B,yBAAyB,EAAE,yBAAyB,CAAoC;IACxF,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAA;gBAEzC,IAAI,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IA8B1C,MAAM,IAAI,MAAM;CAUjB"}
1
+ {"version":3,"file":"PaywallOptions.d.ts","sourceRoot":"","sources":["../../../../src/compat/lib/PaywallOptions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAahD;;;;GAIG;AACH,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,IAAI,SAAS;CACd;AAED;;;;GAIG;AACH,qBAAa,aAAa;IACxB,KAAK,SAA0B;IAC/B,OAAO,SAA8D;IACrE,gBAAgB,SAAS;IAEzB,MAAM,IAAI,MAAM;CAOjB;AAED;;;;GAIG;AACH,qBAAa,cAAc;IACzB,uBAAuB,UAAO;IAC9B,aAAa,EAAE,aAAa,CAAsB;IAClD,8BAA8B,UAAO;IACrC,aAAa,UAAQ;IACrB,oBAAoB,UAAO;IAC3B,yBAAyB,EAAE,yBAAyB,CAAoC;IACxF,sCAAsC,UAAQ;IAC9C,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,OAAO,CAAA;gBAEzC,IAAI,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC;IAiC1C,MAAM,IAAI,MAAM;CAWjB"}
@@ -45,6 +45,7 @@ export class PaywallOptions {
45
45
  shouldPreload = false;
46
46
  automaticallyDismiss = true;
47
47
  transactionBackgroundView = TransactionBackgroundView.spinner;
48
+ shouldShowWebPurchaseConfirmationAlert = false;
48
49
  onBackPressed;
49
50
  constructor(init) {
50
51
  if (init) {
@@ -57,6 +58,9 @@ export class PaywallOptions {
57
58
  if (init.shouldPreload !== undefined) {
58
59
  this.shouldPreload = init.shouldPreload;
59
60
  }
61
+ if (init.shouldShowWebPurchaseConfirmationAlert !== undefined) {
62
+ this.shouldShowWebPurchaseConfirmationAlert = init.shouldShowWebPurchaseConfirmationAlert;
63
+ }
60
64
  if (init.automaticallyDismiss !== undefined) {
61
65
  this.automaticallyDismiss = init.automaticallyDismiss;
62
66
  }
@@ -83,6 +87,7 @@ export class PaywallOptions {
83
87
  shouldPreload: this.shouldPreload,
84
88
  automaticallyDismiss: this.automaticallyDismiss,
85
89
  transactionBackgroundView: this.transactionBackgroundView,
90
+ shouldShowWebPurchaseConfirmationAlert: this.shouldShowWebPurchaseConfirmationAlert,
86
91
  });
87
92
  }
88
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PaywallOptions.js","sourceRoot":"","sources":["../../../../src/compat/lib/PaywallOptions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PaywallInfo } from \"./PaywallInfo\"\n\n/**\n * Helper function to remove undefined values from an object.\n * This is necessary for Android compatibility as the Expo bridge\n * cannot convert undefined to Kotlin types.\n */\nfunction filterUndefined<T extends Record<string, any>>(obj: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined),\n ) as Partial<T>\n}\n\n/**\n * @category Enums\n * @since 0.0.15\n * Defines the different types of views that can appear behind Apple's payment sheet during a transaction.\n */\nexport enum TransactionBackgroundView {\n spinner = \"spinner\",\n none = \"none\",\n}\n\n/**\n * @category Models\n * @since 0.0.15\n * Defines the messaging of the alert presented to the user when restoring a transaction fails.\n */\nexport class RestoreFailed {\n title = \"No Subscription Found\"\n message = \"We couldn't find an active subscription for your account.\"\n closeButtonTitle = \"Okay\"\n\n toJson(): object {\n return filterUndefined({\n title: this.title,\n message: this.message,\n closeButtonTitle: this.closeButtonTitle,\n })\n }\n}\n\n/**\n * @category Models\n * @since 0.0.15\n * Options for configuring the appearance and behavior of paywalls.\n */\nexport class PaywallOptions {\n isHapticFeedbackEnabled = true\n restoreFailed: RestoreFailed = new RestoreFailed()\n shouldShowPurchaseFailureAlert = true\n shouldPreload = false\n automaticallyDismiss = true\n transactionBackgroundView: TransactionBackgroundView = TransactionBackgroundView.spinner\n onBackPressed?: (paywallInfo: PaywallInfo) => boolean\n\n constructor(init?: Partial<PaywallOptions>) {\n if (init) {\n if (init.isHapticFeedbackEnabled !== undefined) {\n this.isHapticFeedbackEnabled = init.isHapticFeedbackEnabled\n }\n if (init.shouldShowPurchaseFailureAlert !== undefined) {\n this.shouldShowPurchaseFailureAlert = init.shouldShowPurchaseFailureAlert\n }\n if (init.shouldPreload !== undefined) {\n this.shouldPreload = init.shouldPreload\n }\n if (init.automaticallyDismiss !== undefined) {\n this.automaticallyDismiss = init.automaticallyDismiss\n }\n if (init.transactionBackgroundView) {\n this.transactionBackgroundView = init.transactionBackgroundView\n }\n if (init.onBackPressed) {\n this.onBackPressed = init.onBackPressed\n }\n if (init.restoreFailed) {\n // Ensure restoreFailed is always a RestoreFailed instance\n this.restoreFailed =\n init.restoreFailed instanceof RestoreFailed\n ? init.restoreFailed\n : Object.assign(new RestoreFailed(), init.restoreFailed)\n }\n }\n }\n\n toJson(): object {\n return filterUndefined({\n isHapticFeedbackEnabled: this.isHapticFeedbackEnabled,\n restoreFailed: this.restoreFailed.toJson(),\n shouldShowPurchaseFailureAlert: this.shouldShowPurchaseFailureAlert,\n shouldPreload: this.shouldPreload,\n automaticallyDismiss: this.automaticallyDismiss,\n transactionBackgroundView: this.transactionBackgroundView,\n })\n }\n}\n"]}
1
+ {"version":3,"file":"PaywallOptions.js","sourceRoot":"","sources":["../../../../src/compat/lib/PaywallOptions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { PaywallInfo } from \"./PaywallInfo\"\n\n/**\n * Helper function to remove undefined values from an object.\n * This is necessary for Android compatibility as the Expo bridge\n * cannot convert undefined to Kotlin types.\n */\nfunction filterUndefined<T extends Record<string, any>>(obj: T): Partial<T> {\n return Object.fromEntries(\n Object.entries(obj).filter(([_, value]) => value !== undefined),\n ) as Partial<T>\n}\n\n/**\n * @category Enums\n * @since 0.0.15\n * Defines the different types of views that can appear behind Apple's payment sheet during a transaction.\n */\nexport enum TransactionBackgroundView {\n spinner = \"spinner\",\n none = \"none\",\n}\n\n/**\n * @category Models\n * @since 0.0.15\n * Defines the messaging of the alert presented to the user when restoring a transaction fails.\n */\nexport class RestoreFailed {\n title = \"No Subscription Found\"\n message = \"We couldn't find an active subscription for your account.\"\n closeButtonTitle = \"Okay\"\n\n toJson(): object {\n return filterUndefined({\n title: this.title,\n message: this.message,\n closeButtonTitle: this.closeButtonTitle,\n })\n }\n}\n\n/**\n * @category Models\n * @since 0.0.15\n * Options for configuring the appearance and behavior of paywalls.\n */\nexport class PaywallOptions {\n isHapticFeedbackEnabled = true\n restoreFailed: RestoreFailed = new RestoreFailed()\n shouldShowPurchaseFailureAlert = true\n shouldPreload = false\n automaticallyDismiss = true\n transactionBackgroundView: TransactionBackgroundView = TransactionBackgroundView.spinner\n shouldShowWebPurchaseConfirmationAlert = false\n onBackPressed?: (paywallInfo: PaywallInfo) => boolean\n\n constructor(init?: Partial<PaywallOptions>) {\n if (init) {\n if (init.isHapticFeedbackEnabled !== undefined) {\n this.isHapticFeedbackEnabled = init.isHapticFeedbackEnabled\n }\n if (init.shouldShowPurchaseFailureAlert !== undefined) {\n this.shouldShowPurchaseFailureAlert = init.shouldShowPurchaseFailureAlert\n }\n if (init.shouldPreload !== undefined) {\n this.shouldPreload = init.shouldPreload\n }\n if (init.shouldShowWebPurchaseConfirmationAlert !== undefined) {\n this.shouldShowWebPurchaseConfirmationAlert = init.shouldShowWebPurchaseConfirmationAlert\n }\n if (init.automaticallyDismiss !== undefined) {\n this.automaticallyDismiss = init.automaticallyDismiss\n }\n if (init.transactionBackgroundView) {\n this.transactionBackgroundView = init.transactionBackgroundView\n }\n if (init.onBackPressed) {\n this.onBackPressed = init.onBackPressed\n }\n if (init.restoreFailed) {\n // Ensure restoreFailed is always a RestoreFailed instance\n this.restoreFailed =\n init.restoreFailed instanceof RestoreFailed\n ? init.restoreFailed\n : Object.assign(new RestoreFailed(), init.restoreFailed)\n }\n }\n }\n\n toJson(): object {\n return filterUndefined({\n isHapticFeedbackEnabled: this.isHapticFeedbackEnabled,\n restoreFailed: this.restoreFailed.toJson(),\n shouldShowPurchaseFailureAlert: this.shouldShowPurchaseFailureAlert,\n shouldPreload: this.shouldPreload,\n automaticallyDismiss: this.automaticallyDismiss,\n transactionBackgroundView: this.transactionBackgroundView,\n shouldShowWebPurchaseConfirmationAlert: this.shouldShowWebPurchaseConfirmationAlert,\n })\n }\n}\n"]}
@@ -19,6 +19,8 @@ private final class AtomicFlag {
19
19
 
20
20
  public class SuperwallExpoModule: Module {
21
21
  public static var shared: SuperwallExpoModule?
22
+ private static let instancesLock = NSLock()
23
+ private static let instances = NSHashTable<SuperwallExpoModule>.weakObjects()
22
24
 
23
25
  private let purchaseController = PurchaseControllerBridge.shared
24
26
  private var delegate: SuperwallDelegateBridge?
@@ -55,10 +57,23 @@ public class SuperwallExpoModule: Module {
55
57
  public required init(appContext: AppContext) {
56
58
  super.init(appContext: appContext)
57
59
  SuperwallExpoModule.shared = self
60
+ SuperwallExpoModule.instancesLock.lock()
61
+ SuperwallExpoModule.instances.add(self)
62
+ SuperwallExpoModule.instancesLock.unlock()
58
63
  }
59
64
 
65
+ // Events must reach every live module instance. More than one app context can
66
+ // exist at once (e.g. expo-dev-client's launcher plus the app), and `shared`
67
+ // may point at an instance whose JS runtime never subscribed - sending only
68
+ // through it silently drops events like `onPurchase`, leaving the native
69
+ // purchase continuation suspended forever.
60
70
  public static func emitEvent(_ name: String, _ data: [String: Any]?) {
61
- SuperwallExpoModule.shared?.sendEvent(name, data ?? [:])
71
+ instancesLock.lock()
72
+ let liveInstances = instances.allObjects
73
+ instancesLock.unlock()
74
+ for instance in liveInstances {
75
+ instance.sendEvent(name, data ?? [:])
76
+ }
62
77
  }
63
78
 
64
79
  public func definition() -> ModuleDefinition {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-superwall",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Offical Expo Integration for Superwall",
5
5
  "main": "build/src/index.js",
6
6
  "types": "build/src/index.d.ts",