@stripe/stripe-react-native 0.45.0 → 0.46.0

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 (85) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/README.md +0 -3
  3. package/android/.gradle/8.11.1/checksums/checksums.lock +0 -0
  4. package/android/.gradle/8.11.1/checksums/md5-checksums.bin +0 -0
  5. package/android/.gradle/8.11.1/checksums/sha1-checksums.bin +0 -0
  6. package/android/.gradle/8.11.1/executionHistory/executionHistory.bin +0 -0
  7. package/android/.gradle/8.11.1/executionHistory/executionHistory.lock +0 -0
  8. package/android/.gradle/8.11.1/fileChanges/last-build.bin +0 -0
  9. package/android/.gradle/8.11.1/fileHashes/fileHashes.bin +0 -0
  10. package/android/.gradle/8.11.1/fileHashes/fileHashes.lock +0 -0
  11. package/android/.gradle/8.11.1/gc.properties +0 -0
  12. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  13. package/android/.gradle/buildOutputCleanup/cache.properties +2 -0
  14. package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
  15. package/android/.gradle/config.properties +2 -0
  16. package/android/.gradle/file-system.probe +0 -0
  17. package/android/.gradle/vcs-1/gc.properties +0 -0
  18. package/android/.idea/caches/deviceStreaming.xml +619 -0
  19. package/android/.idea/compiler.xml +6 -0
  20. package/android/.idea/gradle.xml +19 -0
  21. package/android/.idea/migrations.xml +10 -0
  22. package/android/.idea/misc.xml +10 -0
  23. package/android/.idea/runConfigurations.xml +17 -0
  24. package/android/.idea/vcs.xml +6 -0
  25. package/android/build.gradle +1 -0
  26. package/android/local.properties +8 -0
  27. package/android/src/main/java/com/reactnativestripesdk/CollectBankAccountLauncherFragment.kt +31 -34
  28. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +52 -10
  29. package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +15 -8
  30. package/android/src/main/java/com/reactnativestripesdk/FinancialConnectionsSheetFragment.kt +3 -21
  31. package/android/src/main/java/com/reactnativestripesdk/GooglePayLauncherFragment.kt +3 -17
  32. package/android/src/main/java/com/reactnativestripesdk/GooglePayPaymentMethodLauncherFragment.kt +20 -6
  33. package/android/src/main/java/com/reactnativestripesdk/PaymentLauncherFragment.kt +63 -44
  34. package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +17 -20
  35. package/android/src/main/java/com/reactnativestripesdk/StripeAbstractComposeView.kt +113 -0
  36. package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +74 -6
  37. package/android/src/main/java/com/reactnativestripesdk/addresssheet/AddressLauncherFragment.kt +3 -17
  38. package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetFragment.kt +3 -21
  39. package/android/src/main/java/com/reactnativestripesdk/utils/KeepJsAwakeTask.kt +2 -2
  40. package/android/src/main/java/com/reactnativestripesdk/utils/StripeFragment.kt +52 -0
  41. package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +1 -2
  42. package/ios/EmbeddedPaymentElementView.swift +3 -2
  43. package/ios/NewArch/EmbeddedPaymentElementViewComponentView.h +10 -0
  44. package/ios/NewArch/EmbeddedPaymentElementViewComponentView.mm +81 -0
  45. package/lib/commonjs/components/AddToWalletButton.js +1 -1
  46. package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
  47. package/lib/commonjs/components/AddressSheet.js +1 -1
  48. package/lib/commonjs/components/AddressSheet.js.map +1 -1
  49. package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
  50. package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
  51. package/lib/commonjs/components/CardField.js +1 -1
  52. package/lib/commonjs/components/CardField.js.map +1 -1
  53. package/lib/commonjs/components/CardForm.js +1 -1
  54. package/lib/commonjs/components/CardForm.js.map +1 -1
  55. package/lib/commonjs/components/PlatformPayButton.js +1 -1
  56. package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
  57. package/lib/commonjs/components/StripeContainer.js +1 -1
  58. package/lib/commonjs/components/StripeContainer.js.map +1 -1
  59. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
  60. package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  61. package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
  62. package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
  63. package/lib/module/components/AddToWalletButton.js +1 -1
  64. package/lib/module/components/AddToWalletButton.js.map +1 -1
  65. package/lib/module/components/AddressSheet.js +1 -1
  66. package/lib/module/components/AddressSheet.js.map +1 -1
  67. package/lib/module/components/AuBECSDebitForm.js +1 -1
  68. package/lib/module/components/AuBECSDebitForm.js.map +1 -1
  69. package/lib/module/components/CardField.js +1 -1
  70. package/lib/module/components/CardField.js.map +1 -1
  71. package/lib/module/components/CardForm.js +1 -1
  72. package/lib/module/components/CardForm.js.map +1 -1
  73. package/lib/module/components/PlatformPayButton.js +1 -1
  74. package/lib/module/components/PlatformPayButton.js.map +1 -1
  75. package/lib/module/components/StripeContainer.js +1 -1
  76. package/lib/module/components/StripeContainer.js.map +1 -1
  77. package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
  78. package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
  79. package/lib/module/types/EmbeddedPaymentElement.js +1 -1
  80. package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
  81. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts +0 -5
  82. package/lib/typescript/src/specs/NativeEmbeddedPaymentElement.d.ts.map +1 -1
  83. package/package.json +3 -2
  84. package/src/specs/NativeEmbeddedPaymentElement.ts +1 -10
  85. package/src/types/EmbeddedPaymentElement.tsx +2 -2
@@ -11,13 +11,8 @@ import android.os.Bundle
11
11
  import android.os.Handler
12
12
  import android.os.Looper
13
13
  import android.util.Base64
14
- import android.view.LayoutInflater
15
- import android.view.View
16
- import android.view.ViewGroup
17
- import android.widget.FrameLayout
18
14
  import androidx.appcompat.content.res.AppCompatResources
19
15
  import androidx.core.graphics.drawable.DrawableCompat
20
- import androidx.fragment.app.Fragment
21
16
  import com.facebook.react.bridge.Arguments
22
17
  import com.facebook.react.bridge.Promise
23
18
  import com.facebook.react.bridge.ReactApplicationContext
@@ -30,6 +25,7 @@ import com.reactnativestripesdk.utils.KeepJsAwakeTask
30
25
  import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
31
26
  import com.reactnativestripesdk.utils.PaymentSheetErrorType
32
27
  import com.reactnativestripesdk.utils.PaymentSheetException
28
+ import com.reactnativestripesdk.utils.StripeFragment
33
29
  import com.reactnativestripesdk.utils.createError
34
30
  import com.reactnativestripesdk.utils.createResult
35
31
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
@@ -48,10 +44,9 @@ import java.io.ByteArrayOutputStream
48
44
  import kotlin.Exception
49
45
 
50
46
  @OptIn(ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class)
51
- class PaymentSheetFragment(
52
- private val context: ReactApplicationContext,
53
- private val initPromise: Promise,
54
- ) : Fragment() {
47
+ class PaymentSheetFragment : StripeFragment() {
48
+ private lateinit var context: ReactApplicationContext
49
+ private lateinit var initPromise: Promise
55
50
  private var paymentSheet: PaymentSheet? = null
56
51
  private var flowController: PaymentSheet.FlowController? = null
57
52
  private var paymentIntentClientSecret: String? = null
@@ -64,17 +59,7 @@ class PaymentSheetFragment(
64
59
  internal var paymentSheetIntentCreationCallback = CompletableDeferred<ReadableMap>()
65
60
  private var keepJsAwake: KeepJsAwakeTask? = null
66
61
 
67
- override fun onCreateView(
68
- inflater: LayoutInflater,
69
- container: ViewGroup?,
70
- savedInstanceState: Bundle?,
71
- ): View = FrameLayout(requireActivity()).also { it.visibility = View.GONE }
72
-
73
- override fun onViewCreated(
74
- view: View,
75
- savedInstanceState: Bundle?,
76
- ) {
77
- super.onViewCreated(view, savedInstanceState)
62
+ override fun prepare() {
78
63
  val merchantDisplayName = arguments?.getString("merchantDisplayName").orEmpty()
79
64
  if (merchantDisplayName.isEmpty()) {
80
65
  initPromise.resolve(
@@ -436,6 +421,18 @@ class PaymentSheetFragment(
436
421
  companion object {
437
422
  internal const val TAG = "payment_sheet_launch_fragment"
438
423
 
424
+ internal fun create(
425
+ context: ReactApplicationContext,
426
+ arguments: Bundle,
427
+ initPromise: Promise,
428
+ ): PaymentSheetFragment {
429
+ val instance = PaymentSheetFragment()
430
+ instance.context = context
431
+ instance.initPromise = initPromise
432
+ instance.arguments = arguments
433
+ return instance
434
+ }
435
+
439
436
  private val mapIntToButtonType =
440
437
  mapOf(
441
438
  1 to PaymentSheet.GooglePayConfiguration.ButtonType.Buy,
@@ -0,0 +1,113 @@
1
+ package com.reactnativestripesdk
2
+
3
+ import android.content.Context
4
+ import androidx.compose.runtime.Composable
5
+ import androidx.compose.ui.platform.AbstractComposeView
6
+ import androidx.compose.ui.platform.ViewCompositionStrategy
7
+ import androidx.compose.ui.platform.findViewTreeCompositionContext
8
+ import androidx.lifecycle.Lifecycle
9
+ import androidx.lifecycle.LifecycleEventObserver
10
+ import androidx.lifecycle.LifecycleOwner
11
+ import androidx.lifecycle.LifecycleRegistry
12
+ import androidx.lifecycle.findViewTreeViewModelStoreOwner
13
+ import androidx.lifecycle.setViewTreeLifecycleOwner
14
+ import androidx.lifecycle.setViewTreeViewModelStoreOwner
15
+ import androidx.savedstate.findViewTreeSavedStateRegistryOwner
16
+ import androidx.savedstate.setViewTreeSavedStateRegistryOwner
17
+ import com.facebook.react.bridge.ReactContext
18
+
19
+ /**
20
+ * Compose disposes views by default when using Fragments, which is not compatible with how
21
+ * react-native-screens work. To avoid this we change the composition strategy to use the
22
+ * activity lifecycle instead of the fragment. Note that `setViewTreeLifecycleOwner` also
23
+ * needs to be set otherwise a different code path will dispose of the view.
24
+ *
25
+ * **IMPORTANT** Views using this will need to call `handleOnDropViewInstance` manually to avoid leaking.
26
+ * This can be done using the using the following code in the view manager:
27
+ *
28
+ * ```
29
+ * override fun onDropViewInstance(view: SomeStripeAbstractComposeView) {
30
+ * super.onDropViewInstance(view)
31
+ *
32
+ * view.handleOnDropViewInstance()
33
+ * }
34
+ * ```
35
+ */
36
+ abstract class StripeAbstractComposeView(
37
+ context: Context,
38
+ ) : AbstractComposeView(context) {
39
+ /**
40
+ * Dummy compose view that will be added at the root of the app, this is needed so that the context
41
+ * that compose needs is already initialized and we can set it directly on our compose views.
42
+ * If we do not do this there are cases where react-native initializes compose views in ways that
43
+ * are not supported and causes crashes. An example is when using a compose view inside react-native
44
+ * Modal component.
45
+ */
46
+ class CompatView(
47
+ context: Context,
48
+ ) : AbstractComposeView(context) {
49
+ init {
50
+ visibility = GONE
51
+ }
52
+
53
+ @Composable
54
+ override fun Content() {
55
+ }
56
+ }
57
+
58
+ private var isLifecycleSetup = false
59
+
60
+ // Create a lifecycle this is tied to the activity, but that we can manually
61
+ // update to DESTROYED state when the view is dropped.
62
+ private val lifecycleOwner: LifecycleOwner =
63
+ object : LifecycleOwner {
64
+ override val lifecycle: Lifecycle get() {
65
+ return lifecycleRegistry
66
+ }
67
+ }
68
+ private var lifecycleRegistry = LifecycleRegistry(lifecycleOwner)
69
+
70
+ init {
71
+ // Setup lifecycles
72
+ setViewCompositionStrategy(
73
+ ViewCompositionStrategy.DisposeOnLifecycleDestroyed(lifecycleOwner = lifecycleOwner),
74
+ )
75
+ setViewTreeLifecycleOwner(lifecycleOwner = lifecycleOwner)
76
+
77
+ // Setup context from dummy compose view.
78
+ (context as ReactContext).getNativeModule(StripeSdkModule::class.java)?.composeCompatView?.let {
79
+ setParentCompositionContext(it.findViewTreeCompositionContext())
80
+ setViewTreeSavedStateRegistryOwner(it.findViewTreeSavedStateRegistryOwner())
81
+ setViewTreeViewModelStoreOwner(it.findViewTreeViewModelStoreOwner())
82
+ }
83
+ }
84
+
85
+ override fun onAttachedToWindow() {
86
+ super.onAttachedToWindow()
87
+
88
+ if (isLifecycleSetup) {
89
+ return
90
+ }
91
+
92
+ ((context as? ReactContext)?.currentActivity as? LifecycleOwner?)?.let {
93
+ isLifecycleSetup = true
94
+
95
+ // Setup the lifecycle to match the activity.
96
+ it.lifecycle.addObserver(
97
+ object : LifecycleEventObserver {
98
+ override fun onStateChanged(
99
+ source: LifecycleOwner,
100
+ event: Lifecycle.Event,
101
+ ) {
102
+ lifecycleRegistry.handleLifecycleEvent(event)
103
+ }
104
+ },
105
+ )
106
+ }
107
+ }
108
+
109
+ fun handleOnDropViewInstance() {
110
+ // Update the lifecycle state to DESTROYED to cause the composition to be destroyed.
111
+ lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
112
+ }
113
+ }
@@ -2,8 +2,11 @@ package com.reactnativestripesdk
2
2
 
3
3
  import android.annotation.SuppressLint
4
4
  import android.app.Activity
5
+ import android.app.Application
5
6
  import android.content.Intent
7
+ import android.os.Bundle
6
8
  import android.util.Log
9
+ import android.view.ViewGroup
7
10
  import androidx.fragment.app.FragmentActivity
8
11
  import com.facebook.react.bridge.BaseActivityEventListener
9
12
  import com.facebook.react.bridge.Promise
@@ -11,6 +14,7 @@ import com.facebook.react.bridge.ReactApplicationContext
11
14
  import com.facebook.react.bridge.ReactMethod
12
15
  import com.facebook.react.bridge.ReadableArray
13
16
  import com.facebook.react.bridge.ReadableMap
17
+ import com.facebook.react.bridge.UiThreadUtil
14
18
  import com.facebook.react.bridge.WritableMap
15
19
  import com.facebook.react.bridge.WritableNativeMap
16
20
  import com.facebook.react.module.annotations.ReactModule
@@ -89,6 +93,8 @@ class StripeSdkModule(
89
93
 
90
94
  internal var embeddedIntentCreationCallback = CompletableDeferred<ReadableMap>()
91
95
 
96
+ internal var composeCompatView: StripeAbstractComposeView.CompatView? = null
97
+
92
98
  // If you create a new Fragment, you must put the tag here, otherwise result callbacks for that
93
99
  // Fragment will not work on RN < 0.65
94
100
  private val allStripeFragmentTags: List<String>
@@ -212,6 +218,10 @@ class StripeSdkModule(
212
218
  stripe = Stripe(reactApplicationContext, publishableKey, stripeAccountId)
213
219
 
214
220
  PaymentConfiguration.init(reactApplicationContext, publishableKey, stripeAccountId)
221
+
222
+ preventActivityRecreation()
223
+ setupComposeCompatView()
224
+
215
225
  promise.resolve(null)
216
226
  }
217
227
 
@@ -222,11 +232,9 @@ class StripeSdkModule(
222
232
  ) {
223
233
  getCurrentActivityOrResolveWithError(promise)?.let { activity ->
224
234
  paymentSheetFragment?.removeFragment(reactApplicationContext)
235
+ val bundle = toBundleObject(params)
225
236
  paymentSheetFragment =
226
- PaymentSheetFragment(reactApplicationContext, promise).also {
227
- val bundle = toBundleObject(params)
228
- it.arguments = bundle
229
- }
237
+ PaymentSheetFragment.create(reactApplicationContext, bundle, promise)
230
238
  try {
231
239
  activity.supportFragmentManager
232
240
  .beginTransaction()
@@ -686,7 +694,7 @@ class StripeSdkModule(
686
694
  ) {
687
695
  val googlePayParams = params?.getMap("googlePay")
688
696
  val fragment =
689
- GooglePayPaymentMethodLauncherFragment(
697
+ GooglePayPaymentMethodLauncherFragment.create(
690
698
  reactApplicationContext,
691
699
  getBooleanOrFalse(googlePayParams, "testEnv"),
692
700
  getBooleanOrFalse(googlePayParams, "existingPaymentMethodRequired"),
@@ -927,7 +935,7 @@ class StripeSdkModule(
927
935
  )
928
936
 
929
937
  collectBankAccountLauncherFragment =
930
- CollectBankAccountLauncherFragment(
938
+ CollectBankAccountLauncherFragment.create(
931
939
  reactApplicationContext,
932
940
  publishableKey,
933
941
  stripeAccountId,
@@ -1313,6 +1321,66 @@ class StripeSdkModule(
1313
1321
  return null
1314
1322
  }
1315
1323
 
1324
+ private var isRecreatingActivities = false
1325
+ private val activityLifecycleCallbacks =
1326
+ object : Application.ActivityLifecycleCallbacks {
1327
+ override fun onActivityCreated(
1328
+ activity: Activity,
1329
+ bundle: Bundle?,
1330
+ ) {
1331
+ if (bundle != null) {
1332
+ isRecreatingActivities = true
1333
+ }
1334
+ if (isRecreatingActivities && activity.javaClass.name.startsWith("com.stripe.android")) {
1335
+ activity.finish()
1336
+ }
1337
+ }
1338
+
1339
+ override fun onActivityStarted(activity: Activity) {
1340
+ }
1341
+
1342
+ override fun onActivityResumed(activity: Activity) {
1343
+ isRecreatingActivities = false
1344
+ }
1345
+
1346
+ override fun onActivityPaused(activity: Activity) {
1347
+ }
1348
+
1349
+ override fun onActivityStopped(activity: Activity) {
1350
+ }
1351
+
1352
+ override fun onActivitySaveInstanceState(
1353
+ activity: Activity,
1354
+ bundle: Bundle,
1355
+ ) {
1356
+ }
1357
+
1358
+ override fun onActivityDestroyed(activity: Activity) {
1359
+ }
1360
+ }
1361
+
1362
+ /**
1363
+ * React native apps do not properly handle activity re-creation so make
1364
+ * sure to dismiss any stripe ui when that happens to make sure apps stay
1365
+ * in a consistent state.
1366
+ *
1367
+ * Note that because of some restrictions on some system ui like google
1368
+ * pay this might not always work.
1369
+ */
1370
+ private fun preventActivityRecreation() {
1371
+ currentActivity?.application?.registerActivityLifecycleCallbacks(activityLifecycleCallbacks)
1372
+ }
1373
+
1374
+ private fun setupComposeCompatView() {
1375
+ UiThreadUtil.runOnUiThread {
1376
+ composeCompatView = composeCompatView ?: StripeAbstractComposeView.CompatView(context = reactApplicationContext).also {
1377
+ currentActivity?.findViewById<ViewGroup>(android.R.id.content)?.addView(
1378
+ it,
1379
+ )
1380
+ }
1381
+ }
1382
+ }
1383
+
1316
1384
  companion object {
1317
1385
  const val NAME = NativeStripeSdkModuleSpec.NAME
1318
1386
  }
@@ -1,22 +1,17 @@
1
1
  package com.reactnativestripesdk.addresssheet
2
2
 
3
- import android.os.Bundle
4
- import android.view.LayoutInflater
5
- import android.view.View
6
- import android.view.ViewGroup
7
- import android.widget.FrameLayout
8
- import androidx.fragment.app.Fragment
9
3
  import androidx.fragment.app.FragmentActivity
10
4
  import com.facebook.react.bridge.ReactContext
11
5
  import com.facebook.react.bridge.WritableMap
12
6
  import com.reactnativestripesdk.utils.ErrorType
7
+ import com.reactnativestripesdk.utils.StripeFragment
13
8
  import com.reactnativestripesdk.utils.createError
14
9
  import com.stripe.android.paymentsheet.PaymentSheet
15
10
  import com.stripe.android.paymentsheet.addresselement.AddressDetails
16
11
  import com.stripe.android.paymentsheet.addresselement.AddressLauncher
17
12
  import com.stripe.android.paymentsheet.addresselement.AddressLauncherResult
18
13
 
19
- class AddressLauncherFragment : Fragment() {
14
+ class AddressLauncherFragment : StripeFragment() {
20
15
  companion object {
21
16
  internal var publishableKey: String? = null
22
17
  internal const val TAG = "address_launcher_fragment"
@@ -26,16 +21,7 @@ class AddressLauncherFragment : Fragment() {
26
21
  private var configuration = AddressLauncher.Configuration()
27
22
  private var callback: ((error: WritableMap?, address: AddressDetails?) -> Unit)? = null
28
23
 
29
- override fun onCreateView(
30
- inflater: LayoutInflater,
31
- container: ViewGroup?,
32
- savedInstanceState: Bundle?,
33
- ): View = FrameLayout(requireActivity()).also { it.visibility = View.GONE }
34
-
35
- override fun onViewCreated(
36
- view: View,
37
- savedInstanceState: Bundle?,
38
- ) {
24
+ override fun prepare() {
39
25
  publishableKey?.let { publishableKey ->
40
26
  addressLauncher =
41
27
  AddressLauncher(this, ::onAddressLauncherResult).also {
@@ -7,11 +7,6 @@ import android.os.Bundle
7
7
  import android.os.Handler
8
8
  import android.os.Looper
9
9
  import android.util.Log
10
- import android.view.LayoutInflater
11
- import android.view.View
12
- import android.view.ViewGroup
13
- import android.widget.FrameLayout
14
- import androidx.fragment.app.Fragment
15
10
  import com.facebook.react.bridge.Arguments
16
11
  import com.facebook.react.bridge.Promise
17
12
  import com.facebook.react.bridge.ReactApplicationContext
@@ -28,6 +23,7 @@ import com.reactnativestripesdk.utils.CreateTokenErrorType
28
23
  import com.reactnativestripesdk.utils.ErrorType
29
24
  import com.reactnativestripesdk.utils.KeepJsAwakeTask
30
25
  import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
26
+ import com.reactnativestripesdk.utils.StripeFragment
31
27
  import com.reactnativestripesdk.utils.createError
32
28
  import com.reactnativestripesdk.utils.mapFromPaymentMethod
33
29
  import com.reactnativestripesdk.utils.mapToPreferredNetworks
@@ -44,7 +40,7 @@ import kotlinx.coroutines.Dispatchers
44
40
  import kotlinx.coroutines.launch
45
41
 
46
42
  @OptIn(ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class)
47
- class CustomerSheetFragment : Fragment() {
43
+ class CustomerSheetFragment : StripeFragment() {
48
44
  private var customerSheet: CustomerSheet? = null
49
45
  internal var customerAdapter: ReactNativeCustomerAdapter? = null
50
46
  internal var context: ReactApplicationContext? = null
@@ -52,18 +48,7 @@ class CustomerSheetFragment : Fragment() {
52
48
  private var presentPromise: Promise? = null
53
49
  private var keepJsAwake: KeepJsAwakeTask? = null
54
50
 
55
- override fun onCreateView(
56
- inflater: LayoutInflater,
57
- container: ViewGroup?,
58
- savedInstanceState: Bundle?,
59
- ): View = FrameLayout(requireActivity()).also { it.visibility = View.GONE }
60
-
61
- override fun onViewCreated(
62
- view: View,
63
- savedInstanceState: Bundle?,
64
- ) {
65
- super.onViewCreated(view, savedInstanceState)
66
-
51
+ override fun prepare() {
67
52
  val context =
68
53
  context
69
54
  ?: run {
@@ -196,7 +181,6 @@ class CustomerSheetFragment : Fragment() {
196
181
  }
197
182
 
198
183
  private fun presentWithTimeout(timeout: Long) {
199
- var customerSheetActivity: Activity? = null
200
184
  var activities: MutableList<Activity> = mutableListOf()
201
185
  val activityLifecycleCallbacks =
202
186
  object : Application.ActivityLifecycleCallbacks {
@@ -204,7 +188,6 @@ class CustomerSheetFragment : Fragment() {
204
188
  activity: Activity,
205
189
  savedInstanceState: Bundle?,
206
190
  ) {
207
- customerSheetActivity = activity
208
191
  activities.add(activity)
209
192
  }
210
193
 
@@ -223,7 +206,6 @@ class CustomerSheetFragment : Fragment() {
223
206
  }
224
207
 
225
208
  override fun onActivityDestroyed(activity: Activity) {
226
- customerSheetActivity = null
227
209
  activities = mutableListOf()
228
210
  context?.currentActivity?.application?.unregisterActivityLifecycleCallbacks(this)
229
211
  }
@@ -1,7 +1,7 @@
1
1
  package com.reactnativestripesdk.utils
2
2
 
3
3
  import com.facebook.react.bridge.Arguments
4
- import com.facebook.react.bridge.ReactContext
4
+ import com.facebook.react.bridge.ReactApplicationContext
5
5
  import com.facebook.react.bridge.UiThreadUtil
6
6
  import com.facebook.react.jstasks.HeadlessJsTaskConfig
7
7
  import com.facebook.react.jstasks.HeadlessJsTaskContext
@@ -12,7 +12,7 @@ import com.facebook.react.jstasks.HeadlessJsTaskContext
12
12
  * pausing timers.
13
13
  */
14
14
  internal class KeepJsAwakeTask(
15
- private val context: ReactContext,
15
+ private val context: ReactApplicationContext,
16
16
  ) {
17
17
  private var taskId: Int? = null
18
18
 
@@ -0,0 +1,52 @@
1
+ package com.reactnativestripesdk.utils
2
+
3
+ import android.os.Bundle
4
+ import android.view.LayoutInflater
5
+ import android.view.View
6
+ import android.view.ViewGroup
7
+ import android.widget.FrameLayout
8
+ import androidx.fragment.app.Fragment
9
+ import androidx.fragment.app.FragmentActivity
10
+
11
+ /**
12
+ * Base fragment class to be used to launch Stripe UI that requires a fragment. Use the prepare
13
+ * method to configure it.
14
+ *
15
+ * Note that subclasses of this must implement a no arguments constructor since that is what is
16
+ * invoked when fragments are restored after activity re-creation.
17
+ */
18
+ abstract class StripeFragment : Fragment() {
19
+ private var isRestored = false
20
+
21
+ override fun onCreate(savedInstanceState: Bundle?) {
22
+ super.onCreate(savedInstanceState)
23
+
24
+ isRestored = savedInstanceState != null
25
+ }
26
+
27
+ override fun onCreateView(
28
+ inflater: LayoutInflater,
29
+ container: ViewGroup?,
30
+ savedInstanceState: Bundle?,
31
+ ): View = FrameLayout(requireActivity()).also { it.visibility = View.GONE }
32
+
33
+ override fun onViewCreated(
34
+ view: View,
35
+ savedInstanceState: Bundle?,
36
+ ) {
37
+ super.onViewCreated(view, savedInstanceState)
38
+
39
+ // Prevent fragment from being re-created.
40
+ if (isRestored) {
41
+ (context as? FragmentActivity)
42
+ ?.supportFragmentManager
43
+ ?.beginTransaction()
44
+ ?.remove(this)
45
+ ?.commitAllowingStateLoss()
46
+ } else {
47
+ prepare()
48
+ }
49
+ }
50
+
51
+ abstract fun prepare()
52
+ }
@@ -1,7 +1,6 @@
1
1
  // This is a modified version of the codegen file. Since old arch does not support mEventEmitterCallback
2
2
  // we implement event emitting with RCTDeviceEventEmitter.
3
- // To update this file, take the file generated by codegen and add the `invoke(String, Object)` and
4
- // `invoke(String)` methods. Then replace `mEventEmitterCallback.invoke` with the `invoke` method.
3
+ // To update this file run ./scripts/old-arch-codegen-android
5
4
 
6
5
  /**
7
6
  * This code was generated by [react-native-codegen](https://www.npmjs.com/package/react-native-codegen).
@@ -21,7 +21,8 @@ class EmbeddedPaymentElementView: RCTViewManager {
21
21
  }
22
22
  }
23
23
 
24
- class EmbeddedPaymentElementContainerView: UIView, UIGestureRecognizerDelegate {
24
+ @objc(EmbeddedPaymentElementContainerView)
25
+ public class EmbeddedPaymentElementContainerView: UIView, UIGestureRecognizerDelegate {
25
26
  override init(frame: CGRect) {
26
27
  super.init(frame: frame)
27
28
  backgroundColor = .clear
@@ -33,7 +34,7 @@ class EmbeddedPaymentElementContainerView: UIView, UIGestureRecognizerDelegate {
33
34
  }
34
35
 
35
36
  private func attachPaymentElementIfAvailable() {
36
- guard let embeddedElement = StripeSdkImpl.shared.embeddedInstance else { return }
37
+ guard let embeddedElement = StripeSdkImpl.shared.embeddedInstance else { return }
37
38
  let paymentElementView = embeddedElement.view
38
39
  addSubview(paymentElementView)
39
40
  paymentElementView.translatesAutoresizingMaskIntoConstraints = false
@@ -0,0 +1,10 @@
1
+ #import <UIKit/UIKit.h>
2
+ #import <React/RCTViewComponentView.h>
3
+
4
+ NS_ASSUME_NONNULL_BEGIN
5
+
6
+ @interface EmbeddedPaymentElementViewComponentView : RCTViewComponentView
7
+
8
+ @end
9
+
10
+ NS_ASSUME_NONNULL_END
@@ -0,0 +1,81 @@
1
+ #import "EmbeddedPaymentElementViewComponentView.h"
2
+
3
+ #import <react/renderer/components/rnstripe/ComponentDescriptors.h>
4
+ #import <react/renderer/components/rnstripe/EventEmitters.h>
5
+ #import <react/renderer/components/rnstripe/Props.h>
6
+ #import <react/renderer/components/rnstripe/RCTComponentViewHelpers.h>
7
+
8
+ #import <React/RCTConversions.h>
9
+ #import <React/RCTFabricComponentsPlugins.h>
10
+
11
+ #import "RCTFollyConvert.h"
12
+ #import "StripeSwiftInterop.h"
13
+
14
+ using namespace facebook::react;
15
+
16
+ @interface EmbeddedPaymentElementViewComponentView () <RCTEmbeddedPaymentElementViewViewProtocol>
17
+ @end
18
+
19
+ @implementation EmbeddedPaymentElementViewComponentView {
20
+ EmbeddedPaymentElementContainerView *_view;
21
+ }
22
+
23
+ // Needed because of this: https://github.com/facebook/react-native/pull/37274
24
+ + (void)load
25
+ {
26
+ [super load];
27
+ }
28
+
29
+ - (instancetype)initWithFrame:(CGRect)frame
30
+ {
31
+ if (self = [super initWithFrame:frame]) {
32
+ static const auto defaultProps = std::make_shared<const EmbeddedPaymentElementViewProps>();
33
+ _props = defaultProps;
34
+ [self prepareView];
35
+ }
36
+
37
+ return self;
38
+ }
39
+
40
+ - (void)prepareView
41
+ {
42
+ _view = [EmbeddedPaymentElementContainerView new];
43
+ self.contentView = _view;
44
+ }
45
+
46
+ - (void)handleCommand:(const NSString *)commandName args:(const NSArray *)args
47
+ {
48
+ RCTEmbeddedPaymentElementViewHandleCommand(self, commandName, args);
49
+ }
50
+
51
+ - (void)clearPaymentOption
52
+ {
53
+ // Android only.
54
+ }
55
+
56
+ - (void)confirm
57
+ {
58
+ // Android only.
59
+ }
60
+
61
+ #pragma mark - RCTComponentViewProtocol
62
+
63
+ + (ComponentDescriptorProvider)componentDescriptorProvider
64
+ {
65
+ return concreteComponentDescriptorProvider<EmbeddedPaymentElementViewComponentDescriptor>();
66
+ }
67
+
68
+ - (void)prepareForRecycle
69
+ {
70
+ [super prepareForRecycle];
71
+ [self prepareView];
72
+ }
73
+
74
+
75
+
76
+ @end
77
+
78
+ Class<RCTComponentViewProtocol> EmbeddedPaymentElementViewCls(void)
79
+ {
80
+ return EmbeddedPaymentElementViewComponentView.class;
81
+ }
@@ -1,2 +1,2 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddToWalletButton=_interopRequireDefault(require("../specs/NativeAddToWalletButton"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/davidestes/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddToWalletButton.default,Object.assign({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);}}));}
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddToWalletButton=AddToWalletButton;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddToWalletButton=_interopRequireDefault(require("../specs/NativeAddToWalletButton"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/porter/stripe/stripe-react-native/src/components/AddToWalletButton.tsx";var _excluded=["onComplete"];function AddToWalletButton(_ref){var onComplete=_ref.onComplete,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddToWalletButton.default,Object.assign({},props,{onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);}}));}
2
2
  //# sourceMappingURL=AddToWalletButton.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddToWalletButton","_jsxRuntime","_jsxFileName","_excluded","AddToWalletButton","_ref","onComplete","props","_objectWithoutProperties2","default","jsx","Object","assign","onCompleteAction","value","nativeEvent"],"sourceRoot":"../../../src","sources":["components/AddToWalletButton.tsx"],"mappings":"wSAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAcA,IAAAC,wBAAA,CAAAF,sBAAA,CAAAC,OAAA,sCAAuE,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,yFAAAC,SAAA,gBAgEhE,QAAS,CAAAC,iBAAiBA,CAAAC,IAAA,CAAkC,IAA/B,CAAAC,UAAU,CAAAD,IAAA,CAAVC,UAAU,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAJ,IAAA,CAAAF,SAAA,EACtD,MACE,GAAAF,WAAA,CAAAS,GAAA,EAACV,wBAAA,CAAAS,OAAuB,CAAAE,MAAA,CAAAC,MAAA,IAClBL,KAAK,EACTM,gBAAgB,CAAE,QAAlB,CAAAA,gBAAgBA,CACdC,KAEE,QACC,CAAAR,UAAU,CAACQ,KAAK,CAACC,WAAW,CAAC,EAAC,EACpC,CAAC,CAEN","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddToWalletButton","_jsxRuntime","_jsxFileName","_excluded","AddToWalletButton","_ref","onComplete","props","_objectWithoutProperties2","default","jsx","Object","assign","onCompleteAction","value","nativeEvent"],"sourceRoot":"../../../src","sources":["components/AddToWalletButton.tsx"],"mappings":"wSAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAcA,IAAAC,wBAAA,CAAAF,sBAAA,CAAAC,OAAA,sCAAuE,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,qFAAAC,SAAA,gBAgEhE,QAAS,CAAAC,iBAAiBA,CAAAC,IAAA,CAAkC,IAA/B,CAAAC,UAAU,CAAAD,IAAA,CAAVC,UAAU,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAJ,IAAA,CAAAF,SAAA,EACtD,MACE,GAAAF,WAAA,CAAAS,GAAA,EAACV,wBAAA,CAAAS,OAAuB,CAAAE,MAAA,CAAAC,MAAA,IAClBL,KAAK,EACTM,gBAAgB,CAAE,QAAlB,CAAAA,gBAAgBA,CACdC,KAEE,QACC,CAAAR,UAAU,CAACQ,KAAK,CAACC,WAAW,CAAC,EAAC,EACpC,CAAC,CAEN","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddressSheet=AddressSheet;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddressSheet=_interopRequireDefault(require("../specs/NativeAddressSheet"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/davidestes/stripe/stripe-react-native/src/components/AddressSheet.tsx";var _excluded=["onSubmit","onError"];function AddressSheet(_ref){var onSubmit=_ref.onSubmit,onError=_ref.onError,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddressSheet.default,Object.assign({},props,{onSubmitAction:function onSubmitAction(event){return onSubmit(event.nativeEvent.result);},onErrorAction:function onErrorAction(event){return onError(event.nativeEvent.error);}}));}
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AddressSheet=AddressSheet;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAddressSheet=_interopRequireDefault(require("../specs/NativeAddressSheet"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/porter/stripe/stripe-react-native/src/components/AddressSheet.tsx";var _excluded=["onSubmit","onError"];function AddressSheet(_ref){var onSubmit=_ref.onSubmit,onError=_ref.onError,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAddressSheet.default,Object.assign({},props,{onSubmitAction:function onSubmitAction(event){return onSubmit(event.nativeEvent.result);},onErrorAction:function onErrorAction(event){return onError(event.nativeEvent.error);}}));}
2
2
  //# sourceMappingURL=AddressSheet.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddressSheet","_jsxRuntime","_jsxFileName","_excluded","AddressSheet","_ref","onSubmit","onError","props","_objectWithoutProperties2","default","jsx","Object","assign","onSubmitAction","event","nativeEvent","result","onErrorAction","error"],"sourceRoot":"../../../src","sources":["components/AddressSheet.tsx"],"mappings":"8RAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAQA,IAAAC,mBAAA,CAAAF,sBAAA,CAAAC,OAAA,iCAA6D,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,oFAAAC,SAAA,wBA4DtD,QAAS,CAAAC,YAAYA,CAAAC,IAAA,CAAyC,IAAtC,CAAAC,QAAQ,CAAAD,IAAA,CAARC,QAAQ,CAAEC,OAAO,CAAAF,IAAA,CAAPE,OAAO,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAL,IAAA,CAAAF,SAAA,EACxD,MACE,GAAAF,WAAA,CAAAU,GAAA,EAACX,mBAAA,CAAAU,OAAkB,CAAAE,MAAA,CAAAC,MAAA,IACbL,KAAK,EACTM,cAAc,CAAE,QAAhB,CAAAA,cAAcA,CAAGC,KAAK,QAAK,CAAAT,QAAQ,CAACS,KAAK,CAACC,WAAW,CAACC,MAAM,CAAC,EAAC,CAC9DC,aAAa,CAAE,QAAf,CAAAA,aAAaA,CAAGH,KAAK,QAAK,CAAAR,OAAO,CAACQ,KAAK,CAACC,WAAW,CAACG,KAAK,CAAC,EAAC,EAC5D,CAAC,CAEN","ignoreList":[]}
1
+ {"version":3,"names":["_react","_interopRequireDefault","require","_NativeAddressSheet","_jsxRuntime","_jsxFileName","_excluded","AddressSheet","_ref","onSubmit","onError","props","_objectWithoutProperties2","default","jsx","Object","assign","onSubmitAction","event","nativeEvent","result","onErrorAction","error"],"sourceRoot":"../../../src","sources":["components/AddressSheet.tsx"],"mappings":"8RAAA,IAAAA,MAAA,CAAAC,sBAAA,CAAAC,OAAA,WAQA,IAAAC,mBAAA,CAAAF,sBAAA,CAAAC,OAAA,iCAA6D,IAAAE,WAAA,CAAAF,OAAA,0BAAAG,YAAA,gFAAAC,SAAA,wBA4DtD,QAAS,CAAAC,YAAYA,CAAAC,IAAA,CAAyC,IAAtC,CAAAC,QAAQ,CAAAD,IAAA,CAARC,QAAQ,CAAEC,OAAO,CAAAF,IAAA,CAAPE,OAAO,CAAKC,KAAK,IAAAC,yBAAA,CAAAC,OAAA,EAAAL,IAAA,CAAAF,SAAA,EACxD,MACE,GAAAF,WAAA,CAAAU,GAAA,EAACX,mBAAA,CAAAU,OAAkB,CAAAE,MAAA,CAAAC,MAAA,IACbL,KAAK,EACTM,cAAc,CAAE,QAAhB,CAAAA,cAAcA,CAAGC,KAAK,QAAK,CAAAT,QAAQ,CAACS,KAAK,CAACC,WAAW,CAACC,MAAM,CAAC,EAAC,CAC9DC,aAAa,CAAE,QAAf,CAAAA,aAAaA,CAAGH,KAAK,QAAK,CAAAR,OAAO,CAACQ,KAAK,CAACC,WAAW,CAACG,KAAK,CAAC,EAAC,EAC5D,CAAC,CAEN","ignoreList":[]}
@@ -1,2 +1,2 @@
1
- var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AuBECSDebitForm=AuBECSDebitForm;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAuBECSDebitForm=_interopRequireDefault(require("../specs/NativeAuBECSDebitForm"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/davidestes/stripe/stripe-react-native/src/components/AuBECSDebitForm.tsx";var _excluded=["onComplete","companyName","formStyle"];function AuBECSDebitForm(_ref){var onComplete=_ref.onComplete,companyName=_ref.companyName,formStyle=_ref.formStyle,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAuBECSDebitForm.default,Object.assign({onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);},companyName:companyName,formStyle:Object.assign({},formStyle)},props));}
1
+ var _interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault");Object.defineProperty(exports,"__esModule",{value:true});exports.AuBECSDebitForm=AuBECSDebitForm;var _objectWithoutProperties2=_interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));var _react=_interopRequireDefault(require("react"));var _NativeAuBECSDebitForm=_interopRequireDefault(require("../specs/NativeAuBECSDebitForm"));var _jsxRuntime=require("react/jsx-runtime");var _jsxFileName="/Users/porter/stripe/stripe-react-native/src/components/AuBECSDebitForm.tsx";var _excluded=["onComplete","companyName","formStyle"];function AuBECSDebitForm(_ref){var onComplete=_ref.onComplete,companyName=_ref.companyName,formStyle=_ref.formStyle,props=(0,_objectWithoutProperties2.default)(_ref,_excluded);return(0,_jsxRuntime.jsx)(_NativeAuBECSDebitForm.default,Object.assign({onCompleteAction:function onCompleteAction(value){return onComplete(value.nativeEvent);},companyName:companyName,formStyle:Object.assign({},formStyle)},props));}
2
2
  //# sourceMappingURL=AuBECSDebitForm.js.map