stripe / stripe-android

Stripe Android SDK
https://stripe.com/docs/mobile/android
MIT License
1.29k stars 648 forks source link

Received Error inflating class com.stripe.android.view.CardMultilineWidget exception and app crashed in Accept a payment Android #3902

Closed IamMathankumar closed 3 years ago

IamMathankumar commented 3 years ago

Summary

Followed the Accept payment Kotlin document, App crashed while calling presentPaymentSheet() function

Code to reproduce

Checkout activity kotlin class `class CheckoutActivity : AppCompatActivity() {

private lateinit var paymentSheet: PaymentSheet

private lateinit var customerId: String
private lateinit var ephemeralKeySecret: String
private lateinit var paymentIntentClientSecret: String

private lateinit var buyButton: Button
private lateinit var viewModel: RecommendationViewModel

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_checkout)

    viewModel =
        ViewModelProvider(
            this,
            RecommendationViewModelFactory()
        ).get(RecommendationViewModel::class.java)
    // instantiate view and buyButton
    buyButton = findViewById(R.id.payButton)
    buyButton.isEnabled = false

    paymentSheet = PaymentSheet(this) { result ->
        onPaymentSheetResult(result)
    }

    buyButton.setOnClickListener {
        presentPaymentSheet()
    }
    checkOutApi()
}

private fun checkOutApi() {
    val fieldMap = HashMap<String, String?>()
    fieldMap["amount"] = "51"
    fieldMap["currency"] = "SGD"
    viewModel.checkOut(fieldMap).observe(this, {
        it?.let { resource ->
            when (resource.status) {
                Status.SUCCESS -> {
                    if (it.data?.data != null) {
                        val data = it.data.data
                        customerId = data.customer
                        ephemeralKeySecret = data.ephemeralKey
                        paymentIntentClientSecret = data.paymentIntent

                        runOnUiThread {
                            buyButton.isEnabled = true
                        }
                    }
                }
                Status.ERROR -> {

                }
                Status.LOADING -> {

                }
            }
        }
    })
}

private fun presentPaymentSheet() {
    paymentSheet.presentWithPaymentIntent(
        paymentIntentClientSecret,
        PaymentSheet.Configuration(
            merchantDisplayName = "Example, Inc.",
            customer = PaymentSheet.CustomerConfiguration(
                id = customerId,
                ephemeralKeySecret = ephemeralKeySecret
            )
        )
    )
}

private fun onPaymentSheetResult(
    paymentSheetResult: PaymentSheetResult
) {
    when (paymentSheetResult) {
        is PaymentSheetResult.Canceled -> {
            Toast.makeText(
                this,
                "Payment Canceled",
                Toast.LENGTH_LONG
            ).show()
        }
        is PaymentSheetResult.Failed -> {
            Toast.makeText(
                this,
                "Payment Failed. See logcat for details.",
                Toast.LENGTH_LONG
            ).show()
            Log.e("App", "Got error: ${paymentSheetResult.error}")
        }
        is PaymentSheetResult.Completed -> {
            Toast.makeText(
                this,
                "Payment Complete",
                Toast.LENGTH_LONG
            ).show()
        }
    }
}

private companion object {
    private const val STRIPE_PUBLISHABLE_KEY =
        "pk_test_..."
}

}`

Checkout layout xml <?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".CheckoutActivity" tools:showIn="@layout/activity_checkout"> <Button android:id="@+id/payButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="20dp" android:text="Pay" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>

Android version

Android 11

Impacted devices

Android 11 (Samsung f41) Android 11 Google pixel 2 XL

Installation method

Through a gradle dependency

Dependency Versions

stripe-android:16.10.0 stripe-android:16.8.0 Tried in both versions facing this issue in both version

Android Gradle Plugin:

Mon Apr 26 22:52:31 IST 2021

distributionBase=GRADLE_USER_HOME distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-rc-1-bin.zip distributionPath=wrapper/dists zipStorePath=wrapper/dists zipStoreBase=GRADLE_USER_HOME

Console log

layout/fragment_paymentsheet_add_card: Error inflating class com.stripe.android.view.CardMultilineWidget Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:343) at android.view.LayoutInflater.createView(LayoutInflater.java:852) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:1004) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:959) at android.view.LayoutInflater.rInflate(LayoutInflater.java:1121) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082) at android.view.LayoutInflater.rInflate(LayoutInflater.java:1124) at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:1082) at android.view.LayoutInflater.inflate(LayoutInflater.java:680) at android.view.LayoutInflater.inflate(LayoutInflater.java:532) at com.stripe.android.paymentsheet.BaseAddCardFragment.onCreateView(BaseAddCardFragment.kt:81) at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2963) at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:518) 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:938) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:223) at android.app.ActivityThread.main(ActivityThread.java:7656) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)

mshafrir-stripe commented 3 years ago

@IamMathankumar thanks for filing. Can you share what AndroidX dependencies you're using?

IamMathankumar commented 3 years ago

@mshafrir-stripe Thanks for immediate response.

These all are app dependencies


 implementation 'androidx.core:core-ktx:1.6.0-rc01'
    implementation 'androidx.appcompat:appcompat:1.4.0-alpha02'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    implementation 'androidx.fragment:fragment-ktx:1.3.5'
    implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
    implementation "androidx.navigation:navigation-runtime-ktx:$nav_version"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    implementation 'androidx.legacy:legacy-support-v4:1.0.0'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
    implementation "androidx.viewpager2:viewpager2:1.0.0"
    implementation 'androidx.annotation:annotation:1.2.0'
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.airbnb.android:lottie:3.4.1'
    implementation 'com.github.yalantis:ucrop:2.2.6'
    implementation("com.squareup.okhttp3:okhttp-urlconnection:4.4.1")
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
    implementation 'com.google.android.gms:play-services-auth:19.0.0'
    implementation 'com.facebook.android:facebook-android-sdk:6.4.0'
    implementation "com.github.bumptech.glide:glide:$glide"
    kapt "com.github.bumptech.glide:compiler:$glide"
    implementation 'com.stripe:stripe-android:16.10.0'
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
michelleb-stripe commented 3 years ago

This is an issue with 1.4.0-alph02 of androidx.appcompat:appcompat. If you are able to downgrade to 1.3.0 that will work, otherwise a fix will be in the next release.

IamMathankumar commented 3 years ago

Ok, For now I will downgrade the appcompat version. Thanks for the quick solution

michelleb-stripe commented 3 years ago

@IamMathankumar Version 16.10.2 is released and should resolve your issue.

IamMathankumar commented 3 years ago

Ok, Thank you