Troubleshooting

The plugin is crashing with a PlatformException on Android, on iOS it is working fine

Unfortunately configuring Android is a bit more work and if you do not match the following requirements. You can run into some issues.

Android 5.0 (API level 21) and above

You need to make sure the minSdk in the build.gradle is specifified to 21 or above.

groovy
defaultConfig {
        applicationId "com.your.application"
        minSdkVersion 21
        targetSdkVersion 31

Kotlin version must be at least 1.8.0

Our plugin consists of Kotlin code and if you run an outdated version of Kotlin make sure you upgrade the version in your application's build.gradle file:

groovy
buildscript {
    ext.kotlin_version = '1.8.0'
    repositories {
        google()
        jcenter()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

Gradle tools must be up to date

Out of date Gradle dependencies can yield to weird build results and the App not to compile. Check that you are using the same version (or higher) as specifified in the example app.

Use FlutterFragmentActivity instead of FluterActivity as MainActivity

The Stripe sdk requires a FlutterFragmentActivity instead of the FlutterActivity that is standard specifified when creating a new Flutter project. Follow the following steps to change it:

  1. Create a MainActivity kotlin file (if it doesn’t exist) in the Android folder of your Flutter app. See the snippet below and our example app.
kotlin
package com.flutter.stripe.example

import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.android.FlutterFragmentActivity

class MainActivity: FlutterFragmentActivity() {
}
  1. Refer to the newly created activity in the AndroidManifest.
xml
<application
        android:label="example"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTop"

Using a descendant of Theme.AppCompat for your activity.

In order to properly style the components you need to create a theme for the MainActivity that is a descendant of Theme.AppCompat or Theme.MaterialComponents.

xml
&lt;?xml version="1.0" encoding="utf-8"?>
<resources>
    
    <style name="LaunchTheme" parent="Theme.AppCompat.Light.NoActionBar">
        
        <item name="android:windowBackground">@drawable/launch_background</item>
    </style>
    
    <style name="NormalTheme" parent="Theme.MaterialComponents">
        <item name="android:windowBackground">?android:colorBackground</item>
    </style>
</resources>

See also our example theme, example night theme.

The payment sheet doesn't open in production but it works on test.

Normally when you start developing your Stripe integration you are using test keys on both your Server and Client. When it is time to go to production you need to replace these keys with production ones. Learn more about Stripe api keys here. If both client and server are using keys from different environments the payment intent cannot be handled by the client. That is why the payment sheet will not open. In order to solve this issue make sure the following is in sync:

Server-side

  • Publishable key needs to be a production key
  • Secret key needs to be a production key

You can check if your backend is communicating with the live environment at the Stripe dashboard. Go to payments -> select a payment and check if liveMode is set to true.

json
{
  "id": "pi_1234345",
  "object": "payment_intent",
  "last_payment_error": null,
  "livemode": true,
  "next_action": null,
  "status": "succeeded",
}

Client side

  • Make sure that on the client the production publishable key is provided.
dart
Stripe.publishableKey = stripeProductionPublishableKey;
await Stripe.instance.applySettings();
  • On initializing the payment sheet make sure that isTestEnv is set to false.
dart
await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
          ...
          testEnv: false,
          ...
        ),
      );

The stored cards are not being displayed on the payment_sheet

On the payment sheet it is possible for the customer to save a card so it can be re-used again without the need for entering the card details again. For an elaborate description about this flow check the stripe docs.

This is an image

When the customer marked save card for further use and it is not shown next time, make sure to check the following:

Server-side

The payment intent should be linked to a customer and for the customer an ephemeralKey should be created. You can check if this is the case for your integration by opening the: Stripe dashboard, go to payments-> select the payment and make sure it is linked to a customer.

json
{
  "id": "pi_12345",
  "object": "payment_intent",
  "charges": {
    "object": "list",
    "data": [
      {
        "id": "ch_1234",
        "customer": "cus_12345",
      }
    ]
  },
  }

Client-side

  • When you communicate with your backend you should make sure that you receive both the customerId + ephemeralKey from the backend. If this is not the case checkout the [stripe docs]server implementation on creating a customer + key.
  • Provide the customer and ephemeralKey to the SetupPaymentSheetParameters when initializing the PaymentSheet.
dart
 await Stripe.instance.initPaymentSheet(
        paymentSheetParameters: SetupPaymentSheetParameters(
          // Main params
          paymentIntentClientSecret: data['paymentIntent'],
          merchantDisplayName: 'Flutter Stripe Store Demo',
          // Customer params
          customerId: data['customer'],
          customerEphemeralKeySecret: data['ephemeralKey'],
          // Extra params

Android compile issue app bundle

When you get this issue when building android app bundle.

bash
Missing class com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Args (referenced from: void com.reactnativestripesdk.pushprovisioning.DefaultPushProvisioningProxy.beginPushProvisioning(android.app.Activity, java.lang.String, com.reactnativestripesdk.pushprovisioning.EphemeralKeyProvider))
Missing class com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Error (referenced from: void com.reactnativestripesdk.pushprovisioning.PushProvisioningProxy$createActivityEventListener$listener$1.onActivityResult(android.app.Activity, int, int, android.content.Intent))
Missing class com.stripe.android.pushProvisioning.PushProvisioningActivityStarter (referenced from: void com.reactnativestripesdk.pushprovisioning.DefaultPushProvisioningProxy.beginPushProvisioning(android.app.Activity, java.lang.String, com.reactnativestripesdk.pushprovisioning.EphemeralKeyProvider))
Missing class com.stripe.android.pushProvisioning.PushProvisioningEphemeralKeyProvider (referenced from: void com.reactnativestripesdk.pushprovisioning.DefaultPushProvisioningProxy.beginPushProvisioning(android.app.Activity, java.lang.String, com.reactnativestripesdk.pushprovisioning.EphemeralKeyProvider) and 1 other context)

Add the following rules to your proguard-rules.pro file: example

proguard
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivity$g
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Args
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter$Error
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningActivityStarter
-dontwarn com.stripe.android.pushProvisioning.PushProvisioningEphemeralKeyProvider