@stripe/stripe-react-native 0.57.2 → 0.58.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/android/build.gradle +1 -0
- package/android/gradle.properties +1 -1
- package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementView.kt +0 -3
- package/android/src/main/java/com/reactnativestripesdk/EmbeddedPaymentElementViewManager.kt +5 -3
- package/android/src/main/java/com/reactnativestripesdk/NavigationBarView.kt +12 -1
- package/android/src/main/java/com/reactnativestripesdk/PaymentElementConfig.kt +18 -0
- package/android/src/main/java/com/reactnativestripesdk/PaymentSheetManager.kt +136 -35
- package/android/src/main/java/com/reactnativestripesdk/StripeAbstractComposeView.kt +17 -5
- package/android/src/main/java/com/reactnativestripesdk/StripeSdkModule.kt +9 -2
- package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt +38 -13
- package/android/src/main/java/com/reactnativestripesdk/utils/Mappers.kt +0 -2
- package/android/src/test/java/com/reactnativestripesdk/DrawableConversionPropertyTest.kt +224 -0
- package/android/src/test/java/com/reactnativestripesdk/DrawableConversionTest.kt +146 -0
- package/android/src/test/java/com/reactnativestripesdk/DrawableLoadingTest.kt +150 -0
- package/android/src/test/java/com/reactnativestripesdk/PaymentElementConfigTest.kt +138 -1
- package/android/src/test/java/com/reactnativestripesdk/PaymentOptionImageConsistencyTest.kt +186 -0
- package/ios/ConnectAccountOnboarding/ConnectAccountOnboardingView.swift +13 -19
- package/ios/StripeSdkImpl+Embedded.swift +4 -1
- package/ios/StripeSdkImpl+PaymentSheet.swift +28 -1
- package/ios/StripeSdkImpl.swift +26 -2
- package/jest/mock.js +6 -0
- package/jest/setup.js +30 -0
- 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/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/connect/Components.js +1 -1
- package/lib/commonjs/connect/Components.js.map +1 -1
- package/lib/commonjs/connect/ConnectComponentsProvider.js +1 -1
- package/lib/commonjs/connect/ConnectComponentsProvider.js.map +1 -1
- package/lib/commonjs/connect/EmbeddedComponent.js +9 -4
- package/lib/commonjs/connect/EmbeddedComponent.js.map +1 -1
- package/lib/commonjs/connect/ModalCloseButton.js +1 -1
- package/lib/commonjs/connect/ModalCloseButton.js.map +1 -1
- package/lib/commonjs/connect/NavigationBar.js +1 -1
- package/lib/commonjs/connect/NavigationBar.js.map +1 -1
- package/lib/commonjs/helpers.js +1 -1
- package/lib/commonjs/hooks/useOnramp.js +1 -1
- package/lib/commonjs/hooks/useOnramp.js.map +1 -1
- package/lib/commonjs/specs/NativeAddToWalletButton.js +1 -1
- package/lib/commonjs/specs/NativeAddressSheet.js +1 -1
- package/lib/commonjs/specs/NativeApplePayButton.js +1 -1
- package/lib/commonjs/specs/NativeAuBECSDebitForm.js +1 -1
- package/lib/commonjs/specs/NativeCardField.js +1 -1
- package/lib/commonjs/specs/NativeCardField.js.map +1 -1
- package/lib/commonjs/specs/NativeCardForm.js +1 -1
- package/lib/commonjs/specs/NativeCardForm.js.map +1 -1
- package/lib/commonjs/specs/NativeConnectAccountOnboardingView.js +1 -1
- package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js +1 -1
- package/lib/commonjs/specs/NativeEmbeddedPaymentElement.js.map +1 -1
- package/lib/commonjs/specs/NativeGooglePayButton.js +1 -1
- package/lib/commonjs/specs/NativeNavigationBar.js +1 -1
- package/lib/commonjs/specs/NativeStripeContainer.js +1 -1
- package/lib/commonjs/types/EmbeddedPaymentElement.js +1 -1
- package/lib/commonjs/types/EmbeddedPaymentElement.js.map +1 -1
- package/lib/commonjs/types/FinancialConnections.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/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/connect/Components.js +1 -1
- package/lib/module/connect/Components.js.map +1 -1
- package/lib/module/connect/ConnectComponentsProvider.js +1 -1
- package/lib/module/connect/ConnectComponentsProvider.js.map +1 -1
- package/lib/module/connect/EmbeddedComponent.js +9 -4
- package/lib/module/connect/EmbeddedComponent.js.map +1 -1
- package/lib/module/connect/ModalCloseButton.js +1 -1
- package/lib/module/connect/ModalCloseButton.js.map +1 -1
- package/lib/module/connect/NavigationBar.js +1 -1
- package/lib/module/connect/NavigationBar.js.map +1 -1
- package/lib/module/helpers.js +1 -1
- package/lib/module/hooks/useOnramp.js +1 -1
- package/lib/module/hooks/useOnramp.js.map +1 -1
- package/lib/module/specs/NativeAddToWalletButton.js +1 -1
- package/lib/module/specs/NativeAddressSheet.js +1 -1
- package/lib/module/specs/NativeApplePayButton.js +1 -1
- package/lib/module/specs/NativeAuBECSDebitForm.js +1 -1
- package/lib/module/specs/NativeCardField.js +1 -1
- package/lib/module/specs/NativeCardField.js.map +1 -1
- package/lib/module/specs/NativeCardForm.js +1 -1
- package/lib/module/specs/NativeCardForm.js.map +1 -1
- package/lib/module/specs/NativeConnectAccountOnboardingView.js +1 -1
- package/lib/module/specs/NativeEmbeddedPaymentElement.js +1 -1
- package/lib/module/specs/NativeEmbeddedPaymentElement.js.map +1 -1
- package/lib/module/specs/NativeGooglePayButton.js +1 -1
- package/lib/module/specs/NativeNavigationBar.js +1 -1
- package/lib/module/specs/NativeStripeContainer.js +1 -1
- package/lib/module/types/EmbeddedPaymentElement.js +1 -1
- package/lib/module/types/EmbeddedPaymentElement.js.map +1 -1
- package/lib/module/types/FinancialConnections.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/connect/Components.d.ts.map +1 -1
- package/lib/typescript/src/connect/EmbeddedComponent.d.ts.map +1 -1
- package/lib/typescript/src/connect/connectTypes.d.ts +5 -1
- package/lib/typescript/src/connect/connectTypes.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useOnramp.d.ts +2 -1
- package/lib/typescript/src/hooks/useOnramp.d.ts.map +1 -1
- package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts +6 -1
- package/lib/typescript/src/types/EmbeddedPaymentElement.d.ts.map +1 -1
- package/lib/typescript/src/types/FinancialConnections.d.ts +2 -0
- package/lib/typescript/src/types/FinancialConnections.d.ts.map +1 -1
- package/lib/typescript/src/types/PaymentSheet.d.ts +30 -0
- package/lib/typescript/src/types/PaymentSheet.d.ts.map +1 -1
- package/package.json +15 -5
- package/src/connect/Components.tsx +18 -11
- package/src/connect/EmbeddedComponent.tsx +223 -12
- package/src/connect/connectTypes.ts +5 -1
- package/src/hooks/useOnramp.tsx +5 -1
- package/src/types/EmbeddedPaymentElement.tsx +6 -1
- package/src/types/FinancialConnections.ts +2 -0
- package/src/types/PaymentSheet.ts +32 -0
- package/stripe-react-native.podspec +1 -1
- package/android/.idea/AndroidProjectSystem.xml +0 -6
- package/android/.idea/caches/deviceStreaming.xml +0 -1029
- 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/ios/StripeSdk.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/ios/StripeSdk.xcodeproj/project.xcworkspace/xcuserdata/tianzhao.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/ios/StripeSdk.xcodeproj/xcuserdata/tianzhao.xcuserdatad/xcschemes/xcschememanagement.plist +0 -19
package/android/build.gradle
CHANGED
|
@@ -183,6 +183,7 @@ dependencies {
|
|
|
183
183
|
testImplementation "org.mockito:mockito-core:3.+"
|
|
184
184
|
testImplementation "org.robolectric:robolectric:4.10"
|
|
185
185
|
testImplementation "androidx.test:core:1.4.0"
|
|
186
|
+
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.6.0"
|
|
186
187
|
|
|
187
188
|
implementation "androidx.compose.ui:ui:1.7.8"
|
|
188
189
|
implementation "androidx.compose.foundation:foundation-layout:1.7.8"
|
|
@@ -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=22.
|
|
6
|
+
StripeSdk_stripeVersion=22.7.+
|
|
@@ -29,7 +29,6 @@ import com.stripe.android.model.PaymentMethod
|
|
|
29
29
|
import com.stripe.android.paymentelement.CustomPaymentMethodResult
|
|
30
30
|
import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
|
|
31
31
|
import com.stripe.android.paymentelement.EmbeddedPaymentElement
|
|
32
|
-
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
|
|
33
32
|
import com.stripe.android.paymentelement.rememberEmbeddedPaymentElement
|
|
34
33
|
import com.stripe.android.paymentsheet.CreateIntentResult
|
|
35
34
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
@@ -44,7 +43,6 @@ enum class RowSelectionBehaviorType {
|
|
|
44
43
|
ImmediateAction,
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
48
46
|
class EmbeddedPaymentElementView(
|
|
49
47
|
context: Context,
|
|
50
48
|
) : StripeAbstractComposeView(context) {
|
|
@@ -77,7 +75,6 @@ class EmbeddedPaymentElementView(
|
|
|
77
75
|
}
|
|
78
76
|
|
|
79
77
|
@SuppressLint("RestrictedApi")
|
|
80
|
-
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
81
78
|
@Composable
|
|
82
79
|
override fun Content() {
|
|
83
80
|
val type by remember { rowSelectionBehaviorType }
|
|
@@ -24,7 +24,7 @@ import com.reactnativestripesdk.utils.mapToPreferredNetworks
|
|
|
24
24
|
import com.reactnativestripesdk.utils.parseCustomPaymentMethods
|
|
25
25
|
import com.stripe.android.ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi
|
|
26
26
|
import com.stripe.android.paymentelement.EmbeddedPaymentElement
|
|
27
|
-
import com.stripe.android.
|
|
27
|
+
import com.stripe.android.paymentsheet.CardFundingFilteringPrivatePreview
|
|
28
28
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
29
29
|
import org.json.JSONArray
|
|
30
30
|
import org.json.JSONObject
|
|
@@ -98,7 +98,7 @@ class EmbeddedPaymentElementViewManager :
|
|
|
98
98
|
@SuppressLint("RestrictedApi")
|
|
99
99
|
@OptIn(
|
|
100
100
|
ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class,
|
|
101
|
-
|
|
101
|
+
CardFundingFilteringPrivatePreview::class,
|
|
102
102
|
)
|
|
103
103
|
private fun parseElementConfiguration(
|
|
104
104
|
map: ReadableMap,
|
|
@@ -157,7 +157,9 @@ class EmbeddedPaymentElementViewManager :
|
|
|
157
157
|
),
|
|
158
158
|
).allowsRemovalOfLastSavedPaymentMethod(allowsRemovalOfLastSavedPaymentMethod)
|
|
159
159
|
.cardBrandAcceptance(mapToCardBrandAcceptance(map))
|
|
160
|
-
.
|
|
160
|
+
.apply {
|
|
161
|
+
mapToAllowedCardFundingTypes(map)?.let { allowedCardFundingTypes(it) }
|
|
162
|
+
}.embeddedViewDisplaysMandateText(
|
|
161
163
|
map.getBooleanOr("embeddedViewDisplaysMandateText", true),
|
|
162
164
|
).customPaymentMethods(
|
|
163
165
|
parseCustomPaymentMethods(
|
|
@@ -2,7 +2,11 @@ package com.reactnativestripesdk
|
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
4
|
import android.graphics.Color
|
|
5
|
+
import android.graphics.PorterDuff
|
|
6
|
+
import android.graphics.PorterDuffColorFilter
|
|
7
|
+
import android.os.Build
|
|
5
8
|
import android.view.Gravity
|
|
9
|
+
import android.view.View.MeasureSpec
|
|
6
10
|
import android.widget.FrameLayout
|
|
7
11
|
import android.widget.ImageButton
|
|
8
12
|
import android.widget.TextView
|
|
@@ -18,6 +22,7 @@ class NavigationBarView(
|
|
|
18
22
|
) : FrameLayout(context) {
|
|
19
23
|
private val toolbar: Toolbar
|
|
20
24
|
private val titleTextView: TextView
|
|
25
|
+
private val closeButton: ImageButton
|
|
21
26
|
private var titleText: String? = null
|
|
22
27
|
|
|
23
28
|
init {
|
|
@@ -53,7 +58,7 @@ class NavigationBarView(
|
|
|
53
58
|
toolbar.addView(titleTextView, titleParams)
|
|
54
59
|
|
|
55
60
|
// Create close button
|
|
56
|
-
|
|
61
|
+
closeButton =
|
|
57
62
|
ImageButton(context).apply {
|
|
58
63
|
setImageDrawable(
|
|
59
64
|
context.resources.getDrawable(
|
|
@@ -61,6 +66,12 @@ class NavigationBarView(
|
|
|
61
66
|
null,
|
|
62
67
|
),
|
|
63
68
|
)
|
|
69
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
70
|
+
drawable?.setColorFilter(android.graphics.BlendModeColorFilter(Color.BLACK, android.graphics.BlendMode.SRC_IN))
|
|
71
|
+
} else {
|
|
72
|
+
@Suppress("DEPRECATION")
|
|
73
|
+
drawable?.setColorFilter(PorterDuffColorFilter(Color.BLACK, PorterDuff.Mode.SRC_IN))
|
|
74
|
+
}
|
|
64
75
|
setBackgroundColor(Color.TRANSPARENT)
|
|
65
76
|
setOnClickListener {
|
|
66
77
|
dispatchCloseButtonPress()
|
|
@@ -8,6 +8,7 @@ import com.reactnativestripesdk.utils.getLongOr
|
|
|
8
8
|
import com.reactnativestripesdk.utils.getStringList
|
|
9
9
|
import com.reactnativestripesdk.utils.isEmpty
|
|
10
10
|
import com.stripe.android.paymentelement.PaymentMethodOptionsSetupFutureUsagePreview
|
|
11
|
+
import com.stripe.android.paymentsheet.CardFundingFilteringPrivatePreview
|
|
11
12
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
12
13
|
|
|
13
14
|
@Throws(PaymentSheetException::class)
|
|
@@ -226,3 +227,20 @@ internal fun mapToCardBrandCategory(brand: String): PaymentSheet.CardBrandAccept
|
|
|
226
227
|
"discover" -> PaymentSheet.CardBrandAcceptance.BrandCategory.Discover
|
|
227
228
|
else -> null
|
|
228
229
|
}
|
|
230
|
+
|
|
231
|
+
@OptIn(CardFundingFilteringPrivatePreview::class)
|
|
232
|
+
internal fun mapToAllowedCardFundingTypes(params: ReadableMap?): List<PaymentSheet.CardFundingType>? {
|
|
233
|
+
val cardFundingFiltering = params?.getMap("cardFundingFiltering") ?: return null
|
|
234
|
+
val allowedTypes = cardFundingFiltering.getStringList("allowedCardFundingTypes") ?: return null
|
|
235
|
+
|
|
236
|
+
return allowedTypes
|
|
237
|
+
.mapNotNull { type ->
|
|
238
|
+
when (type) {
|
|
239
|
+
"debit" -> PaymentSheet.CardFundingType.Debit
|
|
240
|
+
"credit" -> PaymentSheet.CardFundingType.Credit
|
|
241
|
+
"prepaid" -> PaymentSheet.CardFundingType.Prepaid
|
|
242
|
+
"unknown" -> PaymentSheet.CardFundingType.Unknown
|
|
243
|
+
else -> null
|
|
244
|
+
}
|
|
245
|
+
}.ifEmpty { null }
|
|
246
|
+
}
|
|
@@ -45,8 +45,8 @@ import com.stripe.android.paymentelement.ConfirmCustomPaymentMethodCallback
|
|
|
45
45
|
import com.stripe.android.paymentelement.CreateIntentWithConfirmationTokenCallback
|
|
46
46
|
import com.stripe.android.paymentelement.CustomPaymentMethodResult
|
|
47
47
|
import com.stripe.android.paymentelement.CustomPaymentMethodResultHandler
|
|
48
|
-
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
|
|
49
48
|
import com.stripe.android.paymentelement.PaymentMethodOptionsSetupFutureUsagePreview
|
|
49
|
+
import com.stripe.android.paymentsheet.CardFundingFilteringPrivatePreview
|
|
50
50
|
import com.stripe.android.paymentsheet.CreateIntentCallback
|
|
51
51
|
import com.stripe.android.paymentsheet.CreateIntentResult
|
|
52
52
|
import com.stripe.android.paymentsheet.PaymentOptionResultCallback
|
|
@@ -58,13 +58,16 @@ import kotlinx.coroutines.CoroutineScope
|
|
|
58
58
|
import kotlinx.coroutines.Dispatchers
|
|
59
59
|
import kotlinx.coroutines.delay
|
|
60
60
|
import kotlinx.coroutines.launch
|
|
61
|
+
import kotlinx.coroutines.suspendCancellableCoroutine
|
|
62
|
+
import kotlinx.coroutines.withTimeoutOrNull
|
|
61
63
|
import java.io.ByteArrayOutputStream
|
|
62
64
|
import kotlin.Exception
|
|
65
|
+
import kotlin.coroutines.resume
|
|
63
66
|
|
|
64
67
|
@OptIn(
|
|
65
68
|
ReactNativeSdkInternal::class,
|
|
66
69
|
ExperimentalAllowsRemovalOfLastSavedPaymentMethodApi::class,
|
|
67
|
-
|
|
70
|
+
CardFundingFilteringPrivatePreview::class,
|
|
68
71
|
)
|
|
69
72
|
class PaymentSheetManager(
|
|
70
73
|
context: ReactApplicationContext,
|
|
@@ -85,7 +88,6 @@ class PaymentSheetManager(
|
|
|
85
88
|
private var keepJsAwake: KeepJsAwakeTask? = null
|
|
86
89
|
|
|
87
90
|
@SuppressLint("RestrictedApi")
|
|
88
|
-
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
89
91
|
override fun onCreate() {
|
|
90
92
|
val activity = getCurrentActivityOrResolveWithError(initPromise) ?: return
|
|
91
93
|
val merchantDisplayName = arguments.getString("merchantDisplayName").orEmpty()
|
|
@@ -140,28 +142,42 @@ class PaymentSheetManager(
|
|
|
140
142
|
|
|
141
143
|
val paymentOptionCallback =
|
|
142
144
|
PaymentOptionResultCallback { paymentOptionResult ->
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
val imageString =
|
|
145
|
+
paymentOptionResult.paymentOption?.let { paymentOption ->
|
|
146
|
+
// Convert drawable to bitmap asynchronously to avoid shared state issues
|
|
147
|
+
CoroutineScope(Dispatchers.Default).launch {
|
|
148
|
+
val imageString =
|
|
149
|
+
try {
|
|
150
|
+
convertDrawableToBase64(paymentOption.icon())
|
|
151
|
+
} catch (e: Exception) {
|
|
152
|
+
val result =
|
|
153
|
+
createError(
|
|
154
|
+
PaymentSheetErrorType.Failed.toString(),
|
|
155
|
+
"Failed to process payment option image: ${e.message}",
|
|
156
|
+
)
|
|
157
|
+
resolvePresentPromise(result)
|
|
158
|
+
return@launch
|
|
159
|
+
}
|
|
160
|
+
|
|
147
161
|
val option: WritableMap = Arguments.createMap()
|
|
148
|
-
option.putString("label",
|
|
162
|
+
option.putString("label", paymentOption.label)
|
|
149
163
|
option.putString("image", imageString)
|
|
150
164
|
val additionalFields: Map<String, Any> = mapOf("didCancel" to paymentOptionResult.didCancel)
|
|
151
|
-
createResult("paymentOption", option, additionalFields)
|
|
165
|
+
val result = createResult("paymentOption", option, additionalFields)
|
|
166
|
+
resolvePresentPromise(result)
|
|
152
167
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
168
|
+
} ?: run {
|
|
169
|
+
val result =
|
|
170
|
+
if (paymentSheetTimedOut) {
|
|
171
|
+
paymentSheetTimedOut = false
|
|
172
|
+
createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out")
|
|
173
|
+
} else {
|
|
174
|
+
createError(
|
|
175
|
+
PaymentSheetErrorType.Canceled.toString(),
|
|
176
|
+
"The payment option selection flow has been canceled",
|
|
177
|
+
)
|
|
163
178
|
}
|
|
164
|
-
|
|
179
|
+
resolvePresentPromise(result)
|
|
180
|
+
}
|
|
165
181
|
}
|
|
166
182
|
|
|
167
183
|
val paymentResultCallback =
|
|
@@ -268,7 +284,9 @@ class PaymentSheetManager(
|
|
|
268
284
|
mapToPreferredNetworks(arguments.getIntegerList("preferredNetworks")),
|
|
269
285
|
).allowsRemovalOfLastSavedPaymentMethod(allowsRemovalOfLastSavedPaymentMethod)
|
|
270
286
|
.cardBrandAcceptance(mapToCardBrandAcceptance(arguments))
|
|
271
|
-
.
|
|
287
|
+
.apply {
|
|
288
|
+
mapToAllowedCardFundingTypes(arguments)?.let { allowedCardFundingTypes(it) }
|
|
289
|
+
}.customPaymentMethods(parseCustomPaymentMethods(arguments.getMap("customPaymentMethodConfiguration")))
|
|
272
290
|
|
|
273
291
|
primaryButtonLabel?.let { configurationBuilder.primaryButtonLabel(it) }
|
|
274
292
|
paymentMethodOrder?.let { configurationBuilder.paymentMethodOrder(it) }
|
|
@@ -413,16 +431,31 @@ class PaymentSheetManager(
|
|
|
413
431
|
private fun configureFlowController() {
|
|
414
432
|
val onFlowControllerConfigure =
|
|
415
433
|
PaymentSheet.FlowController.ConfigCallback { _, _ ->
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
val imageString =
|
|
434
|
+
flowController?.getPaymentOption()?.let { paymentOption ->
|
|
435
|
+
// Launch async job to convert drawable, but resolve promise synchronously
|
|
436
|
+
CoroutineScope(Dispatchers.Default).launch {
|
|
437
|
+
val imageString =
|
|
438
|
+
try {
|
|
439
|
+
convertDrawableToBase64(paymentOption.icon())
|
|
440
|
+
} catch (e: Exception) {
|
|
441
|
+
val result =
|
|
442
|
+
createError(
|
|
443
|
+
PaymentSheetErrorType.Failed.toString(),
|
|
444
|
+
"Failed to process payment option image: ${e.message}",
|
|
445
|
+
)
|
|
446
|
+
initPromise.resolve(result)
|
|
447
|
+
return@launch
|
|
448
|
+
}
|
|
449
|
+
|
|
420
450
|
val option: WritableMap = Arguments.createMap()
|
|
421
|
-
option.putString("label",
|
|
451
|
+
option.putString("label", paymentOption.label)
|
|
422
452
|
option.putString("image", imageString)
|
|
423
|
-
createResult("paymentOption", option)
|
|
424
|
-
|
|
425
|
-
|
|
453
|
+
val result = createResult("paymentOption", option)
|
|
454
|
+
initPromise.resolve(result)
|
|
455
|
+
}
|
|
456
|
+
} ?: run {
|
|
457
|
+
initPromise.resolve(Arguments.createMap())
|
|
458
|
+
}
|
|
426
459
|
}
|
|
427
460
|
|
|
428
461
|
if (!paymentIntentClientSecret.isNullOrEmpty()) {
|
|
@@ -466,7 +499,6 @@ class PaymentSheetManager(
|
|
|
466
499
|
} ?: run { resolvePresentPromise(map) }
|
|
467
500
|
}
|
|
468
501
|
|
|
469
|
-
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
470
502
|
override fun onConfirmCustomPaymentMethod(
|
|
471
503
|
customPaymentMethod: PaymentSheet.CustomPaymentMethod,
|
|
472
504
|
billingDetails: PaymentMethod.BillingDetails,
|
|
@@ -550,17 +582,86 @@ class PaymentSheetManager(
|
|
|
550
582
|
}
|
|
551
583
|
}
|
|
552
584
|
|
|
585
|
+
suspend fun waitForDrawableToLoad(
|
|
586
|
+
drawable: Drawable,
|
|
587
|
+
timeoutMs: Long = 3000,
|
|
588
|
+
): Drawable {
|
|
589
|
+
// If already loaded, return immediately
|
|
590
|
+
if (drawable.intrinsicWidth > 1 && drawable.intrinsicHeight > 1) {
|
|
591
|
+
return drawable
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// Use callback to be notified when drawable finishes loading
|
|
595
|
+
return withTimeoutOrNull(timeoutMs) {
|
|
596
|
+
suspendCancellableCoroutine { continuation ->
|
|
597
|
+
val callback =
|
|
598
|
+
object : Drawable.Callback {
|
|
599
|
+
override fun invalidateDrawable(who: Drawable) {
|
|
600
|
+
// Drawable has changed/loaded - check if it's ready now
|
|
601
|
+
if (who.intrinsicWidth > 1 && who.intrinsicHeight > 1) {
|
|
602
|
+
who.callback = null // Remove callback
|
|
603
|
+
if (continuation.isActive) {
|
|
604
|
+
continuation.resume(who)
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
override fun scheduleDrawable(
|
|
610
|
+
who: Drawable,
|
|
611
|
+
what: Runnable,
|
|
612
|
+
`when`: Long,
|
|
613
|
+
) {}
|
|
614
|
+
|
|
615
|
+
override fun unscheduleDrawable(
|
|
616
|
+
who: Drawable,
|
|
617
|
+
what: Runnable,
|
|
618
|
+
) {}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
drawable.callback = callback
|
|
622
|
+
|
|
623
|
+
// Trigger an invalidation to check if it loads immediately
|
|
624
|
+
drawable.invalidateSelf()
|
|
625
|
+
|
|
626
|
+
continuation.invokeOnCancellation { drawable.callback = null }
|
|
627
|
+
}
|
|
628
|
+
} ?: drawable // Return drawable even if timeout (best effort)
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
suspend fun convertDrawableToBase64(drawable: Drawable): String? {
|
|
632
|
+
val loadedDrawable = waitForDrawableToLoad(drawable)
|
|
633
|
+
val bitmap = getBitmapFromDrawable(loadedDrawable)
|
|
634
|
+
return getBase64FromBitmap(bitmap)
|
|
635
|
+
}
|
|
636
|
+
|
|
553
637
|
fun getBitmapFromDrawable(drawable: Drawable): Bitmap? {
|
|
554
638
|
val drawableCompat = DrawableCompat.wrap(drawable).mutate()
|
|
555
|
-
|
|
639
|
+
|
|
640
|
+
// Determine the size to use - prefer intrinsic size, fall back to bounds
|
|
641
|
+
val width =
|
|
642
|
+
if (drawableCompat.intrinsicWidth > 0) {
|
|
643
|
+
drawableCompat.intrinsicWidth
|
|
644
|
+
} else {
|
|
645
|
+
drawableCompat.bounds.width()
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
val height =
|
|
649
|
+
if (drawableCompat.intrinsicHeight > 0) {
|
|
650
|
+
drawableCompat.intrinsicHeight
|
|
651
|
+
} else {
|
|
652
|
+
drawableCompat.bounds.height()
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (width <= 0 || height <= 0) {
|
|
556
656
|
return null
|
|
557
657
|
}
|
|
558
|
-
|
|
559
|
-
|
|
658
|
+
|
|
659
|
+
val bitmap = createBitmap(width, height, Bitmap.Config.ARGB_8888)
|
|
560
660
|
bitmap.eraseColor(Color.TRANSPARENT)
|
|
561
661
|
val canvas = Canvas(bitmap)
|
|
562
|
-
|
|
563
|
-
|
|
662
|
+
drawableCompat.setBounds(0, 0, canvas.width, canvas.height)
|
|
663
|
+
drawableCompat.draw(canvas)
|
|
664
|
+
|
|
564
665
|
return bitmap
|
|
565
666
|
}
|
|
566
667
|
|
|
@@ -69,6 +69,8 @@ abstract class StripeAbstractComposeView(
|
|
|
69
69
|
|
|
70
70
|
private var innerComposeView: InnerComposeView? = null
|
|
71
71
|
private var isLifecycleSetup = false
|
|
72
|
+
private var activityLifecycleOwner: LifecycleOwner? = null
|
|
73
|
+
private var activityLifecycleObserver: LifecycleEventObserver? = null
|
|
72
74
|
|
|
73
75
|
// Create a lifecycle this is tied to the activity, but that we can manually
|
|
74
76
|
// update to DESTROYED state when the view is dropped.
|
|
@@ -113,24 +115,34 @@ abstract class StripeAbstractComposeView(
|
|
|
113
115
|
return
|
|
114
116
|
}
|
|
115
117
|
|
|
116
|
-
((context as? ReactContext)?.currentActivity as? LifecycleOwner?)?.let {
|
|
118
|
+
((context as? ReactContext)?.currentActivity as? LifecycleOwner?)?.let { owner ->
|
|
117
119
|
isLifecycleSetup = true
|
|
120
|
+
activityLifecycleOwner = owner
|
|
118
121
|
|
|
119
122
|
// Setup the lifecycle to match the activity.
|
|
120
|
-
|
|
123
|
+
val observer =
|
|
121
124
|
object : LifecycleEventObserver {
|
|
122
125
|
override fun onStateChanged(
|
|
123
126
|
source: LifecycleOwner,
|
|
124
127
|
event: Lifecycle.Event,
|
|
125
128
|
) {
|
|
126
|
-
lifecycleRegistry.
|
|
129
|
+
if (lifecycleRegistry.currentState != Lifecycle.State.DESTROYED) {
|
|
130
|
+
lifecycleRegistry.handleLifecycleEvent(event)
|
|
131
|
+
}
|
|
127
132
|
}
|
|
128
|
-
}
|
|
129
|
-
|
|
133
|
+
}
|
|
134
|
+
activityLifecycleObserver = observer
|
|
135
|
+
owner.lifecycle.addObserver(observer)
|
|
130
136
|
}
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
fun handleOnDropViewInstance() {
|
|
140
|
+
activityLifecycleObserver?.let { observer ->
|
|
141
|
+
activityLifecycleOwner?.lifecycle?.removeObserver(observer)
|
|
142
|
+
}
|
|
143
|
+
activityLifecycleObserver = null
|
|
144
|
+
activityLifecycleOwner = null
|
|
145
|
+
|
|
134
146
|
if (lifecycleRegistry.currentState.isAtLeast(Lifecycle.State.CREATED)) {
|
|
135
147
|
lifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY)
|
|
136
148
|
}
|
|
@@ -1072,6 +1072,10 @@ class StripeSdkModule(
|
|
|
1072
1072
|
promise.resolve(createMissingInitError())
|
|
1073
1073
|
return
|
|
1074
1074
|
}
|
|
1075
|
+
|
|
1076
|
+
// Use connectedAccountId from params if provided, otherwise fall back to global stripeAccountId
|
|
1077
|
+
val accountId = getValOr(params, "connectedAccountId", null) ?: stripeAccountId
|
|
1078
|
+
|
|
1075
1079
|
unregisterStripeUIManager(financialConnectionsSheetManager)
|
|
1076
1080
|
financialConnectionsSheetManager =
|
|
1077
1081
|
FinancialConnectionsSheetManager(
|
|
@@ -1079,7 +1083,7 @@ class StripeSdkModule(
|
|
|
1079
1083
|
clientSecret,
|
|
1080
1084
|
FinancialConnectionsSheetManager.Mode.ForToken,
|
|
1081
1085
|
publishableKey,
|
|
1082
|
-
|
|
1086
|
+
accountId,
|
|
1083
1087
|
).also {
|
|
1084
1088
|
registerStripeUIManager(it)
|
|
1085
1089
|
it.present(promise)
|
|
@@ -1097,6 +1101,9 @@ class StripeSdkModule(
|
|
|
1097
1101
|
return
|
|
1098
1102
|
}
|
|
1099
1103
|
|
|
1104
|
+
// Use connectedAccountId from params if provided, otherwise fall back to global stripeAccountId
|
|
1105
|
+
val accountId = getValOr(params, "connectedAccountId", null) ?: stripeAccountId
|
|
1106
|
+
|
|
1100
1107
|
unregisterStripeUIManager(financialConnectionsSheetManager)
|
|
1101
1108
|
financialConnectionsSheetManager =
|
|
1102
1109
|
FinancialConnectionsSheetManager(
|
|
@@ -1104,7 +1111,7 @@ class StripeSdkModule(
|
|
|
1104
1111
|
clientSecret,
|
|
1105
1112
|
FinancialConnectionsSheetManager.Mode.ForSession,
|
|
1106
1113
|
publishableKey,
|
|
1107
|
-
|
|
1114
|
+
accountId,
|
|
1108
1115
|
).also {
|
|
1109
1116
|
registerStripeUIManager(it)
|
|
1110
1117
|
it.present(promise)
|
package/android/src/main/java/com/reactnativestripesdk/customersheet/CustomerSheetManager.kt
CHANGED
|
@@ -17,8 +17,7 @@ import com.reactnativestripesdk.ReactNativeCustomerSessionProvider
|
|
|
17
17
|
import com.reactnativestripesdk.buildBillingDetails
|
|
18
18
|
import com.reactnativestripesdk.buildBillingDetailsCollectionConfiguration
|
|
19
19
|
import com.reactnativestripesdk.buildPaymentSheetAppearance
|
|
20
|
-
import com.reactnativestripesdk.
|
|
21
|
-
import com.reactnativestripesdk.getBitmapFromDrawable
|
|
20
|
+
import com.reactnativestripesdk.convertDrawableToBase64
|
|
22
21
|
import com.reactnativestripesdk.mapToCardBrandAcceptance
|
|
23
22
|
import com.reactnativestripesdk.utils.CreateTokenErrorType
|
|
24
23
|
import com.reactnativestripesdk.utils.ErrorType
|
|
@@ -163,25 +162,49 @@ class CustomerSheetManager(
|
|
|
163
162
|
}
|
|
164
163
|
|
|
165
164
|
private fun handleResult(result: CustomerSheetResult) {
|
|
166
|
-
var promiseResult = Arguments.createMap()
|
|
167
165
|
when (result) {
|
|
168
166
|
is CustomerSheetResult.Failed -> {
|
|
169
167
|
resolvePresentPromise(createError(ErrorType.Failed.toString(), result.exception))
|
|
170
168
|
}
|
|
171
169
|
|
|
172
170
|
is CustomerSheetResult.Selected -> {
|
|
173
|
-
|
|
171
|
+
// Convert drawable asynchronously to avoid shared state issues
|
|
172
|
+
CoroutineScope(Dispatchers.Default).launch {
|
|
173
|
+
try {
|
|
174
|
+
val promiseResult = createPaymentOptionResult(result.selection)
|
|
175
|
+
resolvePresentPromise(promiseResult)
|
|
176
|
+
} catch (e: Exception) {
|
|
177
|
+
resolvePresentPromise(
|
|
178
|
+
createError(
|
|
179
|
+
ErrorType.Failed.toString(),
|
|
180
|
+
"Failed to process payment option image: ${e.message}",
|
|
181
|
+
),
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
174
185
|
}
|
|
175
186
|
|
|
176
187
|
is CustomerSheetResult.Canceled -> {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
188
|
+
// Convert drawable asynchronously to avoid shared state issues
|
|
189
|
+
CoroutineScope(Dispatchers.Default).launch {
|
|
190
|
+
try {
|
|
191
|
+
val promiseResult = createPaymentOptionResult(result.selection)
|
|
192
|
+
promiseResult.putMap(
|
|
193
|
+
"error",
|
|
194
|
+
Arguments.createMap().also { it.putString("code", ErrorType.Canceled.toString()) },
|
|
195
|
+
)
|
|
196
|
+
resolvePresentPromise(promiseResult)
|
|
197
|
+
} catch (e: Exception) {
|
|
198
|
+
resolvePresentPromise(
|
|
199
|
+
createError(
|
|
200
|
+
ErrorType.Failed.toString(),
|
|
201
|
+
"Failed to process payment option image: ${e.message}",
|
|
202
|
+
),
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
182
206
|
}
|
|
183
207
|
}
|
|
184
|
-
resolvePresentPromise(promiseResult)
|
|
185
208
|
}
|
|
186
209
|
|
|
187
210
|
override fun onPresent() {
|
|
@@ -355,7 +378,7 @@ class CustomerSheetManager(
|
|
|
355
378
|
)
|
|
356
379
|
}
|
|
357
380
|
|
|
358
|
-
internal fun createPaymentOptionResult(selection: PaymentOptionSelection?): WritableMap {
|
|
381
|
+
internal suspend fun createPaymentOptionResult(selection: PaymentOptionSelection?): WritableMap {
|
|
359
382
|
var paymentOptionResult = Arguments.createMap()
|
|
360
383
|
|
|
361
384
|
when (selection) {
|
|
@@ -392,16 +415,18 @@ class CustomerSheetManager(
|
|
|
392
415
|
}.build()
|
|
393
416
|
}
|
|
394
417
|
|
|
395
|
-
private fun buildResult(
|
|
418
|
+
private suspend fun buildResult(
|
|
396
419
|
label: String,
|
|
397
420
|
drawable: Drawable,
|
|
398
421
|
paymentMethod: PaymentMethod?,
|
|
399
422
|
): WritableMap {
|
|
423
|
+
val imageString = convertDrawableToBase64(drawable)
|
|
424
|
+
|
|
400
425
|
val result = Arguments.createMap()
|
|
401
426
|
val paymentOption =
|
|
402
427
|
Arguments.createMap().also {
|
|
403
428
|
it.putString("label", label)
|
|
404
|
-
it.putString("image",
|
|
429
|
+
it.putString("image", imageString)
|
|
405
430
|
}
|
|
406
431
|
result.putMap("paymentOption", paymentOption)
|
|
407
432
|
if (paymentMethod != null) {
|
|
@@ -25,7 +25,6 @@ import com.stripe.android.model.StripeIntent
|
|
|
25
25
|
import com.stripe.android.model.StripeIntent.NextActionData
|
|
26
26
|
import com.stripe.android.model.StripeIntent.NextActionType
|
|
27
27
|
import com.stripe.android.model.Token
|
|
28
|
-
import com.stripe.android.paymentelement.ExperimentalCustomPaymentMethodsApi
|
|
29
28
|
import com.stripe.android.paymentsheet.PaymentSheet
|
|
30
29
|
import java.lang.IllegalArgumentException
|
|
31
30
|
|
|
@@ -1036,7 +1035,6 @@ private fun Map<String, Any?>.toReadableMap(): ReadableMap {
|
|
|
1036
1035
|
return writableMap
|
|
1037
1036
|
}
|
|
1038
1037
|
|
|
1039
|
-
@OptIn(ExperimentalCustomPaymentMethodsApi::class)
|
|
1040
1038
|
@SuppressLint("RestrictedApi")
|
|
1041
1039
|
internal fun parseCustomPaymentMethods(customPaymentMethodConfig: ReadableMap?): List<PaymentSheet.CustomPaymentMethod> {
|
|
1042
1040
|
if (customPaymentMethodConfig == null) {
|