diff --git a/android/expoview/build.gradle b/android/expoview/build.gradle index 13a629564e57d..91f012073819e 100644 --- a/android/expoview/build.gradle +++ b/android/expoview/build.gradle @@ -322,8 +322,8 @@ dependencies { api 'com.github.troZee:ViewPager2:v1.0.6' // stripe-react-native - implementation('com.stripe:stripe-android:20.19.+') - implementation('com.stripe:financial-connections:20.19.+') + implementation('com.stripe:stripe-android:20.25.+') + implementation('com.stripe:financial-connections:20.25.+') compileOnly 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt index 4c93a8df97463..a855c6b484662 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt @@ -12,7 +12,7 @@ import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getIntOrNull import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getValOr -import com.stripe.android.databinding.BecsDebitWidgetBinding +import com.stripe.android.databinding.StripeBecsDebitWidgetBinding import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.BecsDebitWidget import com.stripe.android.view.StripeEditText @@ -35,7 +35,7 @@ class AuBECSDebitFormView(private val context: ThemedReactContext) : FrameLayout if (!this::becsDebitWidget.isInitialized || value == null) { return } - val binding = BecsDebitWidgetBinding.bind(becsDebitWidget) + val binding = StripeBecsDebitWidgetBinding.bind(becsDebitWidget) val textColor = getValOr(value, "textColor", null) val textErrorColor = getValOr(value, "textErrorColor", null) val placeholderColor = getValOr(value, "placeholderColor", null) diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt index 1003153f310f2..62917c281a169 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt @@ -22,7 +22,7 @@ import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.u import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode import com.stripe.android.core.model.CountryUtils -import com.stripe.android.databinding.CardInputWidgetBinding +import com.stripe.android.databinding.StripeCardInputWidgetBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.CardInputListener @@ -32,7 +32,7 @@ import com.stripe.android.view.StripeEditText class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { private var mCardWidget: CardInputWidget = CardInputWidget(context) - private val cardInputWidgetBinding = CardInputWidgetBinding.bind(mCardWidget) + private val cardInputWidgetBinding = StripeCardInputWidgetBinding.bind(mCardWidget) val cardDetails: MutableMap = mutableMapOf("brand" to "", "last4" to "", "expiryMonth" to null, "expiryYear" to null, "postalCode" to "", "validNumber" to "Unknown", "validCVC" to "Unknown", "validExpiryDate" to "Unknown") var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt index 473290472e98a..76daa2bdaaab9 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt @@ -20,7 +20,7 @@ import com.google.android.material.shape.ShapeAppearanceModel import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.* import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode -import com.stripe.android.databinding.CardMultilineWidgetBinding +import com.stripe.android.databinding.StripeCardMultilineWidgetBinding import com.stripe.android.databinding.StripeCardFormViewBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams @@ -36,7 +36,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null private val cardFormViewBinding = StripeCardFormViewBinding.bind(cardForm) - private val multilineWidgetBinding = CardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) + private val multilineWidgetBinding = StripeCardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) init { cardFormViewBinding.cardMultilineWidgetContainer.isFocusable = true diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt index 47bdafb4269d4..0e1cd34df59bd 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentMethodCreateParamsFactory.kt @@ -37,6 +37,7 @@ class PaymentMethodCreateParamsFactory( PaymentMethod.Type.USBankAccount -> createUSBankAccountParams(paymentMethodData) PaymentMethod.Type.PayPal -> createPayPalParams() PaymentMethod.Type.Affirm -> createAffirmParams() + PaymentMethod.Type.CashAppPay -> createCashAppParams() else -> { throw Exception("This paymentMethodType is not supported yet") } @@ -202,13 +203,17 @@ class PaymentMethodCreateParamsFactory( return PaymentMethodCreateParams.createAffirm(billingDetailsParams) } + @Throws(PaymentMethodCreateParamsException::class) + private fun createCashAppParams(): PaymentMethodCreateParams { + return PaymentMethodCreateParams.createCashAppPay(billingDetailsParams) + } + @Throws(PaymentMethodCreateParamsException::class) fun createParams(clientSecret: String, paymentMethodType: PaymentMethod.Type?, isPaymentIntent: Boolean): ConfirmStripeIntentParams { try { return when (paymentMethodType) { PaymentMethod.Type.Card -> createCardStripeIntentParams(clientSecret, isPaymentIntent) PaymentMethod.Type.USBankAccount -> createUSBankAccountStripeIntentParams(clientSecret, isPaymentIntent) - PaymentMethod.Type.PayPal -> createPayPalStripeIntentParams(clientSecret, isPaymentIntent) PaymentMethod.Type.Affirm -> createAffirmStripeIntentParams(clientSecret, isPaymentIntent) PaymentMethod.Type.Ideal, PaymentMethod.Type.Alipay, @@ -223,7 +228,9 @@ class PaymentMethodCreateParamsFactory( PaymentMethod.Type.Fpx, PaymentMethod.Type.AfterpayClearpay, PaymentMethod.Type.AuBecsDebit, - PaymentMethod.Type.Klarna -> { + PaymentMethod.Type.Klarna, + PaymentMethod.Type.PayPal, + PaymentMethod.Type.CashAppPay -> { val params = createPaymentMethodParams(paymentMethodType) return if (isPaymentIntent) { @@ -232,11 +239,13 @@ class PaymentMethodCreateParamsFactory( paymentMethodCreateParams = params, clientSecret = clientSecret, setupFutureUsage = mapToPaymentIntentFutureUsage(getValOr(options, "setupFutureUsage")), + mandateData = buildMandateDataParams() ) } else { ConfirmSetupIntentParams.create( paymentMethodCreateParams = params, clientSecret = clientSecret, + mandateData = buildMandateDataParams() ) } } @@ -339,20 +348,6 @@ class PaymentMethodCreateParamsFactory( } } - @Throws(PaymentMethodCreateParamsException::class) - private fun createPayPalStripeIntentParams(clientSecret: String, isPaymentIntent: Boolean): ConfirmStripeIntentParams { - if (!isPaymentIntent) { - throw PaymentMethodCreateParamsException("PayPal is not yet supported through SetupIntents.") - } - - val params = createPayPalParams() - - return ConfirmPaymentIntentParams.createWithPaymentMethodCreateParams( - paymentMethodCreateParams = params, - clientSecret = clientSecret, - ) - } - @Throws(PaymentMethodCreateParamsException::class) private fun createAffirmStripeIntentParams(clientSecret: String, isPaymentIntent: Boolean): ConfirmStripeIntentParams { if (!isPaymentIntent) { @@ -366,6 +361,7 @@ class PaymentMethodCreateParamsFactory( paymentMethodCreateParams = params, clientSecret = clientSecret, setupFutureUsage = mapToPaymentIntentFutureUsage(getValOr(options, "setupFutureUsage")), + mandateData = buildMandateDataParams() ) } @@ -401,6 +397,20 @@ class PaymentMethodCreateParamsFactory( null ) } + + private fun buildMandateDataParams(): MandateDataParams? { + getMapOrNull(paymentMethodData, "mandateData")?.let { mandateData -> + getMapOrNull(mandateData, "customerAcceptance")?.let { customerAcceptance -> + getMapOrNull(customerAcceptance, "online")?.let { onlineParams -> + return MandateDataParams(MandateDataParams.Type.Online( + ipAddress = getValOr(onlineParams, "ipAddress", "") ?: "", + userAgent = getValOr(onlineParams, "userAgent", "") ?: "", + )) + } + } + } + return null + } } class PaymentMethodCreateParamsException(message: String) : Exception(message) diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentSheetFragment.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentSheetFragment.kt index 93c2ae9c6d683..a5223b1cb869e 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentSheetFragment.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/PaymentSheetFragment.kt @@ -1,10 +1,14 @@ package versioned.host.exp.exponent.modules.api.components.reactnativestripesdk +import android.app.Activity +import android.app.Application import android.content.Context import android.graphics.Bitmap import android.graphics.Canvas import android.graphics.Color import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.util.Base64 import android.view.LayoutInflater import android.view.View @@ -21,10 +25,7 @@ import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.a import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.* import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.createError import versioned.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.createResult -import com.stripe.android.paymentsheet.PaymentOptionCallback -import com.stripe.android.paymentsheet.PaymentSheet -import com.stripe.android.paymentsheet.PaymentSheetResult -import com.stripe.android.paymentsheet.PaymentSheetResultCallback +import com.stripe.android.paymentsheet.* import java.io.ByteArrayOutputStream class PaymentSheetFragment( @@ -38,6 +39,7 @@ class PaymentSheetFragment( private lateinit var paymentSheetConfiguration: PaymentSheet.Configuration private var confirmPromise: Promise? = null private var presentPromise: Promise? = null + private var paymentSheetTimedOut = false override fun onCreateView( inflater: LayoutInflater, @@ -62,6 +64,7 @@ class PaymentSheetFragment( val googlePayConfig = buildGooglePayConfig(arguments?.getBundle("googlePay")) val allowsDelayedPaymentMethods = arguments?.getBoolean("allowsDelayedPaymentMethods") val billingDetailsBundle = arguments?.getBundle("defaultBillingDetails") + val billingConfigParams = arguments?.getBundle("billingDetailsCollectionConfiguration") paymentIntentClientSecret = arguments?.getString("paymentIntentClientSecret").orEmpty() setupIntentClientSecret = arguments?.getString("setupIntentClientSecret").orEmpty() val appearance = try { @@ -84,27 +87,48 @@ class PaymentSheetFragment( option.putString("image", imageString) createResult("paymentOption", option) } ?: run { - createError(PaymentSheetErrorType.Canceled.toString(), "The payment option selection flow has been canceled") + if (paymentSheetTimedOut) { + paymentSheetTimedOut = false + createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out") + } else { + createError(PaymentSheetErrorType.Canceled.toString(), "The payment option selection flow has been canceled") + } } presentPromise?.resolve(result) } val paymentResultCallback = PaymentSheetResultCallback { paymentResult -> - when (paymentResult) { - is PaymentSheetResult.Canceled -> { - resolvePaymentResult(createError(PaymentSheetErrorType.Canceled.toString(), "The payment flow has been canceled")) - } - is PaymentSheetResult.Failed -> { - resolvePaymentResult(createError(PaymentSheetErrorType.Failed.toString(), paymentResult.error)) - } - is PaymentSheetResult.Completed -> { - resolvePaymentResult(WritableNativeMap()) - // Remove the fragment now, we can be sure it won't be needed again if an intent is successful - removeFragment(context) + if (paymentSheetTimedOut) { + paymentSheetTimedOut = false + resolvePaymentResult(createError(PaymentSheetErrorType.Timeout.toString(), "The payment has timed out")) + } else { + when (paymentResult) { + is PaymentSheetResult.Canceled -> { + resolvePaymentResult(createError(PaymentSheetErrorType.Canceled.toString(), "The payment flow has been canceled")) + } + is PaymentSheetResult.Failed -> { + resolvePaymentResult(createError(PaymentSheetErrorType.Failed.toString(), paymentResult.error)) + } + is PaymentSheetResult.Completed -> { + resolvePaymentResult(WritableNativeMap()) + // Remove the fragment now, we can be sure it won't be needed again if an intent is successful + removeFragment(context) + paymentSheet = null + flowController = null + } } } } + val billingDetailsConfig = PaymentSheet.BillingDetailsCollectionConfiguration( + name = mapToCollectionMode(billingConfigParams?.getString("name")), + phone = mapToCollectionMode(billingConfigParams?.getString("phone")), + email = mapToCollectionMode(billingConfigParams?.getString("email")), + address = mapToAddressCollectionMode(billingConfigParams?.getString("address")), + attachDefaultsToPaymentMethod = billingConfigParams?.getBoolean("attachDefaultsToPaymentMethod") + ?: false + ) + var defaultBillingDetails: PaymentSheet.BillingDetails? = null if (billingDetailsBundle != null) { val addressBundle = billingDetailsBundle.getBundle("address") @@ -133,7 +157,8 @@ class PaymentSheetFragment( googlePay = googlePayConfig, appearance = appearance, shippingDetails = shippingDetails, - primaryButtonLabel = primaryButtonLabel + primaryButtonLabel = primaryButtonLabel, + billingDetailsCollectionConfiguration = billingDetailsConfig ) if (arguments?.getBoolean("customFlow") == true) { @@ -155,7 +180,45 @@ class PaymentSheetFragment( } } else if(flowController != null) { flowController?.presentPaymentOptions() + } else { + promise.resolve(createMissingInitError()) + } + } + + fun presentWithTimeout(timeout: Long, promise: Promise) { + var paymentSheetActivity: Activity? = null + + val activityLifecycleCallbacks = object : Application.ActivityLifecycleCallbacks { + override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { + paymentSheetActivity = activity + } + + override fun onActivityStarted(activity: Activity) {} + + override fun onActivityResumed(activity: Activity) {} + + override fun onActivityPaused(activity: Activity) {} + + override fun onActivityStopped(activity: Activity) {} + + override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {} + + override fun onActivityDestroyed(activity: Activity) { + paymentSheetActivity = null + context.currentActivity?.application?.unregisterActivityLifecycleCallbacks(this) + } } + + Handler(Looper.getMainLooper()).postDelayed({ + paymentSheetActivity?.let { + it.finish() + paymentSheetTimedOut = true + } + }, timeout) + + context.currentActivity?.application?.registerActivityLifecycleCallbacks(activityLifecycleCallbacks) + + this.present(promise) } fun confirmPayment(promise: Promise) { @@ -205,6 +268,10 @@ class PaymentSheetFragment( companion object { internal const val TAG = "payment_sheet_launch_fragment" + internal fun createMissingInitError(): WritableMap { + return createError(PaymentSheetErrorType.Failed.toString(), "No payment sheet has been initialized yet. You must call `initPaymentSheet` before `presentPaymentSheet`.") + } + internal fun buildGooglePayConfig(params: Bundle?): PaymentSheet.GooglePayConfiguration? { if (params == null) { return null @@ -244,3 +311,21 @@ fun getBase64FromBitmap(bitmap: Bitmap?): String? { val imageBytes: ByteArray = stream.toByteArray() return Base64.encodeToString(imageBytes, Base64.DEFAULT) } + +fun mapToCollectionMode(str: String?): PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode { + return when (str) { + "automatic" -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Automatic + "never" -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Never + "always" -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Always + else -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode.Automatic + } +} + +fun mapToAddressCollectionMode(str: String?): PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode { + return when (str) { + "automatic" -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Automatic + "never" -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Never + "full" -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Full + else -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode.Automatic + } +} diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/StripeSdkModule.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/StripeSdkModule.kt index 9279d9c17c29d..989b6624d1f08 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/StripeSdkModule.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/StripeSdkModule.kt @@ -172,12 +172,29 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ } @ReactMethod - fun presentPaymentSheet(promise: Promise) { - paymentSheetFragment?.present(promise) + fun presentPaymentSheet(options: ReadableMap, promise: Promise) { + if (paymentSheetFragment == null) { + promise.resolve(PaymentSheetFragment.createMissingInitError()) + return + } + + val timeoutKey = "timeout" + if (options.hasKey(timeoutKey)) { + paymentSheetFragment?.presentWithTimeout( + options.getInt(timeoutKey).toLong(), promise + ) + } else { + paymentSheetFragment?.present(promise) + } } @ReactMethod fun confirmPaymentSheetPayment(promise: Promise) { + if (paymentSheetFragment == null) { + promise.resolve(PaymentSheetFragment.createMissingInitError()) + return + } + paymentSheetFragment?.confirmPayment(promise) } @@ -511,10 +528,11 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ @ReactMethod fun isPlatformPaySupported(params: ReadableMap?, promise: Promise) { + val googlePayParams = params?.getMap("googlePay") val fragment = GooglePayPaymentMethodLauncherFragment( reactApplicationContext, - getBooleanOrFalse(params, "testEnv"), - getBooleanOrFalse(params, "existingPaymentMethodRequired"), + getBooleanOrFalse(googlePayParams, "testEnv"), + getBooleanOrFalse(googlePayParams, "existingPaymentMethodRequired"), promise ) @@ -679,7 +697,7 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ return } - if (!PushProvisioningProxy.isNFCEnabled(reactApplicationContext)) { + if (params.getBooleanOr("supportsTapToPay", true) && !PushProvisioningProxy.isNFCEnabled(reactApplicationContext)) { promise.resolve(createCanAddCardResult(false, "UNSUPPORTED_DEVICE")) return } diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt index a91b55f0dbed4..203a7c92ce861 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/AddToWalletButtonView.kt @@ -5,6 +5,7 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.graphics.drawable.RippleDrawable import android.view.MotionEvent +import android.webkit.URLUtil import androidx.appcompat.widget.AppCompatImageView import com.bumptech.glide.RequestManager import com.bumptech.glide.load.DataSource @@ -27,7 +28,7 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val private var token: ReadableMap? = null private var eventDispatcher: EventDispatcher? = context.getNativeModule(UIManagerModule::class.java)?.eventDispatcher - private var loadedSource: GlideUrl? = null + private var loadedSource: Any? = null private var heightOverride: Int = 0 private var widthOverride: Int = 0 @@ -66,7 +67,7 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val } fun onAfterUpdateTransaction() { - val sourceToLoad = createUrlFromSourceMap(sourceMap) + val sourceToLoad = getUrlOrResourceId(sourceMap) if (sourceToLoad == null) { requestManager.clear(this) setImageDrawable(null) @@ -99,9 +100,17 @@ class AddToWalletButtonView(private val context: ThemedReactContext, private val } } - private fun createUrlFromSourceMap(sourceMap: ReadableMap?): GlideUrl? { - val uriKey = sourceMap?.getString("uri") - return uriKey?.let { GlideUrl(uriKey) } + private fun getUrlOrResourceId(sourceMap: ReadableMap?): Any? { + sourceMap?.getString("uri")?.let { + return if (URLUtil.isValidUrl(it)) { + // Debug mode, Image.resolveAssetSource resolves to local http:// URL + GlideUrl(it) + } else { + // Release mode, Image.resolveAssetSource resolves to a drawable resource + context.resources.getIdentifier(it, "drawable", context.packageName) + } + } + return null } override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/PushProvisioningProxy.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/PushProvisioningProxy.kt index 40cb018937b2d..c1e61db776eb8 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/PushProvisioningProxy.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/pushprovisioning/PushProvisioningProxy.kt @@ -33,7 +33,7 @@ object PushProvisioningProxy { fun isNFCEnabled(context: ReactApplicationContext): Boolean { return if (context.packageManager.hasSystemFeature(PackageManager.FEATURE_NFC)) { val adapter = NfcAdapter.getDefaultAdapter(context) - adapter.isEnabled + adapter?.isEnabled ?: false } else { false } diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Errors.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Errors.kt index 76604f6473bf9..35f0293841edb 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Errors.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Errors.kt @@ -34,7 +34,7 @@ enum class RetrieveSetupIntentErrorType { } enum class PaymentSheetErrorType { - Failed, Canceled + Failed, Canceled, Timeout } enum class GooglePayErrorType { diff --git a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Mappers.kt b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Mappers.kt index 83f24a1990bdb..d3aa258c9f3c8 100644 --- a/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Mappers.kt +++ b/android/expoview/src/main/java/versioned/host/exp/exponent/modules/api/components/reactnativestripesdk/utils/Mappers.kt @@ -123,6 +123,7 @@ internal fun mapPaymentMethodType(type: PaymentMethod.Type?): String { PaymentMethod.Type.USBankAccount -> "USBankAccount" PaymentMethod.Type.PayPal -> "PayPal" PaymentMethod.Type.Affirm -> "Affirm" + PaymentMethod.Type.CashAppPay -> "CashApp" else -> "Unknown" } } @@ -152,6 +153,7 @@ internal fun mapToPaymentMethodType(type: String?): PaymentMethod.Type? { "USBankAccount" -> PaymentMethod.Type.USBankAccount "PayPal" -> PaymentMethod.Type.PayPal "Affirm" -> PaymentMethod.Type.Affirm + "CashApp" -> PaymentMethod.Type.CashAppPay else -> null } } @@ -312,7 +314,7 @@ internal fun mapFromCard(card: Card?): WritableMap? { internal fun mapFromToken(token: Token): WritableMap { val tokenMap: WritableMap = WritableNativeMap() tokenMap.putString("id", token.id) - tokenMap.putDouble("created", token.created.time.toDouble()) + tokenMap.putString("created", token.created.time.toString()) tokenMap.putString("type", mapTokenType(token.type)) tokenMap.putBoolean("livemode", token.livemode) tokenMap.putMap("bankAccount", mapFromBankAccount(token.bankAccount)) @@ -344,6 +346,9 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap { it.putString("fingerprint", paymentMethod.card?.fingerprint) it.putString("preferredNetwork", paymentMethod.card?.networks?.preferred) it.putArray("availableNetworks", paymentMethod.card?.networks?.available?.toList() as? ReadableArray) + it.putMap("threeDSecureUsage", WritableNativeMap().also { threeDSecureUsageMap -> + threeDSecureUsageMap.putBoolean("isSupported", paymentMethod.card?.threeDSecureUsage?.isSupported ?: false) + }) }) pm.putMap("SepaDebit", WritableNativeMap().also { it.putString("bankCode", paymentMethod.sepaDebit?.bankCode) diff --git a/android/versioned-abis/expoview-abi47_0_0/build.gradle b/android/versioned-abis/expoview-abi47_0_0/build.gradle index 127ea86782c3e..316a18d7781c5 100644 --- a/android/versioned-abis/expoview-abi47_0_0/build.gradle +++ b/android/versioned-abis/expoview-abi47_0_0/build.gradle @@ -198,8 +198,8 @@ dependencies { api 'com.github.troZee:ViewPager2:v1.0.6' // stripe-react-native - implementation('com.stripe:stripe-android:20.19.+') - implementation('com.stripe:financial-connections:20.19.+') + implementation('com.stripe:stripe-android:20.25.+') + implementation('com.stripe:financial-connections:20.25.+') compileOnly 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" diff --git a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt index 9022cdfbeca0d..62663496fed83 100644 --- a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt +++ b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt @@ -12,7 +12,7 @@ import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getIntOrNull import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getValOr -import com.stripe.android.databinding.BecsDebitWidgetBinding +import com.stripe.android.databinding.StripeBecsDebitWidgetBinding import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.BecsDebitWidget import com.stripe.android.view.StripeEditText @@ -35,7 +35,7 @@ class AuBECSDebitFormView(private val context: ThemedReactContext) : FrameLayout if (!this::becsDebitWidget.isInitialized || value == null) { return } - val binding = BecsDebitWidgetBinding.bind(becsDebitWidget) + val binding = StripeBecsDebitWidgetBinding.bind(becsDebitWidget) val textColor = getValOr(value, "textColor", null) val textErrorColor = getValOr(value, "textErrorColor", null) val placeholderColor = getValOr(value, "placeholderColor", null) diff --git a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt index e06ff4e1ecba2..56b6e7c9a0ab1 100644 --- a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt +++ b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt @@ -21,7 +21,7 @@ import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.u import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode import com.stripe.android.core.model.CountryUtils -import com.stripe.android.databinding.CardInputWidgetBinding +import com.stripe.android.databinding.StripeCardInputWidgetBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.CardInputListener @@ -31,7 +31,7 @@ import com.stripe.android.view.StripeEditText class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { private var mCardWidget: CardInputWidget = CardInputWidget(context) - private val cardInputWidgetBinding = CardInputWidgetBinding.bind(mCardWidget) + private val cardInputWidgetBinding = StripeCardInputWidgetBinding.bind(mCardWidget) val cardDetails: MutableMap = mutableMapOf("brand" to "", "last4" to "", "expiryMonth" to null, "expiryYear" to null, "postalCode" to "", "validNumber" to "Unknown", "validCVC" to "Unknown", "validExpiryDate" to "Unknown") var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null diff --git a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt index 7d795eacfb5c2..86a10635cb119 100644 --- a/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt +++ b/android/versioned-abis/expoview-abi47_0_0/src/main/java/abi47_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt @@ -18,7 +18,7 @@ import com.google.android.material.shape.ShapeAppearanceModel import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.* import abi47_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode -import com.stripe.android.databinding.CardMultilineWidgetBinding +import com.stripe.android.databinding.StripeCardMultilineWidgetBinding import com.stripe.android.databinding.StripeCardFormViewBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams @@ -34,7 +34,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null private val cardFormViewBinding = StripeCardFormViewBinding.bind(cardForm) - private val multilineWidgetBinding = CardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) + private val multilineWidgetBinding = StripeCardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) init { cardFormViewBinding.cardMultilineWidgetContainer.isFocusable = true diff --git a/android/versioned-abis/expoview-abi48_0_0/build.gradle b/android/versioned-abis/expoview-abi48_0_0/build.gradle index 1cf383ca0ba41..84bd083a97a17 100644 --- a/android/versioned-abis/expoview-abi48_0_0/build.gradle +++ b/android/versioned-abis/expoview-abi48_0_0/build.gradle @@ -203,8 +203,8 @@ dependencies { api 'com.github.troZee:ViewPager2:v1.0.6' // stripe-react-native - implementation('com.stripe:stripe-android:20.19.+') - implementation('com.stripe:financial-connections:20.19.+') + implementation('com.stripe:stripe-android:20.25.+') + implementation('com.stripe:financial-connections:20.25.+') compileOnly 'com.stripe:stripe-android-issuing-push-provisioning:1.1.0' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.0' implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1" diff --git a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt index 295cc196dd0a1..9ecec163b5844 100644 --- a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt +++ b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/AuBECSDebitFormView.kt @@ -12,7 +12,7 @@ import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.shape.ShapeAppearanceModel import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getIntOrNull import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.getValOr -import com.stripe.android.databinding.BecsDebitWidgetBinding +import com.stripe.android.databinding.StripeBecsDebitWidgetBinding import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.BecsDebitWidget import com.stripe.android.view.StripeEditText @@ -35,7 +35,7 @@ class AuBECSDebitFormView(private val context: ThemedReactContext) : FrameLayout if (!this::becsDebitWidget.isInitialized || value == null) { return } - val binding = BecsDebitWidgetBinding.bind(becsDebitWidget) + val binding = StripeBecsDebitWidgetBinding.bind(becsDebitWidget) val textColor = getValOr(value, "textColor", null) val textErrorColor = getValOr(value, "textErrorColor", null) val placeholderColor = getValOr(value, "placeholderColor", null) diff --git a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt index 4f7bf8c700e32..f8e77e8a63b72 100644 --- a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt +++ b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFieldView.kt @@ -22,7 +22,7 @@ import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.u import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode import com.stripe.android.core.model.CountryUtils -import com.stripe.android.databinding.CardInputWidgetBinding +import com.stripe.android.databinding.StripeCardInputWidgetBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams import com.stripe.android.view.CardInputListener @@ -32,7 +32,7 @@ import com.stripe.android.view.StripeEditText class CardFieldView(context: ThemedReactContext) : FrameLayout(context) { private var mCardWidget: CardInputWidget = CardInputWidget(context) - private val cardInputWidgetBinding = CardInputWidgetBinding.bind(mCardWidget) + private val cardInputWidgetBinding = StripeCardInputWidgetBinding.bind(mCardWidget) val cardDetails: MutableMap = mutableMapOf("brand" to "", "last4" to "", "expiryMonth" to null, "expiryYear" to null, "postalCode" to "", "validNumber" to "Unknown", "validCVC" to "Unknown", "validExpiryDate" to "Unknown") var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null diff --git a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt index a2aaa6e29b8d2..98656509cfabe 100644 --- a/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt +++ b/android/versioned-abis/expoview-abi48_0_0/src/main/java/abi48_0_0/host/exp/exponent/modules/api/components/reactnativestripesdk/CardFormView.kt @@ -20,7 +20,7 @@ import com.google.android.material.shape.ShapeAppearanceModel import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.* import abi48_0_0.host.exp.exponent.modules.api.components.reactnativestripesdk.utils.mapCardBrand import com.stripe.android.core.model.CountryCode -import com.stripe.android.databinding.CardMultilineWidgetBinding +import com.stripe.android.databinding.StripeCardMultilineWidgetBinding import com.stripe.android.databinding.StripeCardFormViewBinding import com.stripe.android.model.Address import com.stripe.android.model.PaymentMethodCreateParams @@ -36,7 +36,7 @@ class CardFormView(context: ThemedReactContext) : FrameLayout(context) { var cardParams: PaymentMethodCreateParams.Card? = null var cardAddress: Address? = null private val cardFormViewBinding = StripeCardFormViewBinding.bind(cardForm) - private val multilineWidgetBinding = CardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) + private val multilineWidgetBinding = StripeCardMultilineWidgetBinding.bind(cardFormViewBinding.cardMultilineWidget) init { cardFormViewBinding.cardMultilineWidgetContainer.isFocusable = true diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 75bf28e2b24b2..ef9a598aa31b8 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -651,12 +651,12 @@ PODS: - ABI47_0_0React-Core - ABI47_0_0stripe-react-native (0.19.0): - ABI47_0_0React-Core - - Stripe (~> 23.3.0) - - StripeApplePay (~> 23.3.0) - - StripeFinancialConnections (~> 23.3.0) - - StripePayments (~> 23.3.0) - - StripePaymentSheet (~> 23.3.0) - - StripePaymentsUI (~> 23.3.0) + - Stripe (~> 23.8.0) + - StripeApplePay (~> 23.8.0) + - StripeFinancialConnections (~> 23.8.0) + - StripePayments (~> 23.8.0) + - StripePaymentSheet (~> 23.8.0) + - StripePaymentsUI (~> 23.8.0) - ABI47_0_0UMAppLoader (4.0.0) - ABI47_0_0Yoga (1.14.0) - ABI48_0_0EASClient (0.5.1): @@ -1375,12 +1375,12 @@ PODS: - ABI48_0_0React-Core - ABI48_0_0stripe-react-native (0.23.3): - ABI48_0_0React-Core - - Stripe (~> 23.3.0) - - StripeApplePay (~> 23.3.0) - - StripeFinancialConnections (~> 23.3.0) - - StripePayments (~> 23.3.0) - - StripePaymentSheet (~> 23.3.0) - - StripePaymentsUI (~> 23.3.0) + - Stripe (~> 23.8.0) + - StripeApplePay (~> 23.8.0) + - StripeFinancialConnections (~> 23.8.0) + - StripePayments (~> 23.8.0) + - StripePaymentSheet (~> 23.8.0) + - StripePaymentsUI (~> 23.8.0) - ABI48_0_0UMAppLoader (4.1.1) - ABI48_0_0Yoga (1.14.0) - Analytics (4.1.8) @@ -2257,42 +2257,42 @@ PODS: - libwebp (~> 1.0) - SDWebImage/Core (~> 5.15) - SocketRocket (0.6.0) - - Stripe (23.3.4): - - StripeApplePay (= 23.3.4) - - StripeCore (= 23.3.4) - - StripePayments (= 23.3.4) - - StripePaymentsUI (= 23.3.4) - - StripeUICore (= 23.3.4) - - stripe-react-native (0.23.3): + - Stripe (23.8.0): + - StripeApplePay (= 23.8.0) + - StripeCore (= 23.8.0) + - StripePayments (= 23.8.0) + - StripePaymentsUI (= 23.8.0) + - StripeUICore (= 23.8.0) + - stripe-react-native (0.27.2): - React-Core - - Stripe (~> 23.3.0) - - StripeApplePay (~> 23.3.0) - - StripeFinancialConnections (~> 23.3.0) - - StripePayments (~> 23.3.0) - - StripePaymentSheet (~> 23.3.0) - - StripePaymentsUI (~> 23.3.0) - - StripeApplePay (23.3.4): - - StripeCore (= 23.3.4) - - StripeCore (23.3.4) - - StripeFinancialConnections (23.3.4): - - StripeCore (= 23.3.4) - - StripeUICore (= 23.3.4) - - StripePayments (23.3.4): - - StripeCore (= 23.3.4) - - StripePayments/Stripe3DS2 (= 23.3.4) - - StripePayments/Stripe3DS2 (23.3.4): - - StripeCore (= 23.3.4) - - StripePaymentSheet (23.3.4): - - StripeApplePay (= 23.3.4) - - StripeCore (= 23.3.4) - - StripePayments (= 23.3.4) - - StripePaymentsUI (= 23.3.4) - - StripePaymentsUI (23.3.4): - - StripeCore (= 23.3.4) - - StripePayments (= 23.3.4) - - StripeUICore (= 23.3.4) - - StripeUICore (23.3.4): - - StripeCore (= 23.3.4) + - Stripe (~> 23.8.0) + - StripeApplePay (~> 23.8.0) + - StripeFinancialConnections (~> 23.8.0) + - StripePayments (~> 23.8.0) + - StripePaymentSheet (~> 23.8.0) + - StripePaymentsUI (~> 23.8.0) + - StripeApplePay (23.8.0): + - StripeCore (= 23.8.0) + - StripeCore (23.8.0) + - StripeFinancialConnections (23.8.0): + - StripeCore (= 23.8.0) + - StripeUICore (= 23.8.0) + - StripePayments (23.8.0): + - StripeCore (= 23.8.0) + - StripePayments/Stripe3DS2 (= 23.8.0) + - StripePayments/Stripe3DS2 (23.8.0): + - StripeCore (= 23.8.0) + - StripePaymentSheet (23.8.0): + - StripeApplePay (= 23.8.0) + - StripeCore (= 23.8.0) + - StripePayments (= 23.8.0) + - StripePaymentsUI (= 23.8.0) + - StripePaymentsUI (23.8.0): + - StripeCore (= 23.8.0) + - StripePayments (= 23.8.0) + - StripeUICore (= 23.8.0) + - StripeUICore (23.8.0): + - StripeCore (= 23.8.0) - UMAppLoader (4.1.2) - Yoga (1.14.0) - ZXingObjC/Core (3.6.5) @@ -3511,7 +3511,7 @@ SPEC CHECKSUMS: ABI47_0_0RNReanimated: 14fe3ece9c4654cdc3f37e1d4b4e544fe81e4641 ABI47_0_0RNScreens: b7b92c672e91734079636fbcf8fdac5a249aca8d ABI47_0_0RNSVG: 6ebc184a6e7f101269a30971df3bae6e93422b65 - ABI47_0_0stripe-react-native: 0da072b30eb714649506414f85e18a19911511d1 + ABI47_0_0stripe-react-native: 8f865f0a8dc71652ccf1c3f3ae5afcbc4ce248d7 ABI47_0_0UMAppLoader: b6f390d4e683ebfb1042a15ac2ec8ecdca796eb9 ABI47_0_0Yoga: 00f64b690ab46751611af3a78fb2032b31a3287d ABI48_0_0EASClient: d94d43ff199751369890423fbd8f0bea0706c69d @@ -3621,7 +3621,7 @@ SPEC CHECKSUMS: ABI48_0_0RNReanimated: 0fb27b63961864e65152a9ff66c784849f44b170 ABI48_0_0RNScreens: a3d32e7eea2da5f114caeebd7f40540ea8150058 ABI48_0_0RNSVG: 505e6c30ec1af5196e1ebc63b15f7f4883e37821 - ABI48_0_0stripe-react-native: 10d38e575f12896c284962183534058ece127c5e + ABI48_0_0stripe-react-native: a00d60443b6abb729be0e345085d902c62b8c7c7 ABI48_0_0UMAppLoader: 142596799d5a7b05119ae9f5c4e51ccc590e49a5 ABI48_0_0Yoga: 13a232e4a5d1ecd44a45e050b5983aa20116b1fa Analytics: 9655e0e1c71ea98107cfcb2b14891168acc6c6c9 @@ -3784,15 +3784,15 @@ SPEC CHECKSUMS: SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c SDWebImageWebPCoder: 295a6573c512f54ad2dd58098e64e17dcf008499 SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 - Stripe: 7393b16fe555d4a68e6555044e7b57eff11ae547 - stripe-react-native: c71683ecc56c63eecbb7172c2f97c8ac737fa37c - StripeApplePay: 174b09c0211134417e340c68af199a3dd34f3cd6 - StripeCore: babb08ec2b961f7cde8663dad3b4cbb77e0ae63b - StripeFinancialConnections: 484096f2dc5d3c20cc24a5ad4d261953ba806ef0 - StripePayments: 71bf62ccdacefc4b68b46a02a7f2492aeba252b3 - StripePaymentSheet: 722ea7bea092c243d771122fe3572a9c84512704 - StripePaymentsUI: fd08081c4be73c16322dc76a1878140520a9df2e - StripeUICore: ed68cbd5ad0626e0760e772f8c82d96cae9b829b + Stripe: 5432fbab660595a3bee937235dd71a99028ac68c + stripe-react-native: 3c3ce2b0dbc0b4a85d8eaa72e96b78ef679b87d6 + StripeApplePay: 5e686f50ee07c439b79b907dffeb144135e601c9 + StripeCore: 91164d69b8593f44df9ee93e56a00355592068b6 + StripeFinancialConnections: b30a494579271f33f38d9a934288c2ad617bfc26 + StripePayments: c19d94c55723894e1f47dadb40a6f1bfa7fac214 + StripePaymentSheet: 1fef5afa050bfd684e84553cba613041a2b3d7b7 + StripePaymentsUI: 7d2fc8fe17c3fdc63508bc54df2b7cc3f45c8ef7 + StripeUICore: 1dc4d2f9afcd908db85190e9091dfe260a1861fe UMAppLoader: d1cd37524ea948f9e695722994496784a6d6213c Yoga: 258bd5f6f188432f18cc3f854497f1cf6a0f21c1 ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb diff --git a/ios/vendored/sdk47/@stripe/stripe-react-native/ABI47_0_0stripe-react-native.podspec.json b/ios/vendored/sdk47/@stripe/stripe-react-native/ABI47_0_0stripe-react-native.podspec.json index 280a0adaad4a0..cb8f8644b62e2 100644 --- a/ios/vendored/sdk47/@stripe/stripe-react-native/ABI47_0_0stripe-react-native.podspec.json +++ b/ios/vendored/sdk47/@stripe/stripe-react-native/ABI47_0_0stripe-react-native.podspec.json @@ -17,22 +17,22 @@ "dependencies": { "ABI47_0_0React-Core": [], "Stripe": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentSheet": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePayments": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentsUI": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeApplePay": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeFinancialConnections": [ - "~> 23.3.0" + "~> 23.8.0" ] }, "testspecs": [ diff --git a/ios/vendored/sdk48/@stripe/stripe-react-native/ABI48_0_0stripe-react-native.podspec.json b/ios/vendored/sdk48/@stripe/stripe-react-native/ABI48_0_0stripe-react-native.podspec.json index 01a859d58a962..5895ae73fcc39 100644 --- a/ios/vendored/sdk48/@stripe/stripe-react-native/ABI48_0_0stripe-react-native.podspec.json +++ b/ios/vendored/sdk48/@stripe/stripe-react-native/ABI48_0_0stripe-react-native.podspec.json @@ -17,22 +17,22 @@ "dependencies": { "ABI48_0_0React-Core": [], "Stripe": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentSheet": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePayments": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentsUI": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeApplePay": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeFinancialConnections": [ - "~> 23.3.0" + "~> 23.8.0" ] }, "testspecs": [ diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonManager.m b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonManager.m index 58dcef892ffbd..de3630c054583 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonManager.m +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonManager.m @@ -11,5 +11,6 @@ @interface RCT_EXTERN_MODULE(ApplePayButtonManager, RCTViewManager) RCT_EXPORT_VIEW_PROPERTY(onShippingMethodSelectedAction, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onShippingContactSelectedAction, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onCouponCodeEnteredAction, RCTDirectEventBlock) +RCT_EXPORT_VIEW_PROPERTY(onOrderTrackingAction, RCTDirectEventBlock) @end diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonView.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonView.swift index fc60f277fa92e..6014be59123f5 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonView.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayButtonView.swift @@ -10,6 +10,7 @@ class ApplePayButtonView: UIView { @objc var onShippingMethodSelectedAction: RCTDirectEventBlock? @objc var onShippingContactSelectedAction: RCTDirectEventBlock? @objc var onCouponCodeEnteredAction: RCTDirectEventBlock? + @objc var onOrderTrackingAction: RCTDirectEventBlock? @objc var type: NSNumber? @objc var buttonStyle: NSNumber? @@ -33,6 +34,7 @@ class ApplePayButtonView: UIView { stripeSdk?.shippingMethodUpdateJSCallback = onShippingMethodSelectedAction stripeSdk?.shippingContactUpdateJSCallback = onShippingContactSelectedAction stripeSdk?.couponCodeEnteredJSCallback = onCouponCodeEnteredAction + stripeSdk?.platformPayOrderTrackingJSCallback = onOrderTrackingAction } } diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayUtils.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayUtils.swift index fef07d060198d..75e993a58618e 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayUtils.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayUtils.swift @@ -19,11 +19,7 @@ class ApplePayUtils { } if let additionalEnabledNetworks = params["additionalEnabledNetworks"] as? [String] { - do { - StripeAPI.additionalEnabledApplePayNetworks = try ApplePayUtils.mapToArrayOfPaymentNetworks(arrayOfStrings: additionalEnabledNetworks) - } catch { - return (Errors.createError(ErrorType.Failed, error.localizedDescription), nil) - } + StripeAPI.additionalEnabledApplePayNetworks = ApplePayUtils.mapToArrayOfPaymentNetworks(arrayOfStrings: additionalEnabledNetworks) } else if (params["jcbEnabled"] as? Bool == true) { StripeAPI.additionalEnabledApplePayNetworks = [.JCB] } @@ -61,7 +57,7 @@ class ApplePayUtils { do { paymentRequest.paymentSummaryItems = try ApplePayUtils .buildPaymentSummaryItems(items: summaryItems as? [[String : Any]]) - } catch { + } catch { return (Errors.createError(ErrorType.Failed, error.localizedDescription), nil) } @@ -84,10 +80,79 @@ class ApplePayUtils { paymentRequest.couponCode = couponCode } } - + + do { + try paymentRequest.configureRequestType(requestParams: params["request"] as? NSDictionary) + } catch { + return (Errors.createError(ErrorType.Failed, error.localizedDescription), nil) + } + return (nil, paymentRequest) } +#if compiler(>=5.7) + @available(iOS 16.0, *) + internal class func buildRecurringPaymentRequest(params: NSDictionary) throws -> PKRecurringPaymentRequest { + guard let description = params["description"] as? String else { + throw ApplePayUtilsError.missingParameter(nil, "description") + } + guard let urlString = params["managementUrl"] as? String else { + throw ApplePayUtilsError.missingParameter(nil, "managementUrl") + } + guard let url = URL(string: urlString) else { + throw ApplePayUtilsError.invalidUrl(urlString) + } + let regularBilling = try ApplePayUtils.createRecurringPaymentSummaryItem(item: params["billing"] as? [String : Any] ?? [:]) + let request = PKRecurringPaymentRequest(paymentDescription: description, regularBilling: regularBilling, managementURL: url) + if let trialParams = params["trialBilling"] as? [String : Any] { + request.trialBilling = try ApplePayUtils.createRecurringPaymentSummaryItem(item: trialParams) + } + if let tokenNotificationURL = params["tokenNotificationURL"] as? String { + request.tokenNotificationURL = URL(string: tokenNotificationURL) + } + request.billingAgreement = params["billingAgreement"] as? String + return request + } + + @available(iOS 16.0, *) + internal class func buildAutomaticReloadPaymentRequest(params: NSDictionary) throws -> PKAutomaticReloadPaymentRequest { + guard let description = params["description"] as? String else { + throw ApplePayUtilsError.missingParameter(nil, "description") + } + guard let urlString = params["managementUrl"] as? String else { + throw ApplePayUtilsError.missingParameter(nil, "managementUrl") + } + guard let url = URL(string: urlString) else { + throw ApplePayUtilsError.invalidUrl(urlString) + } + let automaticReloadBilling = PKAutomaticReloadPaymentSummaryItem.init(label: params["label"] as? String ?? "", amount: NSDecimalNumber(string: params["reloadAmount"] as? String ?? "")) + guard let threshold = params["thresholdAmount"] as? String else { + throw ApplePayUtilsError.missingParameter(nil, "thresholdAmount") + } + automaticReloadBilling.thresholdAmount = NSDecimalNumber(string: threshold) + let request = PKAutomaticReloadPaymentRequest(paymentDescription: description, automaticReloadBilling: automaticReloadBilling, managementURL: url) + if let tokenNotificationURL = params["tokenNotificationURL"] as? String { + request.tokenNotificationURL = URL(string: tokenNotificationURL) + } + request.billingAgreement = params["billingAgreement"] as? String + return request + } + + @available(iOS 16.0, *) + internal class func buildPaymentTokenContexts(items: [[String : Any]]) -> [PKPaymentTokenContext] { + var result: [PKPaymentTokenContext] = [] + for item in items { + let context = PKPaymentTokenContext.init(merchantIdentifier: item["merchantIdentifier"] as? String ?? "", + externalIdentifier: item["externalIdentifier"] as? String ?? "", + merchantName: item["merchantName"] as? String ?? "", + merchantDomain: item["merchantDomain"] as? String, + amount: NSDecimalNumber(string: item["thresholdAmount"] as? String ?? "")) + result.append(context) + } + return result + } +#endif + internal class func getMerchantCapabilityFrom(string: String?) -> PKMerchantCapability { switch string { case "supportsDebit": @@ -119,7 +184,7 @@ class ApplePayUtils { } @available(iOS 15.0, *) - internal class func createDeferredPaymentSummaryItem(item: [String : Any]) throws -> PKPaymentSummaryItem { + internal class func createDeferredPaymentSummaryItem(item: [String : Any]) throws -> PKDeferredPaymentSummaryItem { let label = item["label"] as? String ?? "" let amount = NSDecimalNumber(string: item["amount"] as? String ?? "") @@ -135,7 +200,7 @@ class ApplePayUtils { } @available(iOS 15.0, *) - internal class func createRecurringPaymentSummaryItem(item: [String : Any]) throws -> PKPaymentSummaryItem { + internal class func createRecurringPaymentSummaryItem(item: [String : Any]) throws -> PKRecurringPaymentSummaryItem { let label = item["label"] as? String ?? "" let amount = NSDecimalNumber(string: item["amount"] as? String ?? "") @@ -285,8 +350,8 @@ class ApplePayUtils { return (shippingAddressErrors, couponCodeErrors) } - internal class func mapToArrayOfPaymentNetworks(arrayOfStrings: [String]) throws -> [PKPaymentNetwork] { - let validNetworks: [PKPaymentNetwork?] = try arrayOfStrings.map { networkString in + internal class func mapToArrayOfPaymentNetworks(arrayOfStrings: [String]) -> [PKPaymentNetwork] { + let validNetworks: [PKPaymentNetwork?] = arrayOfStrings.map { networkString in return PKPaymentNetwork.init(rawValue: networkString) } return validNetworks.compactMap { $0 } @@ -295,7 +360,9 @@ class ApplePayUtils { public class func buildPaymentSheetApplePayConfig( merchantIdentifier: String?, merchantCountryCode: String?, - paymentSummaryItems: [[String : Any]]? + paymentSummaryItems: [[String : Any]]?, + buttonType: NSNumber?, + customHandlers: PaymentSheet.ApplePayConfiguration.Handlers? ) throws -> PaymentSheet.ApplePayConfiguration { guard let merchantId = merchantIdentifier else { throw ApplePayUtilsError.missingMerchantId @@ -306,20 +373,25 @@ class ApplePayUtils { let paymentSummaryItems = try ApplePayUtils.buildPaymentSummaryItems( items: paymentSummaryItems ) + return PaymentSheet.ApplePayConfiguration.init( merchantId: merchantId, merchantCountryCode: countryCode, - paymentSummaryItems:paymentSummaryItems.count > 0 ? paymentSummaryItems : nil + buttonType: PKPaymentButtonType(rawValue: buttonType as? Int ?? 0) ?? .plain, + paymentSummaryItems: paymentSummaryItems.count > 0 ? paymentSummaryItems : nil, + customHandlers: customHandlers ) } } enum ApplePayUtilsError : Error, Equatable { case invalidCartSummaryItemType(String) - case missingParameter(String, String) + case missingParameter(String?, String) case invalidTimeInterval(String) case invalidPaymentNetwork(String) case invalidErrorType(String) + case invalidUrl(String) + case invalidRequestType(String) case missingMerchantId case missingCountryCode } @@ -330,7 +402,11 @@ extension ApplePayUtilsError: LocalizedError { case .invalidCartSummaryItemType(let type): return "Failed to ceate Apple Pay summary item. Expected `type` to be one of 'Immediate', 'Recurring', or 'Deferred', but received: \(type)" case .missingParameter(let label, let parameter): - return "Failed to create Apple Pay summary item with label: \(label). The \(parameter) item parameter is required, but none was provided." + if let label = label { + return "Failed to create Apple Pay summary item with label: \(label). The \(parameter) item parameter is required, but none was provided." + } else { + return "The \(parameter) item parameter is required, but none was provided." + } case .invalidTimeInterval(let providedInterval): return "Failed to create Apple Pay summary item. \(providedInterval) is not a valid timeInterval, must be one of: minute, hour, day, month, or year." case .invalidPaymentNetwork(let network): @@ -341,6 +417,31 @@ extension ApplePayUtilsError: LocalizedError { return "`merchantIdentifier` is required, but none was found. Ensure you are passing this to initStripe your StripeProvider." case .missingCountryCode: return "`merchantCountryCode` is a required param, but was not provided." + case .invalidUrl(let url): + return "Invalid URL: \(url)." + case .invalidRequestType(let tyoe): + return "Apple Pay request type `\(tyoe)` is not supported." + } + } +} + +extension PKPaymentRequest { + func configureRequestType(requestParams: NSDictionary?) throws -> Void { +#if compiler(>=5.7) + if #available(iOS 16.0, *) { + if let requestParams = requestParams { + switch requestParams["type"] as? String { + case "Recurring": + self.recurringPaymentRequest = try ApplePayUtils.buildRecurringPaymentRequest(params: requestParams) + case "AutomaticReload": + self.automaticReloadPaymentRequest = try ApplePayUtils.buildAutomaticReloadPaymentRequest(params: requestParams) + case "MultiMerchant": + self.multiTokenContexts = ApplePayUtils.buildPaymentTokenContexts(items: requestParams["merchants"] as? [[String : Any]] ?? []) + default: + throw ApplePayUtilsError.invalidRequestType(String(describing: requestParams["type"])) + } + } } +#endif } } diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayViewController.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayViewController.swift index 63c77454666f1..d80ade7573d5a 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayViewController.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/ApplePayViewController.swift @@ -122,13 +122,13 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC didSelect shippingMethod: PKShippingMethod, handler: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void ) { + if (self.hasLegacyApplePayListeners) { + // Legacy, remove when useApplePay hook is removed + sendEvent(withName: "onDidSetShippingMethod", body: ["shippingMethod": Mappers.mapFromShippingMethod(shippingMethod: shippingMethod)]) + } if let callback = self.shippingMethodUpdateJSCallback { self.shippingMethodUpdateCompletion = handler callback(["shippingMethod": Mappers.mapFromShippingMethod(shippingMethod: shippingMethod)]) - if (self.hasLegacyApplePayListeners) { - // Legacy, remove when useApplePay hook is removed - sendEvent(withName: "onDidSetShippingMethod", body: ["shippingMethod": Mappers.mapFromShippingMethod(shippingMethod: shippingMethod)]) - } } else { handler( PKPaymentRequestShippingMethodUpdate.init(paymentSummaryItems: applePaySummaryItems) @@ -141,13 +141,13 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC didSelectShippingContact contact: PKContact, handler: @escaping (PKPaymentRequestShippingContactUpdate) -> Void ) { + if (self.hasLegacyApplePayListeners) { + // Legacy, remove when useApplePay hook is removed + sendEvent(withName: "onDidSetShippingContact", body: ["shippingContact": Mappers.mapFromShippingContact(shippingContact: contact)]) + } if let callback = self.shippingContactUpdateJSCallback { self.shippingContactUpdateCompletion = handler callback(["shippingContact": Mappers.mapFromShippingContact(shippingContact: contact)]) - if (self.hasLegacyApplePayListeners) { - // Legacy, remove when useApplePay hook is removed - sendEvent(withName: "onDidSetShippingContact", body: ["shippingContact": Mappers.mapFromShippingContact(shippingContact: contact)]) - } } else { handler( PKPaymentRequestShippingContactUpdate.init( @@ -177,6 +177,19 @@ extension StripeSdk : PKPaymentAuthorizationViewControllerDelegate, STPApplePayC } } + func applePayContext( + _ context: STPApplePayContext, + willCompleteWithResult authorizationResult: PKPaymentAuthorizationResult, + handler: @escaping (PKPaymentAuthorizationResult) -> Void + ) { + if let callback = self.platformPayOrderTrackingJSCallback { + self.orderTrackingHandler = (authorizationResult, handler) + callback(nil) + } else { + handler(authorizationResult) + } + } + func applePayContext( _ context: STPApplePayContext, didCompleteWith status: STPPaymentStatus, diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Errors.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Errors.swift index c0faba822789b..993c9b7a3b4aa 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Errors.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Errors.swift @@ -5,6 +5,7 @@ enum ErrorType { static let Failed = "Failed" static let Canceled = "Canceled" static let Unknown = "Unknown" + static let Timeout = "Timeout" } class Errors { diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Mappers.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Mappers.swift index 5157470bb3516..e2dd4a5153b75 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Mappers.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/Mappers.swift @@ -187,7 +187,7 @@ class Mappers { "isPending": shippingMethod.type == .pending, "label": shippingMethod.label ] - + if #available(iOS 15.0, *) { if let dateComponentsRange = shippingMethod.dateComponentsRange { method.setObject( @@ -292,6 +292,7 @@ class Mappers { case STPPaymentMethodType.USBankAccount: return "USBankAccount" case STPPaymentMethodType.payPal: return "PayPal" case STPPaymentMethodType.affirm: return "Affirm" + case STPPaymentMethodType.cashApp: return "CashApp" case STPPaymentMethodType.unknown: return "Unknown" default: return "Unknown" } @@ -322,6 +323,7 @@ class Mappers { case "USBankAccount": return STPPaymentMethodType.USBankAccount case "PayPal": return STPPaymentMethodType.payPal case "Affirm": return STPPaymentMethodType.affirm + case "CashApp": return STPPaymentMethodType.cashApp default: return STPPaymentMethodType.unknown } } @@ -610,8 +612,11 @@ class Mappers { "last4": paymentMethod.card?.last4 ?? NSNull(), "preferredNetwork": paymentMethod.card?.networks?.preferred ?? NSNull(), "availableNetworks": paymentMethod.card?.networks?.available ?? NSNull(), + "threeDSecureUsage": [ + "isSupported": paymentMethod.card?.threeDSecureUsage?.supported ?? false + ], ] - + let sepaDebit: NSDictionary = [ "bankCode": paymentMethod.sepaDebit?.bankCode ?? NSNull(), "country": paymentMethod.sepaDebit?.country ?? NSNull(), @@ -948,7 +953,7 @@ class Mappers { } return nil } - + class func convertDateToUnixTimestampSeconds(date: Date?) -> String? { if let date = date { let value = date.timeIntervalSince1970 diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentMethodFactory.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentMethodFactory.swift index 32c1d3e4afd3d..dcad5ddb3475c 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentMethodFactory.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentMethodFactory.swift @@ -55,6 +55,8 @@ class PaymentMethodFactory { return try createPayPalPaymentMethodParams() case STPPaymentMethodType.affirm: return try createAffirmPaymentMethodParams() + case STPPaymentMethodType.cashApp: + return try createCashAppPaymentMethodParams() // case STPPaymentMethodType.weChatPay: // return try createWeChatPayPaymentMethodParams() default: @@ -106,6 +108,8 @@ class PaymentMethodFactory { return nil case STPPaymentMethodType.affirm: return nil + case STPPaymentMethodType.cashApp: + return nil default: throw PaymentMethodError.paymentNotSupported } @@ -369,6 +373,26 @@ class PaymentMethodFactory { let params = STPPaymentMethodAffirmParams() return STPPaymentMethodParams(affirm: params, metadata: nil) } + + private func createCashAppPaymentMethodParams() throws -> STPPaymentMethodParams { + let params = STPPaymentMethodCashAppParams() + return STPPaymentMethodParams(cashApp: params, billingDetails: billingDetailsParams, metadata: nil) + } + + func createMandateData() -> STPMandateDataParams? { + if let mandateParams = paymentMethodData?["mandateData"] as? NSDictionary { + if let customerAcceptanceParams = mandateParams["customerAcceptance"] as? NSDictionary { + let mandate = STPMandateDataParams.init(customerAcceptance: STPMandateCustomerAcceptanceParams.init()) + + mandate.customerAcceptance.type = .online + if let onlineParams = customerAcceptanceParams["online"] as? NSDictionary { + mandate.customerAcceptance.onlineParams = .init(ipAddress: onlineParams["ipAddress"] as? String ?? "", userAgent: onlineParams["userAgent"] as? String ?? "") + } + return mandate + } + } + return nil + } } enum PaymentMethodError: Error { diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentPassFinder.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentPassFinder.swift index ff3c4b2930154..9cd952e54f480 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentPassFinder.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/PaymentPassFinder.swift @@ -13,14 +13,18 @@ internal class PaymentPassFinder: NSObject { case PAIRED_DEVICE } - class func findPassWithLast4(last4: String, hasPairedAppleWatch: Bool, completion: @escaping ((Bool, [PassLocation]) -> Void)) { + class func findPassWith( + primaryAccountIdentifier: String, + hasPairedAppleWatch: Bool, + completion: @escaping ((Bool, [PassLocation]) -> Void) + ) { let existingPassOnDevice: PKPass? = { if #available(iOS 13.4, *) { return PKPassLibrary().passes(of: PKPassType.secureElement) - .first(where: { $0.secureElementPass?.primaryAccountNumberSuffix == last4 && $0.secureElementPass?.passActivationState != .deactivated && !$0.isRemotePass }) + .first(where: { $0.secureElementPass?.primaryAccountIdentifier == primaryAccountIdentifier && $0.secureElementPass?.passActivationState != .deactivated && !$0.isRemotePass }) } else { return PKPassLibrary().passes(of: PKPassType.payment) - .first(where: { $0.paymentPass?.primaryAccountNumberSuffix == last4 && $0.paymentPass?.passActivationState != .deactivated && !$0.isRemotePass }) + .first(where: { $0.paymentPass?.primaryAccountIdentifier == primaryAccountIdentifier && $0.paymentPass?.passActivationState != .deactivated && !$0.isRemotePass }) } }() @@ -41,10 +45,10 @@ internal class PaymentPassFinder: NSObject { let existingPassOnPairedDevices: PKPass? = { if #available(iOS 13.4, *) { return PKPassLibrary().remoteSecureElementPasses - .first(where: { $0.secureElementPass?.primaryAccountNumberSuffix == last4 && $0.secureElementPass?.passActivationState != .deactivated }) + .first(where: { $0.secureElementPass?.primaryAccountIdentifier == primaryAccountIdentifier && $0.secureElementPass?.passActivationState != .deactivated }) } else { return PKPassLibrary().remotePaymentPasses() - .first(where: { $0.paymentPass?.primaryAccountNumberSuffix == last4 && $0.paymentPass?.passActivationState != .deactivated }) + .first(where: { $0.paymentPass?.primaryAccountIdentifier == primaryAccountIdentifier && $0.paymentPass?.passActivationState != .deactivated }) } }() diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk+PaymentSheet.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk+PaymentSheet.swift new file mode 100644 index 0000000000000..bf43585069f31 --- /dev/null +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk+PaymentSheet.swift @@ -0,0 +1,201 @@ +// +// StripeSdk+PaymentSheet.swift +// stripe-react-native +// +// Created by Charles Cruzan on 1/6/23. +// + +import Foundation +import StripePaymentSheet + +extension StripeSdk { + internal func buildPaymentSheetConfiguration(params: NSDictionary, orderTrackingCallback: RCTResponseSenderBlock? = nil) -> (error: NSDictionary?, configuration: PaymentSheet.Configuration?) { + var configuration = PaymentSheet.Configuration() + + configuration.primaryButtonLabel = params["primaryButtonLabel"] as? String + + if let appearanceParams = params["appearance"] as? NSDictionary { + do { + configuration.appearance = try PaymentSheetAppearance.buildAppearanceFromParams(userParams: appearanceParams) + } catch { + return(error: Errors.createError(ErrorType.Failed, error.localizedDescription), configuration: nil) + } + } + + if let applePayParams = params["applePay"] as? NSDictionary { + do { + configuration.applePay = try ApplePayUtils.buildPaymentSheetApplePayConfig( + merchantIdentifier: self.merchantIdentifier, + merchantCountryCode: applePayParams["merchantCountryCode"] as? String, + paymentSummaryItems: applePayParams["cartItems"] as? [[String : Any]], + buttonType: applePayParams["buttonType"] as? NSNumber, + customHandlers: buildCustomerHandlersForPaymentSheet(applePayParams: applePayParams, orderTrackingCallback: orderTrackingCallback) + ) + } catch { + return(error: Errors.createError(ErrorType.Failed, error.localizedDescription), configuration: nil) + } + } + + if let merchantDisplayName = params["merchantDisplayName"] as? String { + configuration.merchantDisplayName = merchantDisplayName + } + + if let returnURL = params["returnURL"] as? String { + configuration.returnURL = returnURL + } + + if let allowsDelayedPaymentMethods = params["allowsDelayedPaymentMethods"] as? Bool { + configuration.allowsDelayedPaymentMethods = allowsDelayedPaymentMethods + } + + if let billingConfigParams = params["billingDetailsCollectionConfiguration"] as? [String: Any?] { + configuration.billingDetailsCollectionConfiguration.name = StripeSdk.mapToCollectionMode(str: billingConfigParams["name"] as? String) + configuration.billingDetailsCollectionConfiguration.phone = StripeSdk.mapToCollectionMode(str: billingConfigParams["phone"] as? String) + configuration.billingDetailsCollectionConfiguration.email = StripeSdk.mapToCollectionMode(str: billingConfigParams["email"] as? String) + configuration.billingDetailsCollectionConfiguration.address = StripeSdk.mapToAddressCollectionMode(str: billingConfigParams["address"] as? String) + configuration.billingDetailsCollectionConfiguration.attachDefaultsToPaymentMethod = billingConfigParams["attachDefaultsToPaymentMethod"] as? Bool == true + } + + if let defaultBillingDetails = params["defaultBillingDetails"] as? [String: Any?] { + configuration.defaultBillingDetails.name = defaultBillingDetails["name"] as? String + configuration.defaultBillingDetails.email = defaultBillingDetails["email"] as? String + configuration.defaultBillingDetails.phone = defaultBillingDetails["phone"] as? String + + if let address = defaultBillingDetails["address"] as? [String: String] { + configuration.defaultBillingDetails.address = .init(city: address["city"], + country: address["country"], + line1: address["line1"], + line2: address["line2"], + postalCode: address["postalCode"], + state: address["state"]) + } + + } + + if let defaultShippingDetails = params["defaultShippingDetails"] as? NSDictionary { + configuration.shippingDetails = { + return AddressSheetUtils.buildAddressDetails(params: defaultShippingDetails) + } + } + + if #available(iOS 13.0, *) { + if let style = params["style"] as? String { + configuration.style = Mappers.mapToUserInterfaceStyle(style) + } + } + + if let customerId = params["customerId"] as? String { + if let customerEphemeralKeySecret = params["customerEphemeralKeySecret"] as? String { + if (!Errors.isEKClientSecretValid(clientSecret: customerEphemeralKeySecret)) { + return(error: Errors.createError(ErrorType.Failed, "`customerEphemeralKeySecret` format does not match expected client secret formatting."), configuration: nil) + } + configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret) + } + } + + return (nil, configuration) + } + + internal func preparePaymentSheetInstance(params: NSDictionary, configuration: PaymentSheet.Configuration, resolve: @escaping RCTPromiseResolveBlock) { + + func handlePaymentSheetFlowControllerResult(result: Result, stripeSdk: StripeSdk?) { + switch result { + case .failure(let error): + resolve(Errors.createError(ErrorType.Failed, error as NSError)) + case .success(let paymentSheetFlowController): + self.paymentSheetFlowController = paymentSheetFlowController + var result: NSDictionary? = nil + if let paymentOption = stripeSdk?.paymentSheetFlowController?.paymentOption { + result = [ + "label": paymentOption.label, + "image": paymentOption.image.pngData()?.base64EncodedString() ?? "" + ] + } + resolve(Mappers.createResult("paymentOption", result)) + } + } + + if let paymentIntentClientSecret = params["paymentIntentClientSecret"] as? String { + if (!Errors.isPIClientSecretValid(clientSecret: paymentIntentClientSecret)) { + resolve(Errors.createError(ErrorType.Failed, "`secret` format does not match expected client secret formatting.")) + return + } + + if params["customFlow"] as? Bool == true { + PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, + configuration: configuration) { [weak self] result in + handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self) + } + } else { + self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) + resolve([]) + } + } else if let setupIntentClientSecret = params["setupIntentClientSecret"] as? String { + if (!Errors.isSetiClientSecretValid(clientSecret: setupIntentClientSecret)) { + resolve(Errors.createError(ErrorType.Failed, "`secret` format does not match expected client secret formatting.")) + return + } + + if params["customFlow"] as? Bool == true { + PaymentSheet.FlowController.create(setupIntentClientSecret: setupIntentClientSecret, + configuration: configuration) { [weak self] result in + handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self) + } + } else { + self.paymentSheet = PaymentSheet(setupIntentClientSecret: setupIntentClientSecret, configuration: configuration) + resolve([]) + } + } else { + resolve(Errors.createError(ErrorType.Failed, "You must provide either paymentIntentClientSecret or setupIntentClientSecret")) + } + } + + private func buildCustomerHandlersForPaymentSheet(applePayParams: NSDictionary, orderTrackingCallback: RCTResponseSenderBlock?) -> PaymentSheet.ApplePayConfiguration.Handlers? { + if (applePayParams["request"] == nil && orderTrackingCallback == nil) { + return nil + } + return PaymentSheet.ApplePayConfiguration.Handlers(paymentRequestHandler: { request in + do { + try request.configureRequestType(requestParams: applePayParams) + } catch { + // At this point, we can't resolve a promise with an error object, so our best option is to create a redbox error + RCTMakeAndLogError(error.localizedDescription, nil, nil) + } + return request + }, authorizationResultHandler: { result, completion in + if let orderTrackingCallback = orderTrackingCallback { + self.orderTrackingHandler = (result, completion) + orderTrackingCallback(nil) + } else { + completion(result) + } + }) + } + + private static func mapToCollectionMode(str: String?) -> PaymentSheet.BillingDetailsCollectionConfiguration.CollectionMode { + switch str { + case "automatic": + return .automatic + case "never": + return .never + case "always": + return .always + default: + return .automatic + } + } + + private static func mapToAddressCollectionMode(str: String?) -> PaymentSheet.BillingDetailsCollectionConfiguration.AddressCollectionMode { + switch str { + case "automatic": + return .automatic + case "never": + return .never + case "full": + return .full + default: + return .automatic + } + } +} + diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk-Bridging-Header.h b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk-Bridging-Header.h index 7d39914a84102..f1795e19ec4e8 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk-Bridging-Header.h +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk-Bridging-Header.h @@ -1,6 +1,7 @@ #import #import #import +#import #import #import #import diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.m b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.m index a4780ed4240c4..0bf02417c0cb0 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.m +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.m @@ -113,7 +113,15 @@ @interface RCT_EXTERN_MODULE(StripeSdk, RCTEventEmitter) ) RCT_EXTERN_METHOD( - presentPaymentSheet:(RCTPromiseResolveBlock)resolve + initPaymentSheetWithOrderTracking:(NSDictionary *)params + callback:(RCTResponseSenderBlock)orderTrackingCallback + resolver: (RCTPromiseResolveBlock)resolve + rejecter: (RCTPromiseRejectBlock)reject + ) + +RCT_EXTERN_METHOD( + presentPaymentSheet:(NSDictionary *)options + resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) @@ -177,4 +185,12 @@ @interface RCT_EXTERN_MODULE(StripeSdk, RCTEventEmitter) resolver: (RCTPromiseResolveBlock)resolve rejecter: (RCTPromiseRejectBlock)reject ) +RCT_EXTERN_METHOD( + configureOrderTracking:(NSString *)orderTypeIdentifier + orderIdentifier:(NSString *)orderIdentifier + webServiceUrl:(NSString *)webServiceUrl + authenticationToken:(NSString *)authenticationToken + resolver: (RCTPromiseResolveBlock)resolve + rejecter: (RCTPromiseRejectBlock)reject + ) @end diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.swift index 68eb53b409b95..90cd5c130662e 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/StripeSdk.swift @@ -10,8 +10,8 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap var merchantIdentifier: String? = nil - private var paymentSheet: PaymentSheet? - private var paymentSheetFlowController: PaymentSheet.FlowController? + internal var paymentSheet: PaymentSheet? + internal var paymentSheetFlowController: PaymentSheet.FlowController? var urlScheme: String? = nil @@ -42,9 +42,11 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap set { _couponCodeUpdateCompletion = newValue } } private var _couponCodeUpdateCompletion: Any? = nil + var orderTrackingHandler: (result: PKPaymentAuthorizationResult, handler: ((PKPaymentAuthorizationResult) -> Void))? = nil var shippingMethodUpdateJSCallback: RCTDirectEventBlock? = nil var shippingContactUpdateJSCallback: RCTDirectEventBlock? = nil var couponCodeEnteredJSCallback: RCTDirectEventBlock? = nil + var platformPayOrderTrackingJSCallback: RCTDirectEventBlock? = nil var applePaySummaryItems: [PKPaymentSummaryItem] = [] var applePayShippingMethods: [PKShippingMethod] = [] var applePayShippingAddressErrors: [Error]? = nil @@ -59,7 +61,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap } override func supportedEvents() -> [String]! { - return ["onDidSetShippingMethod", "onDidSetShippingContact"] + return ["onDidSetShippingMethod", "onDidSetShippingContact", "onDidSetCouponCode"] } @objc override static func requiresMainQueueSetup() -> Bool { @@ -107,134 +109,27 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap @objc(initPaymentSheet:resolver:rejecter:) func initPaymentSheet(params: NSDictionary, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void { - var configuration = PaymentSheet.Configuration() self.paymentSheetFlowController = nil - configuration.primaryButtonLabel = params["primaryButtonLabel"] as? String - - if let appearanceParams = params["appearance"] as? NSDictionary { - do { - configuration.appearance = try PaymentSheetAppearance.buildAppearanceFromParams(userParams: appearanceParams) - } catch { - resolve(Errors.createError(ErrorType.Failed, error.localizedDescription)) - return - } - } - - if let applePayParams = params["applePay"] as? NSDictionary { - do { - configuration.applePay = try ApplePayUtils.buildPaymentSheetApplePayConfig( - merchantIdentifier: self.merchantIdentifier, - merchantCountryCode: applePayParams["merchantCountryCode"] as? String, - paymentSummaryItems: applePayParams["paymentSummaryItems"] as? [[String : Any]] - ) - } catch { - resolve(Errors.createError(ErrorType.Failed, error.localizedDescription)) - return - } - } - - if let merchantDisplayName = params["merchantDisplayName"] as? String { - configuration.merchantDisplayName = merchantDisplayName - } - - if let returnURL = params["returnURL"] as? String { - configuration.returnURL = returnURL - } - - if let allowsDelayedPaymentMethods = params["allowsDelayedPaymentMethods"] as? Bool { - configuration.allowsDelayedPaymentMethods = allowsDelayedPaymentMethods - } - - if let defaultBillingDetails = params["defaultBillingDetails"] as? [String: Any?] { - configuration.defaultBillingDetails.name = defaultBillingDetails["name"] as? String - configuration.defaultBillingDetails.email = defaultBillingDetails["email"] as? String - configuration.defaultBillingDetails.phone = defaultBillingDetails["phone"] as? String - - if let address = defaultBillingDetails["address"] as? [String: String] { - configuration.defaultBillingDetails.address = .init(city: address["city"], - country: address["country"], - line1: address["line1"], - line2: address["line2"], - postalCode: address["postalCode"], - state: address["state"]) - } - + let (error, configuration) = buildPaymentSheetConfiguration(params: params) + guard let configuration = configuration else { + resolve(error) + return } - if let defaultShippingDetails = params["defaultShippingDetails"] as? NSDictionary { - configuration.shippingDetails = { - return AddressSheetUtils.buildAddressDetails(params: defaultShippingDetails) - } - } - - if let customerId = params["customerId"] as? String { - if let customerEphemeralKeySecret = params["customerEphemeralKeySecret"] as? String { - if (!Errors.isEKClientSecretValid(clientSecret: customerEphemeralKeySecret)) { - resolve(Errors.createError(ErrorType.Failed, "`customerEphemeralKeySecret` format does not match expected client secret formatting.")) - return - } - configuration.customer = .init(id: customerId, ephemeralKeySecret: customerEphemeralKeySecret) - } - } - - if #available(iOS 13.0, *) { - if let style = params["style"] as? String { - configuration.style = Mappers.mapToUserInterfaceStyle(style) - } - } - - func handlePaymentSheetFlowControllerResult(result: Result, stripeSdk: StripeSdk?) { - switch result { - case .failure(let error): - resolve(Errors.createError(ErrorType.Failed, error as NSError)) - case .success(let paymentSheetFlowController): - self.paymentSheetFlowController = paymentSheetFlowController - var result: NSDictionary? = nil - if let paymentOption = stripeSdk?.paymentSheetFlowController?.paymentOption { - result = [ - "label": paymentOption.label, - "image": paymentOption.image.pngData()?.base64EncodedString() ?? "" - ] - } - resolve(Mappers.createResult("paymentOption", result)) - } - } - - if let paymentIntentClientSecret = params["paymentIntentClientSecret"] as? String { - if (!Errors.isPIClientSecretValid(clientSecret: paymentIntentClientSecret)) { - resolve(Errors.createError(ErrorType.Failed, "`secret` format does not match expected client secret formatting.")) - return - } - - if params["customFlow"] as? Bool == true { - PaymentSheet.FlowController.create(paymentIntentClientSecret: paymentIntentClientSecret, - configuration: configuration) { [weak self] result in - handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self) - } - } else { - self.paymentSheet = PaymentSheet(paymentIntentClientSecret: paymentIntentClientSecret, configuration: configuration) - resolve([]) - } - } else if let setupIntentClientSecret = params["setupIntentClientSecret"] as? String { - if (!Errors.isSetiClientSecretValid(clientSecret: setupIntentClientSecret)) { - resolve(Errors.createError(ErrorType.Failed, "`secret` format does not match expected client secret formatting.")) - return - } - - if params["customFlow"] as? Bool == true { - PaymentSheet.FlowController.create(setupIntentClientSecret: setupIntentClientSecret, - configuration: configuration) { [weak self] result in - handlePaymentSheetFlowControllerResult(result: result, stripeSdk: self) - } - } else { - self.paymentSheet = PaymentSheet(setupIntentClientSecret: setupIntentClientSecret, configuration: configuration) - resolve([]) - } - } else { - resolve(Errors.createError(ErrorType.Failed, "You must provide either paymentIntentClientSecret or setupIntentClientSecret")) + preparePaymentSheetInstance(params: params, configuration: configuration, resolve: resolve) + } + + @objc(initPaymentSheetWithOrderTracking:callback:resolver:rejecter:) + func initPaymentSheetWithOrderTracking(params: NSDictionary, callback orderTrackingCallback: @escaping RCTResponseSenderBlock, resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock) -> Void { + let (error, configuration) = buildPaymentSheetConfiguration(params: params, orderTrackingCallback: orderTrackingCallback) + guard let configuration = configuration else { + resolve(error) + return } - + + preparePaymentSheetInstance(params: params, configuration: configuration, resolve: resolve) } @objc(confirmPaymentSheetPayment:rejecter:) @@ -267,15 +162,26 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap resolve(nil) } - @objc(presentPaymentSheet:rejecter:) - func presentPaymentSheet(resolver resolve: @escaping RCTPromiseResolveBlock, + @objc(presentPaymentSheet:resolver:rejecter:) + func presentPaymentSheet(options: NSDictionary, + resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) -> Void { - + var paymentSheetViewController: UIViewController? + + if let timeout = options["timeout"] as? Double { + DispatchQueue.main.asyncAfter(deadline: .now() + timeout/1000) { + if let paymentSheetViewController = paymentSheetViewController { + paymentSheetViewController.dismiss(animated: true) + resolve(Errors.createError(ErrorType.Timeout, "The payment has timed out.")) + } + } + } DispatchQueue.main.async { + paymentSheetViewController = UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController() if let paymentSheetFlowController = self.paymentSheetFlowController { - paymentSheetFlowController.presentPaymentOptions(from: - findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController()) + paymentSheetFlowController.presentPaymentOptions(from: findViewControllerPresenter(from: paymentSheetViewController!) ) { + paymentSheetViewController = nil if let paymentOption = self.paymentSheetFlowController?.paymentOption { let option: NSDictionary = [ "label": paymentOption.label, @@ -287,9 +193,9 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap } } } else if let paymentSheet = self.paymentSheet { - paymentSheet.present(from: - findViewControllerPresenter(from: UIApplication.shared.delegate?.window??.rootViewController ?? UIViewController()) + paymentSheet.present(from: findViewControllerPresenter(from: paymentSheetViewController!) ) { paymentResult in + paymentSheetViewController = nil switch paymentResult { case .completed: resolve([]) @@ -301,7 +207,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap } } } else { - resolve(Errors.createError(ErrorType.Failed, "No payment sheet has been initialized yet")) + resolve(Errors.createError(ErrorType.Failed, "No payment sheet has been initialized yet. You must call `initPaymentSheet` before `presentPaymentSheet`.")) } } } @@ -334,11 +240,6 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap return } - if (paymentMethodType == .payPal) { - resolve(Errors.createError(ErrorType.Failed, "PayPal is not yet supported through SetupIntents.")) - return - } - var err: NSDictionary? = nil let setupIntentParams: STPSetupIntentConfirmParams = { // If payment method data is not supplied, assume payment method was attached through via collectBankAccount @@ -354,6 +255,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap do { let paymentMethodParams = try factory.createParams(paymentMethodType: paymentMethodType) parameters.paymentMethodParams = paymentMethodParams + parameters.mandateData = factory.createMandateData() } catch { err = Errors.createError(ErrorType.Failed, error as NSError?) } @@ -603,6 +505,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap self.applePayShippingMethods = paymentRequest.shippingMethods ?? [] self.applePayShippingAddressErrors = nil self.applePayCouponCodeErrors = nil + self.orderTrackingHandler = nil self.confirmApplePayResolver = resolve if (isPaymentIntent) { self.confirmApplePayPaymentClientSecret = clientSecret @@ -974,6 +877,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap let paymentMethodOptions = try factory.createOptions(paymentMethodType: paymentMethodType) parameters.paymentMethodParams = paymentMethodParams parameters.paymentMethodOptions = paymentMethodOptions + parameters.mandateData = factory.createMandateData() } catch { err = Errors.createError(ErrorType.Failed, error as NSError?) } @@ -1115,12 +1019,7 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock ) -> Void { - guard let last4 = params["cardLastFour"] as? String else { - resolve(Errors.createError(ErrorType.Failed, "You must provide `cardLastFour`")) - return - } PushProvisioningUtils.canAddCardToWallet( - last4: last4, primaryAccountIdentifier: params["primaryAccountIdentifier"] as? String ?? "", testEnv: params["testEnv"] as? Bool ?? false, hasPairedAppleWatch: params["hasPairedAppleWatch"] as? Bool ?? false) @@ -1182,6 +1081,32 @@ class StripeSdk: RCTEventEmitter, STPBankSelectionViewControllerDelegate, UIAdap } FinancialConnections.present(withClientSecret: clientSecret, returnURL: returnURL, resolve: resolve) } + + @objc(configureOrderTracking:orderIdentifier:webServiceUrl:authenticationToken:resolver:rejecter:) + func configureOrderTracking( + orderTypeIdentifier: String, + orderIdentifier: String, + webServiceUrl: String, + authenticationToken: String, + resolver resolve: @escaping RCTPromiseResolveBlock, + rejecter reject: @escaping RCTPromiseRejectBlock + ) { +#if compiler(>=5.7) + if #available(iOS 16.0, *) { + if let orderTrackingHandler = self.orderTrackingHandler { + if let url = URL(string: webServiceUrl) { + orderTrackingHandler.result.orderDetails = PKPaymentOrderDetails( + orderTypeIdentifier: orderTypeIdentifier, + orderIdentifier: orderIdentifier, + webServiceURL: url, + authenticationToken: authenticationToken) + } + orderTrackingHandler.handler(orderTrackingHandler.result) + self.orderTrackingHandler = nil + } + } +#endif + } func presentationControllerDidDismiss(_ presentationController: UIPresentationController) { confirmPaymentResolver?(Errors.createError(ErrorType.Canceled, "FPX Payment has been canceled")) diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/AddToWalletButtonView.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/AddToWalletButtonView.swift index c48adbbf71647..67624545b9e44 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/AddToWalletButtonView.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/AddToWalletButtonView.swift @@ -39,7 +39,7 @@ class AddToWalletButtonView: UIView { } @objc func beginPushProvisioning() { - if (!PushProvisioningUtils.canAddPaymentPass(primaryAccountIdentifier: cardDetails?["primaryAccountIdentifier"] as? String ?? "", isTestMode: self.testEnv)) { + if (!PushProvisioningUtils.canAddPaymentPass(isTestMode: self.testEnv)) { onCompleteAction!( Errors.createError( ErrorType.Failed, diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/PushProvisioningUtils.swift b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/PushProvisioningUtils.swift index 02efc8db67539..866b8e4408adb 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/PushProvisioningUtils.swift +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/ios/pushprovisioning/PushProvisioningUtils.swift @@ -10,24 +10,18 @@ import Stripe internal class PushProvisioningUtils { class func canAddCardToWallet( - last4: String, primaryAccountIdentifier: String, testEnv: Bool, hasPairedAppleWatch: Bool, completion: @escaping (_ canAddCard: Bool, _ status: AddCardToWalletStatus?) -> Void ) { - if (!PKAddPassesViewController.canAddPasses()) { + if (!canAddPaymentPass(isTestMode: testEnv)) { completion(false, AddCardToWalletStatus.UNSUPPORTED_DEVICE) - } - - let canAddCard = canAddPaymentPass( - primaryAccountIdentifier: primaryAccountIdentifier, - isTestMode: testEnv) - - if (!canAddCard) { - completion(canAddCard, AddCardToWalletStatus.MISSING_CONFIGURATION) } else { - PaymentPassFinder.findPassWithLast4(last4: last4, hasPairedAppleWatch: hasPairedAppleWatch) { canAddCardToADevice, passLocations in + PaymentPassFinder.findPassWith( + primaryAccountIdentifier: primaryAccountIdentifier, + hasPairedAppleWatch: hasPairedAppleWatch) + { canAddCardToADevice, passLocations in var status: AddCardToWalletStatus? = nil if (!canAddCardToADevice) { status = AddCardToWalletStatus.CARD_ALREADY_EXISTS @@ -41,16 +35,12 @@ internal class PushProvisioningUtils { } } - class func canAddPaymentPass(primaryAccountIdentifier: String, isTestMode: Bool) -> Bool { + class func canAddPaymentPass(isTestMode: Bool) -> Bool { if (isTestMode) { return STPFakeAddPaymentPassViewController.canAddPaymentPass() } - - if #available(iOS 13.4, *) { - return PKPassLibrary().canAddSecureElementPass(primaryAccountIdentifier: primaryAccountIdentifier) - } else { - return PKAddPaymentPassViewController.canAddPaymentPass() - } + + return PKAddPaymentPassViewController.canAddPaymentPass() } class func getPassLocation(last4: String) -> PaymentPassFinder.PassLocation? { @@ -79,7 +69,6 @@ internal class PushProvisioningUtils { enum AddCardToWalletStatus: String { case UNSUPPORTED_DEVICE - case MISSING_CONFIGURATION case CARD_ALREADY_EXISTS case CARD_EXISTS_ON_CURRENT_DEVICE case CARD_EXISTS_ON_PAIRED_DEVICE diff --git a/ios/vendored/unversioned/@stripe/stripe-react-native/stripe-react-native.podspec.json b/ios/vendored/unversioned/@stripe/stripe-react-native/stripe-react-native.podspec.json index 0b80275ed623a..45823922dedfe 100644 --- a/ios/vendored/unversioned/@stripe/stripe-react-native/stripe-react-native.podspec.json +++ b/ios/vendored/unversioned/@stripe/stripe-react-native/stripe-react-native.podspec.json @@ -1,6 +1,6 @@ { "name": "stripe-react-native", - "version": "0.23.3", + "version": "0.27.2", "summary": "Stripe SDK for React Native", "homepage": "https://github.com/stripe/stripe-react-native/#readme", "license": "MIT", @@ -10,29 +10,29 @@ }, "source": { "git": "https://github.com/stripe/stripe-react-native.git", - "tag": "0.23.3" + "tag": "0.27.2" }, "source_files": "ios/**/*.{h,m,mm,swift}", "exclude_files": "ios/Tests/", "dependencies": { "React-Core": [], "Stripe": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentSheet": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePayments": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripePaymentsUI": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeApplePay": [ - "~> 23.3.0" + "~> 23.8.0" ], "StripeFinancialConnections": [ - "~> 23.3.0" + "~> 23.8.0" ] }, "testspecs": [ diff --git a/packages/expo/bundledNativeModules.json b/packages/expo/bundledNativeModules.json index 384f817a53501..f9c1c37efac2c 100644 --- a/packages/expo/bundledNativeModules.json +++ b/packages/expo/bundledNativeModules.json @@ -8,7 +8,7 @@ "@react-native-community/viewpager": "5.0.11", "@react-native-picker/picker": "2.4.8", "@react-native-segmented-control/segmented-control": "2.4.0", - "@stripe/stripe-react-native": "0.23.3", + "@stripe/stripe-react-native": "0.27.2", "expo-analytics-amplitude": "~11.3.0", "expo-app-auth": "~11.1.0", "expo-app-loader-provider": "~8.0.0",