stripe / stripe-react-native

React Native library for Stripe.
https://stripe.dev/stripe-react-native
MIT License
1.29k stars 263 forks source link

GooglePay - PaymentConfiguration was not initialized. #725

Closed AdamLee321 closed 2 years ago

AdamLee321 commented 3 years ago

Bug Description When running initGooglePay on Android the app immediately crashes and throws this error:

Screenshot 2021-11-17 at 16 14 51

To Reproduce Removing this block of code stops the app from crashing, so the issue lies here:

componentDidMount() {
  initGooglePay({
    testEnv: true,
    merchantName: 'Test App',
    countryCode: 'US',
  })
    .then(response => {
      console.log('response', response);
    })
    .catch(err => {
      console.log('error', error);
    });
}

Expected behavior This should return a response which will allow the app to render the google pay button.

Test Device:

Additional setup information: package.json: "@stripe/stripe-react-native": "^0.2.2", "react": "17.0.2", "react-native": "0.66.0",

app/build.gradle: implementation 'com.google.android.gms:play-services-wallet:18.1.3'

build.gradle: minSdkVersion = 21 compileSdkVersion = 30 targetSdkVersion = 30

If there is anything else I can provide to help identifying the issue let me know. If anyone knows a workaround could you post a fix please?

AdamLee321 commented 3 years ago

I found the issue and I am closing this as it has nothing to do with the library the issue was my app. I had code in build.gradle to use the exo player for playing video and had code which turned out was not needed.

// jcenter repository is deprecated: https://developer.android.com/studio/build/jcenter-migration
        //noinspection JcenterRepositoryObsolete
        jcenter() {
            content {
                // however, react-native-video's native packages have not been migrated yet, so we keep this config for now
                includeModule("com.yqritc", "android-scalablevideoview")
                includeModule("com.google.android.exoplayer", "extension-okhttp")
                includeModule("com.google.android.exoplayer", "exoplayer")
                includeModule("com.google.android.exoplayer", "exoplayer-core")
                includeModule("com.google.android.exoplayer", "exoplayer-dash")
                includeModule("com.google.android.exoplayer", "exoplayer-hls")
                includeModule("com.google.android.exoplayer", "exoplayer-smoothstreaming")
                includeModule("com.google.android.exoplayer", "exoplayer-ui")
                includeModule("com.google.android.exoplayer", "exoplayer-extractor")
                includeModule("com.google.android.exoplayer", "exoplayer-common")
                includeModule("com.google.android.exoplayer", "exoplayer-transformer")
            }
        }

Removing this fixed Google Pay. In case anyone has this very specific issue it might save you some time.

AdamLee321 commented 3 years ago

Reopening as it turns out the above did not fix the issue. Could anyone please help with this issue?

bill-pairaktaridis commented 3 years ago

Yeah, I'm having the same issue but not with all devices...

bill-pairaktaridis commented 3 years ago

It looks like we resolved this on our end.

I removed the implementation 'com.google.android.gms:play-services-wallet:18.1.3' line and replaced it with only implementation 'com.stripe:stripe-android:18.2.0'.

Give it a shot. It's been a weird bug because I couldn't replicate it locally.

AdamLee321 commented 3 years ago

Hey @bill-pairaktaridis, I will give it a shot and report back to you. Thanks for posting a solution.

UPDATE: Adding just implementation 'com.stripe:stripe-android:18.2.0' didn't resolve the issue for me, I also added PaymentConfiguration.init(this, PUBLISHABLE_KEY) to onCreate in MainApplication.java.

I don't think this is the solution to this issue but more of a workaround. I will leave this issue open for now but anyone that needs this fix right away can do this.

Rc85 commented 2 years ago

Also having the same issue with 0.2.3.

java.lang.IllegalStateException: PaymentConfiguration was not initialized. Call PaymentConfiguration.init().
    at com.stripe.android.PaymentConfiguration$Companion.loadInstance(PaymentConfiguration.kt:77)
    at com.stripe.android.PaymentConfiguration$Companion.getInstance(PaymentConfiguration.kt:69)
    at com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher.<init>(GooglePayPaymentMethodLauncher.kt:69)
    at com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher.<init>(GooglePayPaymentMethodLauncher.kt:170)
    at com.stripe.android.googlepaylauncher.GooglePayPaymentMethodLauncher.<init>(GooglePayPaymentMethodLauncher.kt:154)
    at com.reactnativestripesdk.GooglePayFragment.onViewCreated(GooglePayFragment.kt:62)
    at androidx.fragment.app.Fragment.performViewCreated(Fragment.java:2987)
    at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:546)
    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2189)
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2100)
    at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2002)
    at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:524)
    at android.os.Handler.handleCallback(Handler.java:883)
    at android.os.Handler.dispatchMessage(Handler.java:100)
    at android.os.Looper.loop(Looper.java:237)
    at android.app.ActivityThread.main(ActivityThread.java:8107)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:496)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1100)
rob5408 commented 1 year ago

Just dropping a note that this still crashes in 0.26.0.

I tried suggestions from this issue as well as the other two "PaymentConfiguration was not initialized" issues in this repo:

The crash would even still occur if I limited isPlatformPaySupported calls to iOS only.

As observed by others it was device specific. My Pixel 4 never experienced a crash, but my Nexus 5x would crash maybe 95% of the time. I ended up just "disabling" Google Pay in PaymentConfiguration.kt (see below). I know this isn't possible for most people, but we don't support Google Pay anyway and it was preventing us from releasing our latest version.

  @ReactMethod
  fun isPlatformPaySupported(params: ReadableMap?, promise: Promise) {
    promise.resolve("")
  }

Good luck y'all!

AkshayKrJha commented 1 year ago

With version 0.35.0 of stripe, and 0.72.6 of react-native, this bug was observed in my case too. What worked however was to hide the <PlatformPayButton/> , unless the promise isPlatformPaySupported() ,(with a timeout of 1s) resolves, and state variable updated thereafter, like

// for timeout

useEffect(() => {
        const t = setTimeout(() => {
            // this line errs, timeout fixes it
            isGPayAvailable().then(() => {
                clearTimeout(t)
            })
        }, 1000)
    }
        , [])

// part of the UI

<UI>
{!gPayDisabled && <PlatformPayButton
                {...otherProps}
                disabled={gPayDisabled}
            />}
</UI>
altick commented 2 months ago

I have experienced the same issue and solved it by replacing StripeProvider with a custom provider that stores the state of the initialization. So we know if the stripe is ready before we call the isPlatformPaySupported.

The problem: When StripeProvider initializes the SDK it doesn't await it neither provides a state of the initialization. https://github.com/stripe/stripe-react-native/blob/888c6cb31d7a00b362832e0566ac2d08890e5445/src/components/StripeProvider.tsx#L68

The solution:

    const { isPlatformPaySupported } = useStripe();
    const [isInitialized, setIsInitialized] = React.useState(false);

    useEffect(() => {
        initStripe({
            publishableKey: "...",
        }).then(() => setIsInitialized(true));
    }, []);

   if (isInitialized) {
       isPlatformPaySupported();
   }
minhnhut170701 commented 5 days ago

I have experienced the same issue and solved it by replacing StripeProvider with a custom provider that stores the state of the initialization. So we know if the stripe is ready before we call the isPlatformPaySupported.

The problem: When StripeProvider initializes the SDK it doesn't await it neither provides a state of the initialization.

https://github.com/stripe/stripe-react-native/blob/888c6cb31d7a00b362832e0566ac2d08890e5445/src/components/StripeProvider.tsx#L68

The solution:

    const { isPlatformPaySupported } = useStripe();
    const [isInitialized, setIsInitialized] = React.useState(false);

    useEffect(() => {
        initStripe({
            publishableKey: "...",
        }).then(() => setIsInitialized(true));
    }, []);

   if (isInitialized) {
       isPlatformPaySupported();
   }

It worked for me. In my case code like.

 const [isInitialized, setIsInitialized] = useState(false);
    const initializeStripe = async () => {
        if (isAndroid) {
            await NativeStripeSdk.initialise({
            publishableKey,
            appInfo,
            stripeAccountId,
            threeDSecureParams,
            urlScheme,
            setReturnUrlSchemeOnAndroid,
            });
        } else {
            await NativeStripeSdk.initialise({
            publishableKey,
            appInfo,
            stripeAccountId,
            threeDSecureParams,
            merchantIdentifier,
            urlScheme,
            });
      }
       setIsInitialized(true);
    };

  initializeStripe();

  if (!isInitialized) {
    return null; // or a loading spinner
  }