@stripe/stripe-react-native 0.48.0 → 0.50.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.
- package/CHANGELOG.md +18 -0
- package/README.md +1 -1
- package/android/gradle.properties +1 -1
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/com/reactnativestripesdk/CustomPaymentMethodActivity.kt +81 -0
- package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +171 -56
- package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +34 -3
- package/android/src/main/java/com/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +0 -17
- package/android/src/main/java/com/reactnativestripesdk/PaymentOptionDisplayDataMapper.kt +0 -2
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetAppearance.kt +57 -3
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt +140 -19
- package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +22 -0
- package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +52 -6
- package/android/src/main/res/values/styles.xml +27 -0
- package/android/src/oldarch/java/com/reactnativestripesdk/NativeStripeSdkModuleSpec.java +8 -0
- package/ios/ApplePayButtonManager.m +4 -0
- package/ios/ApplePayButtonView.swift +11 -4
- package/ios/Mappers.swift +0 -5
- package/ios/NewArch/ApplePayButtonComponentView.mm +6 -0
- package/ios/OldArch/StripeSdkEventEmitterCompat.h +1 -1
- package/ios/OldArch/StripeSdkEventEmitterCompat.m +7 -1
- package/ios/PaymentMethodFactory.swift +0 -17
- package/ios/PaymentSheetAppearance.swift +22 -1
- package/ios/StripeSdk.mm +7 -0
- package/ios/StripeSdkEmitter.swift +1 -0
- package/ios/StripeSdkImpl+Embedded.swift +39 -17
- package/ios/StripeSdkImpl+PaymentSheet.swift +156 -5
- package/ios/StripeSdkImpl.swift +43 -10
- package/lib/commonjs/components/AddToWalletButton.js +1 -1
- package/lib/commonjs/components/AddToWalletButton.js.map +1 -1
- package/lib/commonjs/components/AddressSheet.js +1 -1
- package/lib/commonjs/components/AddressSheet.js.map +1 -1
- package/lib/commonjs/components/AuBECSDebitForm.js +1 -1
- package/lib/commonjs/components/AuBECSDebitForm.js.map +1 -1
- package/lib/commonjs/components/CardField.js +1 -1
- package/lib/commonjs/components/CardField.js.map +1 -1
- package/lib/commonjs/components/CardForm.js +1 -1
- package/lib/commonjs/components/CardForm.js.map +1 -1
- package/lib/commonjs/components/CustomerSheet.js +1 -1
- package/lib/commonjs/components/CustomerSheet.js.map +1 -1
- package/lib/commonjs/components/PlatformPayButton.js +1 -1
- package/lib/commonjs/components/PlatformPayButton.js.map +1 -1
- package/lib/commonjs/components/StripeContainer.js +1 -1
- package/lib/commonjs/components/StripeContainer.js.map +1 -1
- package/lib/commonjs/events.js.map +1 -1
- package/lib/commonjs/functions.js +1 -1
- package/lib/commonjs/functions.js.map +1 -1
- package/lib/commonjs/hooks/useStripe.js +1 -1
- package/lib/commonjs/hooks/useStripe.js.map +1 -1
- package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
- package/lib/commonjs/specs/NativeApplePayButton.js.map +1 -1
- package/lib/commonjs/specs/NativeStripeSdkModule.js.map +1 -1
- package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
- package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
- package/lib/commonjs/types/PaymentIntent.js.map +1 -1
- package/lib/commonjs/types/PaymentSheet.js +1 -1
- package/lib/commonjs/types/PaymentSheet.js.map +1 -1
- package/lib/module/components/AddToWalletButton.js +1 -1
- package/lib/module/components/AddToWalletButton.js.map +1 -1
- package/lib/module/components/AddressSheet.js +1 -1
- package/lib/module/components/AddressSheet.js.map +1 -1
- package/lib/module/components/AuBECSDebitForm.js +1 -1
- package/lib/module/components/AuBECSDebitForm.js.map +1 -1
- package/lib/module/components/CardField.js +1 -1
- package/lib/module/components/CardField.js.map +1 -1
- package/lib/module/components/CardForm.js +1 -1
- package/lib/module/components/CardForm.js.map +1 -1
- package/lib/module/components/CustomerSheet.js +1 -1
- package/lib/module/components/CustomerSheet.js.map +1 -1
- package/lib/module/components/PlatformPayButton.js +1 -1
- package/lib/module/components/PlatformPayButton.js.map +1 -1
- package/lib/module/components/StripeContainer.js +1 -1
- package/lib/module/components/StripeContainer.js.map +1 -1
- package/lib/module/events.js.map +1 -1
- package/lib/module/functions.js +1 -1
- package/lib/module/functions.js.map +1 -1
- package/lib/module/hooks/useStripe.js +1 -1
- package/lib/module/hooks/useStripe.js.map +1 -1
- package/lib/module/specs/NativeApplePayButton.js +1 -1
- package/lib/module/specs/NativeApplePayButton.js.map +1 -1
- package/lib/module/specs/NativeStripeSdkModule.js.map +1 -1
- package/lib/module/types/EmbeddedPaymentElement.js +1 -1
- package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
- package/lib/module/types/PaymentIntent.js.map +1 -1
- package/lib/module/types/PaymentSheet.js +1 -1
- package/lib/module/types/PaymentSheet.js.map +1 -1
- package/lib/typescript/src/components/PlatformPayButton.d.ts.map +1 -1
- package/lib/typescript/src/events.d.ts +1 -1
- package/lib/typescript/src/events.d.ts.map +1 -1
- package/lib/typescript/src/functions.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeApplePayButton.d.ts +4 -0
- package/lib/typescript/src/specs/NativeApplePayButton.d.ts.map +1 -1
- package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts +2 -0
- package/lib/typescript/src/specs/NativeStripeSdkModule.d.ts.map +1 -1
- package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts +29 -0
- package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentIntent.d.ts +2 -11
- package/lib/typescript/src/types/PaymentIntent.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentMethod.d.ts +2 -13
- package/lib/typescript/src/types/PaymentMethod.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentSheet.d.ts +78 -2
- package/lib/typescript/src/types/PaymentSheet.d.ts.map +1 -1
- package/package-lock.json +14114 -0
- package/package.json +1 -1
- package/patches/README.md +55 -0
- package/patches/old-arch-codegen-fix.patch +87 -0
- package/src/components/PlatformPayButton.tsx +12 -4
- package/src/events.ts +3 -1
- package/src/functions.ts +36 -1
- package/src/specs/NativeApplePayButton.ts +5 -0
- package/src/specs/NativeStripeSdkModule.ts +4 -0
- package/src/types/EmbeddedPaymentElement.tsx +80 -2
- package/src/types/PaymentIntent.ts +1 -11
- package/src/types/PaymentMethod.ts +0 -14
- package/src/types/PaymentSheet.ts +86 -1
- package/stripe-react-native.podspec +1 -1
- package/android/.gradle/8.11.1/checksums/checksums.lock +0 -0
- package/android/.gradle/8.11.1/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.11.1/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.11.1/executionHistory/executionHistory.bin +0 -0
- package/android/.gradle/8.11.1/executionHistory/executionHistory.lock +0 -0
- package/android/.gradle/8.11.1/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.11.1/fileHashes/fileHashes.bin +0 -0
- package/android/.gradle/8.11.1/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.11.1/gc.properties +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +0 -2
- package/android/.gradle/buildOutputCleanup/outputFiles.bin +0 -0
- package/android/.gradle/config.properties +0 -2
- package/android/.gradle/file-system.probe +0 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/caches/deviceStreaming.xml +0 -619
- package/android/.idea/compiler.xml +0 -6
- package/android/.idea/gradle.xml +0 -19
- package/android/.idea/migrations.xml +0 -10
- package/android/.idea/misc.xml +0 -10
- package/android/.idea/runConfigurations.xml +0 -17
- package/android/.idea/vcs.xml +0 -6
- package/android/local.properties +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## 0.50.0 - 2025-07-17
|
|
4
|
+
|
|
5
|
+
**Features**
|
|
6
|
+
- Added support for Custom Payment Methods in PaymentSheet and Embedded Payment Element.
|
|
7
|
+
|
|
8
|
+
**Fixes**
|
|
9
|
+
- Removed Sofort from playground pages. Sofort is no longer support by Stripe.
|
|
10
|
+
- **Patches**
|
|
11
|
+
- Fixed codegen error when using React Native 0.74+ with old architecture by converting EventEmitter properties to callback functions in TurboModule interface. [#1977](https://github.com/stripe/stripe-react-native/issues/1977). See `patches/README.md` for more info.
|
|
12
|
+
|
|
13
|
+
## 0.49.0 - 2025-07-02
|
|
14
|
+
|
|
15
|
+
**Features**
|
|
16
|
+
- Added rowSelectionBehavior to `EmbeddedPaymentElementConfiguration` with `immediateAction` option
|
|
17
|
+
- Added `flatWithChevron` to `AppearanceParams.embeddedPaymentElement.rowConfig.style`
|
|
18
|
+
- Added `PaymentMethodOptions` to `PaymentMode` to enable setting payment method level setup future usage value
|
|
19
|
+
- Added `None` to `FutureUsage`
|
|
20
|
+
|
|
3
21
|
## 0.48.0 - 2025-06-11
|
|
4
22
|
|
|
5
23
|
**Feature**
|
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ Get started with our [📚 integration guides](https://stripe.com/docs/payments/
|
|
|
23
23
|
|
|
24
24
|
**Native UI**: We provide native screens and elements to securely collect payment details on Android and iOS.
|
|
25
25
|
|
|
26
|
-
**PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay,
|
|
26
|
+
**PaymentSheet**: [Learn how to integrate](https://stripe.com/docs/payments/accept-a-payment) PaymentSheet, our new pre-built payments UI for mobile apps. PaymentSheet lets you accept cards, Apple Pay, Google Pay, and much more out of the box and also supports saving & reusing payment methods. PaymentSheet currently accepts the following payment methods: Card, Apple Pay, Google Pay, SEPA Debit, Bancontact, iDEAL, EPS, P24, Afterpay/Clearpay, Klarna, Giropay, and ACH.
|
|
27
27
|
|
|
28
28
|
#### Recommended usage
|
|
29
29
|
|
|
@@ -3,4 +3,4 @@ StripeSdk_compileSdkVersion=30
|
|
|
3
3
|
StripeSdk_targetSdkVersion=28
|
|
4
4
|
StripeSdk_minSdkVersion=21
|
|
5
5
|
# Keep StripeSdk_stripeVersion in sync with https://github.com/stripe/stripe-identity-react-native/blob/main/android/gradle.properties
|
|
6
|
-
StripeSdk_stripeVersion=21.
|
|
6
|
+
StripeSdk_stripeVersion=21.19.+
|
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
2
|
package="com.reactnativestripesdk">
|
|
3
|
+
|
|
4
|
+
<application>
|
|
5
|
+
<activity
|
|
6
|
+
android:name=".CustomPaymentMethodActivity"
|
|
7
|
+
android:theme="@style/Theme.StripeReactNative.Transparent"
|
|
8
|
+
android:exported="false"
|
|
9
|
+
android:launchMode="singleTop"
|
|
10
|
+
android:excludeFromRecents="true"
|
|
11
|
+
android:noHistory="true" />
|
|
12
|
+
</application>
|
|
3
13
|
</manifest>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
package com.reactnativestripesdk
|
|
2
|
+
|
|
3
|
+
import android.os.Bundle
|
|
4
|
+
import android.view.MotionEvent
|
|
5
|
+
import com.facebook.react.ReactActivity
|
|
6
|
+
import java.lang.ref.WeakReference
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* A transparent activity that is launched when the Payment Element requests the
|
|
10
|
+
* `confirmCustomPaymentMethodCallback`.
|
|
11
|
+
*
|
|
12
|
+
* Its only purpose is to bring the app back to the foreground (the Stripe
|
|
13
|
+
* SDK launches its own proxy activity which pauses the host React Native
|
|
14
|
+
* activity). Having a React (transparent) activity on top ensures that React
|
|
15
|
+
* Native can display UI elements such as `Alert` dialogs coming from
|
|
16
|
+
* JavaScript.
|
|
17
|
+
*
|
|
18
|
+
* The activity uses a translucent theme to minimize visibility and is excluded
|
|
19
|
+
* from recents, though it may still be briefly visible to the end-user during
|
|
20
|
+
* certain operations.
|
|
21
|
+
*/
|
|
22
|
+
class CustomPaymentMethodActivity : ReactActivity() {
|
|
23
|
+
override fun onCreate(savedInstanceState: Bundle?) {
|
|
24
|
+
// Disable the transition animation to make it truly invisible
|
|
25
|
+
overridePendingTransition(0, 0)
|
|
26
|
+
super.onCreate(savedInstanceState)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
override fun getMainComponentName(): String? {
|
|
30
|
+
// We don't want to mount another React Native root – returning null is
|
|
31
|
+
// enough to make ReactActivity skip loading a JS component while still
|
|
32
|
+
// hooking into the lifecycle so that ReactContext is aware of this
|
|
33
|
+
// activity.
|
|
34
|
+
return null
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
|
38
|
+
// Ensure touch events are properly handled by React Native
|
|
39
|
+
return super.onTouchEvent(event)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
|
|
43
|
+
// Ensure touch events are properly dispatched to React Native
|
|
44
|
+
return super.dispatchTouchEvent(event)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
override fun onResume() {
|
|
48
|
+
super.onResume()
|
|
49
|
+
// Ensure the activity is properly focused for touch events
|
|
50
|
+
currentFocus?.requestFocus()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override fun finish() {
|
|
54
|
+
super.finish()
|
|
55
|
+
// Disable the exit animation as well
|
|
56
|
+
overridePendingTransition(0, 0)
|
|
57
|
+
|
|
58
|
+
// Clear the weak reference when finished
|
|
59
|
+
if (currentActivityRef?.get() == this) {
|
|
60
|
+
currentActivityRef = null
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
companion object {
|
|
65
|
+
@Volatile
|
|
66
|
+
private var currentActivityRef: WeakReference<CustomPaymentMethodActivity>? = null
|
|
67
|
+
|
|
68
|
+
fun finishCurrent() {
|
|
69
|
+
currentActivityRef?.get()?.let { activity ->
|
|
70
|
+
activity.runOnUiThread {
|
|
71
|
+
activity.finish()
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
override fun onStart() {
|
|
78
|
+
super.onStart()
|
|
79
|
+
currentActivityRef = WeakReference(this)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
package com.reactnativestripesdk
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.content.Intent
|
|
5
|
+
import android.util.Log
|
|
4
6
|
import androidx.compose.foundation.layout.Box
|
|
5
7
|
import androidx.compose.foundation.layout.requiredHeight
|
|
6
8
|
import androidx.compose.runtime.Composable
|
|
7
9
|
import androidx.compose.runtime.LaunchedEffect
|
|
8
10
|
import androidx.compose.runtime.getValue
|
|
9
11
|
import androidx.compose.runtime.mutableIntStateOf
|
|
12
|
+
import androidx.compose.runtime.mutableStateOf
|
|
10
13
|
import androidx.compose.runtime.remember
|
|
14
|
+
import androidx.compose.runtime.rememberCoroutineScope
|
|
11
15
|
import androidx.compose.runtime.setValue
|
|
12
16
|
import androidx.compose.ui.Modifier
|
|
13
17
|
import androidx.compose.ui.layout.layout
|
|
@@ -18,18 +22,29 @@ import androidx.compose.ui.unit.dp
|
|
|
18
22
|
import com.facebook.react.bridge.Arguments
|
|
19
23
|
import com.facebook.react.uimanager.ThemedReactContext
|
|
20
24
|
import com.reactnativestripesdk.utils.KeepJsAwakeTask
|
|
25
|
+
import com.reactnativestripesdk.utils.mapFromCustomPaymentMethod
|
|
21
26
|
import com.reactnativestripesdk.utils.mapFromPaymentMethod
|
|
27
|
+
import com.stripe.android.model.PaymentMethod
|
|
28
|
+
import com.stripe.android.paymentelement.CustomPaymentMethodResult
|
|
29
|
+
import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
|
|
22
30
|
import com.stripe.android.paymentelement.EmbeddedPaymentElement
|
|
23
|
-
import com.stripe.android.paymentelement.
|
|
31
|
+
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
|
|
24
32
|
import com.stripe.android.paymentelement.rememberEmbeddedPaymentElement
|
|
25
33
|
import com.stripe.android.paymentsheet.CreateIntentResult
|
|
26
34
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
27
35
|
import kotlinx.coroutines.CompletableDeferred
|
|
28
36
|
import kotlinx.coroutines.channels.Channel
|
|
37
|
+
import kotlinx.coroutines.delay
|
|
29
38
|
import kotlinx.coroutines.flow.consumeAsFlow
|
|
39
|
+
import kotlinx.coroutines.launch
|
|
30
40
|
import toWritableMap
|
|
31
41
|
|
|
32
|
-
|
|
42
|
+
enum class RowSelectionBehaviorType {
|
|
43
|
+
Default,
|
|
44
|
+
ImmediateAction,
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
33
48
|
class EmbeddedPaymentElementView(
|
|
34
49
|
context: Context,
|
|
35
50
|
) : StripeAbstractComposeView(context) {
|
|
@@ -47,75 +62,175 @@ class EmbeddedPaymentElementView(
|
|
|
47
62
|
var latestIntentConfig: PaymentSheet.IntentConfiguration? = null
|
|
48
63
|
var latestElementConfig: EmbeddedPaymentElement.Configuration? = null
|
|
49
64
|
|
|
65
|
+
val rowSelectionBehaviorType = mutableStateOf<RowSelectionBehaviorType?>(null)
|
|
66
|
+
|
|
50
67
|
private val reactContext get() = context as ThemedReactContext
|
|
51
68
|
private val events = Channel<Event>(Channel.UNLIMITED)
|
|
52
69
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
70
|
+
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
71
|
+
@Composable
|
|
72
|
+
override fun Content() {
|
|
73
|
+
val type by remember { rowSelectionBehaviorType }
|
|
74
|
+
val coroutineScope = rememberCoroutineScope()
|
|
75
|
+
|
|
76
|
+
val confirmCustomPaymentMethodCallback =
|
|
77
|
+
remember(coroutineScope) {
|
|
78
|
+
{
|
|
79
|
+
customPaymentMethod: PaymentSheet.CustomPaymentMethod,
|
|
80
|
+
billingDetails: PaymentMethod.BillingDetails,
|
|
81
|
+
->
|
|
82
|
+
// Launch a transparent Activity to ensure React Native UI can appear on top of the Stripe proxy activity.
|
|
57
83
|
try {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
84
|
+
val intent =
|
|
85
|
+
Intent(reactContext, CustomPaymentMethodActivity::class.java).apply {
|
|
86
|
+
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
|
87
|
+
addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
|
|
88
|
+
}
|
|
89
|
+
reactContext.startActivity(intent)
|
|
90
|
+
} catch (e: Exception) {
|
|
91
|
+
Log.e("StripeReactNative", "Failed to start CustomPaymentMethodActivity", e)
|
|
67
92
|
}
|
|
68
93
|
|
|
69
|
-
|
|
70
|
-
|
|
94
|
+
val stripeSdkModule =
|
|
95
|
+
try {
|
|
96
|
+
requireStripeSdkModule()
|
|
97
|
+
} catch (ex: IllegalArgumentException) {
|
|
98
|
+
Log.e("StripeReactNative", "StripeSdkModule not found for CPM callback", ex)
|
|
99
|
+
CustomPaymentMethodActivity.finishCurrent()
|
|
100
|
+
return@remember
|
|
101
|
+
}
|
|
71
102
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
|
|
76
|
-
}
|
|
103
|
+
// Keep JS awake while React Native is backgrounded by Stripe SDK.
|
|
104
|
+
val keepJsAwakeTask =
|
|
105
|
+
KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
|
|
77
106
|
|
|
78
|
-
|
|
107
|
+
// Run on coroutine scope.
|
|
108
|
+
coroutineScope.launch {
|
|
109
|
+
try {
|
|
110
|
+
// Give the CustomPaymentMethodActivity a moment to fully initialize
|
|
111
|
+
delay(100)
|
|
79
112
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
113
|
+
// Emit event so JS can show the Alert and eventually respond via `customPaymentMethodResultCallback`.
|
|
114
|
+
stripeSdkModule.emitOnCustomPaymentMethodConfirmHandlerCallback(
|
|
115
|
+
mapFromCustomPaymentMethod(customPaymentMethod, billingDetails),
|
|
116
|
+
)
|
|
83
117
|
|
|
84
|
-
|
|
118
|
+
// Await JS result.
|
|
119
|
+
val resultFromJs = stripeSdkModule.customPaymentMethodResultCallback.await()
|
|
85
120
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
121
|
+
keepJsAwakeTask.stop()
|
|
122
|
+
|
|
123
|
+
val status = resultFromJs.getString("status")
|
|
124
|
+
|
|
125
|
+
val nativeResult =
|
|
126
|
+
when (status) {
|
|
127
|
+
"completed" ->
|
|
128
|
+
CustomPaymentMethodResult
|
|
129
|
+
.completed()
|
|
130
|
+
"canceled" ->
|
|
131
|
+
CustomPaymentMethodResult
|
|
132
|
+
.canceled()
|
|
133
|
+
"failed" -> {
|
|
134
|
+
val errMsg = resultFromJs.getString("error") ?: "Custom payment failed"
|
|
135
|
+
CustomPaymentMethodResult
|
|
136
|
+
.failed(displayMessage = errMsg)
|
|
137
|
+
}
|
|
138
|
+
else ->
|
|
139
|
+
CustomPaymentMethodResult
|
|
140
|
+
.failed(displayMessage = "Unknown status")
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Return result to Stripe SDK.
|
|
144
|
+
CustomPaymentMethodResultHandler.handleCustomPaymentMethodResult(
|
|
145
|
+
reactContext,
|
|
146
|
+
nativeResult,
|
|
147
|
+
)
|
|
148
|
+
} finally {
|
|
149
|
+
// Clean up the transparent activity
|
|
150
|
+
CustomPaymentMethodActivity.finishCurrent()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
94
153
|
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
val builder =
|
|
157
|
+
remember(type) {
|
|
158
|
+
EmbeddedPaymentElement
|
|
159
|
+
.Builder(
|
|
160
|
+
createIntentCallback = { paymentMethod, shouldSavePaymentMethod ->
|
|
161
|
+
val stripeSdkModule =
|
|
162
|
+
try {
|
|
163
|
+
requireStripeSdkModule()
|
|
164
|
+
} catch (ex: IllegalArgumentException) {
|
|
165
|
+
return@Builder CreateIntentResult.Failure(
|
|
166
|
+
cause =
|
|
167
|
+
Exception(
|
|
168
|
+
"Tried to call confirmHandler, but no callback was found. Please file an issue: https://github.com/stripe/stripe-react-native/issues",
|
|
169
|
+
),
|
|
170
|
+
displayMessage = "An unexpected error occurred",
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Make sure that JS is active since the activity will be paused when stripe ui is presented.
|
|
175
|
+
val keepJsAwakeTask =
|
|
176
|
+
KeepJsAwakeTask(reactContext.reactApplicationContext).apply { start() }
|
|
177
|
+
|
|
178
|
+
val params =
|
|
179
|
+
Arguments.createMap().apply {
|
|
180
|
+
putMap("paymentMethod", mapFromPaymentMethod(paymentMethod))
|
|
181
|
+
putBoolean("shouldSavePaymentMethod", shouldSavePaymentMethod)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
stripeSdkModule.emitOnConfirmHandlerCallback(params)
|
|
185
|
+
|
|
186
|
+
val resultFromJavascript = stripeSdkModule.embeddedIntentCreationCallback.await()
|
|
187
|
+
// reset the completable
|
|
188
|
+
stripeSdkModule.embeddedIntentCreationCallback = CompletableDeferred()
|
|
189
|
+
|
|
190
|
+
keepJsAwakeTask.stop()
|
|
191
|
+
|
|
192
|
+
resultFromJavascript.getString("clientSecret")?.let {
|
|
193
|
+
CreateIntentResult.Success(clientSecret = it)
|
|
194
|
+
} ?: run {
|
|
195
|
+
val errorMap = resultFromJavascript.getMap("error")
|
|
196
|
+
CreateIntentResult.Failure(
|
|
197
|
+
cause = Exception(errorMap?.getString("message")),
|
|
198
|
+
displayMessage = errorMap?.getString("localizedMessage"),
|
|
199
|
+
)
|
|
105
200
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
201
|
+
},
|
|
202
|
+
resultCallback = { result ->
|
|
203
|
+
val map =
|
|
204
|
+
Arguments.createMap().apply {
|
|
205
|
+
when (result) {
|
|
206
|
+
is EmbeddedPaymentElement.Result.Completed -> {
|
|
207
|
+
putString("status", "completed")
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
is EmbeddedPaymentElement.Result.Canceled -> {
|
|
211
|
+
putString("status", "canceled")
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
is EmbeddedPaymentElement.Result.Failed -> {
|
|
215
|
+
putString("status", "failed")
|
|
216
|
+
putString("error", result.error.message ?: "Unknown error")
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
requireStripeSdkModule().emitEmbeddedPaymentElementFormSheetConfirmComplete(map)
|
|
221
|
+
},
|
|
222
|
+
).confirmCustomPaymentMethodCallback(confirmCustomPaymentMethodCallback)
|
|
223
|
+
.rowSelectionBehavior(
|
|
224
|
+
if (type == RowSelectionBehaviorType.Default) {
|
|
225
|
+
EmbeddedPaymentElement.RowSelectionBehavior.default()
|
|
226
|
+
} else {
|
|
227
|
+
EmbeddedPaymentElement.RowSelectionBehavior.immediateAction {
|
|
228
|
+
requireStripeSdkModule().emitEmbeddedPaymentElementRowSelectionImmediateAction()
|
|
109
229
|
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
},
|
|
114
|
-
)
|
|
115
|
-
}
|
|
230
|
+
},
|
|
231
|
+
)
|
|
232
|
+
}
|
|
116
233
|
|
|
117
|
-
@Composable
|
|
118
|
-
override fun Content() {
|
|
119
234
|
val embedded = rememberEmbeddedPaymentElement(builder)
|
|
120
235
|
var height by remember {
|
|
121
236
|
mutableIntStateOf(0)
|
|
@@ -18,13 +18,13 @@ import com.reactnativestripesdk.addresssheet.AddressSheetView
|
|
|
18
18
|
import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
|
|
19
19
|
import com.reactnativestripesdk.utils.PaymentSheetException
|
|
20
20
|
import com.reactnativestripesdk.utils.mapToPreferredNetworks
|
|
21
|
+
import com.reactnativestripesdk.utils.parseCustomPaymentMethods
|
|
21
22
|
import com.reactnativestripesdk.utils.toBundleObject
|
|
22
23
|
import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
|
|
23
24
|
import com.stripe.android.paymentelement.EmbeddedPaymentElement
|
|
24
|
-
import com.stripe.android.paymentelement.
|
|
25
|
+
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
|
|
25
26
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
26
27
|
|
|
27
|
-
@OptIn(ExperimentalEmbeddedPaymentElementApi::class)
|
|
28
28
|
@ReactModule(name = EmbeddedPaymentElementViewManager.NAME)
|
|
29
29
|
class EmbeddedPaymentElementViewManager :
|
|
30
30
|
ViewGroupManager<EmbeddedPaymentElementView>(),
|
|
@@ -54,6 +54,9 @@ class EmbeddedPaymentElementViewManager :
|
|
|
54
54
|
view: EmbeddedPaymentElementView,
|
|
55
55
|
cfg: Dynamic,
|
|
56
56
|
) {
|
|
57
|
+
val rowSelectionBehaviorType = parseRowSelectionBehavior(cfg.asMap())
|
|
58
|
+
view.rowSelectionBehaviorType.value = rowSelectionBehaviorType
|
|
59
|
+
|
|
57
60
|
val elementConfig = parseElementConfiguration(cfg.asMap(), view.context)
|
|
58
61
|
view.latestElementConfig = elementConfig
|
|
59
62
|
// if intentConfig is already set, configure immediately:
|
|
@@ -79,7 +82,10 @@ class EmbeddedPaymentElementViewManager :
|
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
@SuppressLint("RestrictedApi")
|
|
82
|
-
@OptIn(
|
|
85
|
+
@OptIn(
|
|
86
|
+
ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class,
|
|
87
|
+
ExperimentalCustomPaymentMethodsApi::class,
|
|
88
|
+
)
|
|
83
89
|
private fun parseElementConfiguration(
|
|
84
90
|
map: ReadableMap,
|
|
85
91
|
context: Context,
|
|
@@ -183,6 +189,16 @@ class EmbeddedPaymentElementViewManager :
|
|
|
183
189
|
),
|
|
184
190
|
).allowsRemovalOfLastSavedPaymentMethod(allowsRemovalOfLastSavedPaymentMethod)
|
|
185
191
|
.cardBrandAcceptance(mapToCardBrandAcceptance(toBundleObject(map)))
|
|
192
|
+
// Serialize original ReadableMap because toBundleObject cannot keep arrays of objects
|
|
193
|
+
.customPaymentMethods(
|
|
194
|
+
parseCustomPaymentMethods(
|
|
195
|
+
toBundleObject(map.getMap("customPaymentMethodConfiguration")).apply {
|
|
196
|
+
map.getMap("customPaymentMethodConfiguration")?.let { readable ->
|
|
197
|
+
putSerializable("customPaymentMethodConfigurationReadableMap", readable.toHashMap())
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
),
|
|
201
|
+
)
|
|
186
202
|
|
|
187
203
|
primaryButtonLabel?.let { configurationBuilder.primaryButtonLabel(it) }
|
|
188
204
|
paymentMethodOrder?.let { configurationBuilder.paymentMethodOrder(it) }
|
|
@@ -190,6 +206,21 @@ class EmbeddedPaymentElementViewManager :
|
|
|
190
206
|
return configurationBuilder.build()
|
|
191
207
|
}
|
|
192
208
|
|
|
209
|
+
private fun parseRowSelectionBehavior(map: ReadableMap): RowSelectionBehaviorType {
|
|
210
|
+
val rowSelectionBehavior =
|
|
211
|
+
map
|
|
212
|
+
.getMap("rowSelectionBehavior")
|
|
213
|
+
?.getString("type")
|
|
214
|
+
?.let { type ->
|
|
215
|
+
when (type) {
|
|
216
|
+
"immediateAction" -> RowSelectionBehaviorType.ImmediateAction
|
|
217
|
+
else -> RowSelectionBehaviorType.Default
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
?: RowSelectionBehaviorType.Default
|
|
221
|
+
return rowSelectionBehavior
|
|
222
|
+
}
|
|
223
|
+
|
|
193
224
|
private fun parseIntentConfiguration(map: ReadableMap): PaymentSheet.IntentConfiguration {
|
|
194
225
|
val intentConfig = PaymentSheetFragment.buildIntentConfiguration(toBundleObject(map))
|
|
195
226
|
return intentConfig ?: throw IllegalArgumentException("IntentConfiguration is null")
|
|
@@ -38,7 +38,6 @@ class PaymentMethodCreateParamsFactory(
|
|
|
38
38
|
PaymentMethod.Type.Card -> createCardPaymentMethodParams()
|
|
39
39
|
PaymentMethod.Type.Ideal -> createIDEALParams()
|
|
40
40
|
PaymentMethod.Type.Alipay -> createAlipayParams()
|
|
41
|
-
PaymentMethod.Type.Sofort -> createSofortParams()
|
|
42
41
|
PaymentMethod.Type.Bancontact -> createBancontactParams()
|
|
43
42
|
PaymentMethod.Type.SepaDebit -> createSepaParams()
|
|
44
43
|
PaymentMethod.Type.Oxxo -> createOXXOParams()
|
|
@@ -79,21 +78,6 @@ class PaymentMethodCreateParamsFactory(
|
|
|
79
78
|
@Throws(PaymentMethodCreateParamsException::class)
|
|
80
79
|
private fun createAlipayParams(): PaymentMethodCreateParams = PaymentMethodCreateParams.createAlipay()
|
|
81
80
|
|
|
82
|
-
@Throws(PaymentMethodCreateParamsException::class)
|
|
83
|
-
private fun createSofortParams(): PaymentMethodCreateParams {
|
|
84
|
-
val country =
|
|
85
|
-
getValOr(paymentMethodData, "country", null)
|
|
86
|
-
?: run {
|
|
87
|
-
throw PaymentMethodCreateParamsException("You must provide bank account country")
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
return PaymentMethodCreateParams.create(
|
|
91
|
-
PaymentMethodCreateParams.Sofort(country = country),
|
|
92
|
-
billingDetailsParams,
|
|
93
|
-
metadata = metadataParams,
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
81
|
@Throws(PaymentMethodCreateParamsException::class)
|
|
98
82
|
private fun createBancontactParams(): PaymentMethodCreateParams {
|
|
99
83
|
billingDetailsParams?.let {
|
|
@@ -271,7 +255,6 @@ class PaymentMethodCreateParamsFactory(
|
|
|
271
255
|
PaymentMethod.Type.Affirm -> createAffirmStripeIntentParams(clientSecret, isPaymentIntent)
|
|
272
256
|
PaymentMethod.Type.Ideal,
|
|
273
257
|
PaymentMethod.Type.Alipay,
|
|
274
|
-
PaymentMethod.Type.Sofort,
|
|
275
258
|
PaymentMethod.Type.Bancontact,
|
|
276
259
|
PaymentMethod.Type.SepaDebit,
|
|
277
260
|
PaymentMethod.Type.Oxxo,
|
|
@@ -2,13 +2,11 @@ import com.facebook.react.bridge.Arguments
|
|
|
2
2
|
import com.facebook.react.bridge.WritableMap
|
|
3
3
|
import com.reactnativestripesdk.utils.mapFromPaymentSheetBillingDetails
|
|
4
4
|
import com.stripe.android.paymentelement.EmbeddedPaymentElement
|
|
5
|
-
import com.stripe.android.paymentelement.ExperimentalEmbeddedPaymentElementApi
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Serialize Stripe's PaymentOptionDisplayData into a WritableMap
|
|
9
8
|
* that can be sent over the RN bridge.
|
|
10
9
|
*/
|
|
11
|
-
@OptIn(ExperimentalEmbeddedPaymentElementApi::class)
|
|
12
10
|
fun EmbeddedPaymentElement.PaymentOptionDisplayData.toWritableMap(): WritableMap =
|
|
13
11
|
Arguments.createMap().apply {
|
|
14
12
|
putString("label", label)
|
|
@@ -6,7 +6,7 @@ import android.content.res.Configuration
|
|
|
6
6
|
import android.graphics.Color
|
|
7
7
|
import android.os.Bundle
|
|
8
8
|
import com.reactnativestripesdk.utils.PaymentSheetAppearanceException
|
|
9
|
-
import com.stripe.android.paymentelement.
|
|
9
|
+
import com.stripe.android.paymentelement.AppearanceAPIAdditionsPreview
|
|
10
10
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
11
11
|
import com.stripe.android.uicore.StripeThemeDefaults
|
|
12
12
|
|
|
@@ -57,6 +57,7 @@ fun buildPaymentSheetAppearance(
|
|
|
57
57
|
)
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
@OptIn(AppearanceAPIAdditionsPreview::class)
|
|
60
61
|
private fun buildTypography(
|
|
61
62
|
fontParams: Bundle?,
|
|
62
63
|
context: Context,
|
|
@@ -244,7 +245,6 @@ private fun buildPrimaryButtonColors(
|
|
|
244
245
|
),
|
|
245
246
|
)
|
|
246
247
|
|
|
247
|
-
@OptIn(ExperimentalEmbeddedPaymentElementApi::class)
|
|
248
248
|
@SuppressLint("RestrictedApi")
|
|
249
249
|
@Throws(PaymentSheetAppearanceException::class)
|
|
250
250
|
private fun buildEmbeddedAppearance(
|
|
@@ -341,7 +341,7 @@ private fun buildEmbeddedAppearance(
|
|
|
341
341
|
val checkmarkParams = getBundleOrNull(flatParams, PaymentSheetAppearanceKeys.CHECKMARK)
|
|
342
342
|
val separatorInsetsParams = getBundleOrNull(flatParams, PaymentSheetAppearanceKeys.SEPARATOR_INSETS)
|
|
343
343
|
|
|
344
|
-
// Default separator insets specific to FlatWithCheckmark
|
|
344
|
+
// Default separator insets specific to FlatWithCheckmark and FlatWithChevron
|
|
345
345
|
val defaultSeparatorStartInsetDp = 0.0f
|
|
346
346
|
val defaultSeparatorEndInsetDp = 0.0f
|
|
347
347
|
|
|
@@ -392,6 +392,59 @@ private fun buildEmbeddedAppearance(
|
|
|
392
392
|
colorsDark = flatCheckmarkColors,
|
|
393
393
|
)
|
|
394
394
|
}
|
|
395
|
+
"flatWithChevron" -> {
|
|
396
|
+
val flatParams = getBundleOrNull(rowParams, PaymentSheetAppearanceKeys.FLAT)
|
|
397
|
+
val chevronParams = getBundleOrNull(flatParams, PaymentSheetAppearanceKeys.CHEVRON)
|
|
398
|
+
val separatorInsetsParams = getBundleOrNull(flatParams, PaymentSheetAppearanceKeys.SEPARATOR_INSETS)
|
|
399
|
+
|
|
400
|
+
// Default separator insets specific to FlatWithCheckmark and FlatWithChevron
|
|
401
|
+
val defaultSeparatorStartInsetDp = 0.0f
|
|
402
|
+
val defaultSeparatorEndInsetDp = 0.0f
|
|
403
|
+
|
|
404
|
+
// Parse dimensions as Floats
|
|
405
|
+
val separatorThickness = getFloatOr(flatParams, PaymentSheetAppearanceKeys.SEPARATOR_THICKNESS, defaultSeparatorThicknessDp)
|
|
406
|
+
val startSeparatorInset = getFloatOr(separatorInsetsParams, PaymentSheetAppearanceKeys.LEFT, defaultSeparatorStartInsetDp)
|
|
407
|
+
val endSeparatorInset = getFloatOr(separatorInsetsParams, PaymentSheetAppearanceKeys.RIGHT, defaultSeparatorEndInsetDp)
|
|
408
|
+
|
|
409
|
+
// Parse booleans
|
|
410
|
+
val topEnabled = getBooleanOr(flatParams, PaymentSheetAppearanceKeys.TOP_SEPARATOR_ENABLED, true)
|
|
411
|
+
val bottomEnabled = getBooleanOr(flatParams, PaymentSheetAppearanceKeys.BOTTOM_SEPARATOR_ENABLED, true)
|
|
412
|
+
|
|
413
|
+
val parsedSeparatorColor =
|
|
414
|
+
dynamicColorFromParams(
|
|
415
|
+
context,
|
|
416
|
+
flatParams,
|
|
417
|
+
PaymentSheetAppearanceKeys.SEPARATOR_COLOR,
|
|
418
|
+
Color.GRAY,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
val parsedChevronColor =
|
|
422
|
+
dynamicColorFromParams(
|
|
423
|
+
context,
|
|
424
|
+
chevronParams,
|
|
425
|
+
PaymentSheetAppearanceKeys.COLOR,
|
|
426
|
+
defaultColors.componentBorder, // Default to component border color like other elements
|
|
427
|
+
)
|
|
428
|
+
|
|
429
|
+
// Create the required Colors object
|
|
430
|
+
val flatChevronColors =
|
|
431
|
+
PaymentSheet.Appearance.Embedded.RowStyle.FlatWithChevron.Colors(
|
|
432
|
+
separatorColor = parsedSeparatorColor,
|
|
433
|
+
chevronColor = parsedChevronColor,
|
|
434
|
+
)
|
|
435
|
+
|
|
436
|
+
PaymentSheet.Appearance.Embedded.RowStyle.FlatWithChevron(
|
|
437
|
+
separatorThicknessDp = separatorThickness,
|
|
438
|
+
startSeparatorInsetDp = startSeparatorInset,
|
|
439
|
+
endSeparatorInsetDp = endSeparatorInset,
|
|
440
|
+
topSeparatorEnabled = topEnabled,
|
|
441
|
+
bottomSeparatorEnabled = bottomEnabled,
|
|
442
|
+
additionalVerticalInsetsDp = additionalInsets,
|
|
443
|
+
horizontalInsetsDp = 0.0F, // We do not have an iOS equal for this API so it's not configurable in React Native
|
|
444
|
+
colorsLight = flatChevronColors,
|
|
445
|
+
colorsDark = flatChevronColors,
|
|
446
|
+
)
|
|
447
|
+
}
|
|
395
448
|
"floatingButton" -> {
|
|
396
449
|
val floatingParams = getBundleOrNull(rowParams, PaymentSheetAppearanceKeys.FLOATING)
|
|
397
450
|
PaymentSheet.Appearance.Embedded.RowStyle.FloatingButton(
|
|
@@ -606,6 +659,7 @@ private class PaymentSheetAppearanceKeys {
|
|
|
606
659
|
const val SELECTED_COLOR = "selectedColor"
|
|
607
660
|
const val UNSELECTED_COLOR = "unselectedColor"
|
|
608
661
|
const val CHECKMARK = "checkmark"
|
|
662
|
+
const val CHEVRON = "chevron"
|
|
609
663
|
const val COLOR = "color"
|
|
610
664
|
const val CHECKMARK_INSET = "inset"
|
|
611
665
|
|