v0.19.0版本Stripe React Native Android端PaymentSheet崩溃问题
问题:stripe-react-native v0.19.0 Android端调用presentPaymentSheet崩溃,报错ViewTreeLifecycleOwner not found
问题描述
在stripe-react-native v0.19.0版本中,Android 13和10系统下调用presentPaymentSheet时应用无报错直接崩溃,通过Sentry捕获到错误:
IllegalStateException: ViewTreeLifecycleOwner not found
iOS端运行完全正常。
复现步骤
按照Stripe官方视频及文档实现支付功能,核心代码如下:
export default function TestPaymentScreen(props) { const [ready, setReady] = useState(false); const {initPaymentSheet, presentPaymentSheet, loading} = usePaymentSheet(); useEffect(() => { initializePaymentSheet(); }, []); const initializePaymentSheet = async () => { const {paymentIntent, ephemeralKey, customer} = await fetchPaymentSheetParams(); const {error} = await initPaymentSheet({ customerId: customer, customerEphemeralKeySecret: ephemeralKey, paymentIntentClientSecret: paymentIntent, merchantDisplayName: 'MyApp', allowsDelayedPaymentMethods: true, returnURL: 'stripe-example://stripe-redirect', }); if (error) { Alert.alert(`Error codes: ${error.code}`, error.message); } else { setReady(true); } }; const fetchPaymentSheetParams = async () => { const response = await fetch(`http://192.168.1.67:8000/checkout`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, }); const {paymentIntent, ephemeralKey, customer} = await response.json(); return { paymentIntent, ephemeralKey, customer, }; }; async function buy() { const {error} = await presentPaymentSheet(); if (error) { Alert.alert(`Error code: ${error.code}`, error.message); } else { Alert.alert('Success', 'The payment was confirmed successfully'); setReady(false); } } /* ... */ }
点击按钮调用presentPaymentSheet(原文误写为openPaymentSheet)时,Android应用崩溃,Metro控制台无报错,Sentry显示详细错误:
IllegalStateException ViewTreeLifecycleOwner not found from androidx.coordinatorlayout.widget.CoordinatorLayout{5876b97 V.E...... ......I. 0,0-0,0 #7f0800cf app:id/coordinator}
预期行为
PaymentSheet正常弹出
设备信息
- 设备:Pixel 4
- 系统:Android 13
相关配置
package.json
{ "name": "MyApp", "version": "0.0.1", "private": true, "scripts": { "android": "react-native run-android", "ios": "react-native run-ios", "start": "react-native start", "test": "jest", "lint": "eslint ." }, "dependencies": { "@babel/runtime-corejs3": "^7.13.10", "@georstat/react-native-image-gallery": "^1.1.0", "@react-native-async-storage/async-storage": "^1.17.10", "@react-native-community/checkbox": "^0.5.7", "@react-native-community/cli-platform-ios": "^5.0.1", "@react-native-community/datetimepicker": "^3.4.3", "@react-native-community/geolocation": "^2.0.2", "@react-native-community/masked-view": "^0.1.10", "@react-native-community/push-notification-ios": "^1.8.0", "@react-native-community/slider": "^3.0.3", "@react-native-community/viewpager": "^4.2.4", "@react-native-firebase/app": "^11.5.0", "@react-native-firebase/messaging": "^11.5.0", "@react-native-google-signin/google-signin": "^6.0.0", "@react-native/normalize-color": "^2.0.0", "@react-navigation/drawer": "^5.12.4", "@sentry/react-native": "^4.2.2", "@stripe/stripe-react-native": "^0.19.0", "axios": "^0.27.2", "core-js": "^3.9.1", "firebase": "^8.3.1", "is-base64": "^1.1.0", "moment": "^2.29.1", "native-base": "^2.13.15", "react": "^16.13.1", "react-dom": "^16.14.0", "react-is": "^16.13.1", "react-native": "^0.64.4", "react-native-animatable": "^1.3.3", "react-native-app-intro-slider": "^4.0.4", "react-native-awesome-alerts": "^1.5.2", "react-native-calendar-picker": "^7.1.1", "react-native-calendars": "^1.1254.0", "react-native-check-box": "^2.1.7", "react-native-city-picker": "^1.0.3", "react-native-city-select": "^0.1.7", "react-native-country-picker-modal": "^2.0.0", "react-native-date-picker": "^4.2.5", "react-native-device-info": "^8.7.1", "react-native-dotenv": "^3.3.1", "react-native-dropdown-picker": "^5.4.2", "react-native-elements": "^3.3.2", "react-native-fast-image": "^8.5.11", "react-native-gesture-handler": "^1.10.3", "react-native-gifted-chat": "^0.16.3", "react-native-google-places-autocomplete": "^2.4.1", "react-native-image-crop-picker": "^0.37.3", "react-native-image-picker": "^4.10.0", "react-native-image-slider-box": "^1.0.12", "react-native-keyboard-aware-scroll-view": "^0.9.5", "react-native-launch-navigator": "^1.0.8", "react-native-maps": "git+https://github.com/react-native-community/react-native-maps.git", "react-native-modal-dropdown": "git+https://github.com/siemiatj/react-native-modal-dropdown.git", "react-native-open-maps": "^0.4.0", "react-native-phone-input": "^1.3.2", "react-native-phone-number-input": "^2.1.0", "react-native-photo-gallery": "^0.2.4", "react-native-push-notification": "^8.1.1", "react-native-really-awesome-button": "^1.6.0", "react-native-reanimated": "^1.13.4", "react-native-safe-area-context": "^3.2.0", "react-native-schedule-availability": "^0.2.0", "react-native-screens": "^2.18.1", "react-native-simple-toast": "^1.1.4", "react-native-star-rating": "^1.1.0", "react-native-svg": "^12.3.0", "react-native-svg-transformer": "^0.14.3", "react-native-svg-uri": "^1.2.3", "react-native-swipeable-rating": "^0.2.1", "react-native-swiper": "^1.6.0-nightly.5", "react-native-switch": "^2.0.0", "react-native-vector-icons": "^7.1.0", "react-native-webview": "^11.23.1", "react-navigation": "^4.4.4", "react-navigation-drawer": "^2.7.0", "react-navigation-stack": "^2.10.4", "react-navigation-tabs": "^2.11.0", "react-schedule-selector": "^3.0.0", "rn-schedule-availability": "^0.5.0", "styled-components": "^5.3.5", "toggle-switch-react-native": "^3.2.0" }, "devDependencies": { "@babel/core": "^7.13.14", "@babel/runtime": "^7.13.10", "@react-native-community/eslint-config": "^1.1.0", "babel-jest": "^25.1.0", "eslint": "^6.5.1", "jest": "^25.1.0", "metro-react-native-babel-preset": "^0.59.0", "react-test-renderer": "16.13.1" }, "files": [ ".flowconfig", "android", "cli.js", "flow", "init.sh", "scripts/compose-source-maps.js", "scripts/ios-configure-glog.sh", "scripts/ios-install-third-party.sh", "scripts/launchPackager.bat", "scripts/launchPackager.command", "scripts/node-binary.sh", "scripts/packager.sh", "scripts/react-native-xcode.sh", "jest-preset.js", "jest", "lib", "rn-get-polyfills.js", "Libraries", "LICENSE", "packager", "react-native.config.js", "react.gradle", "React.podspec", "React-Core.podspec", "React", "ReactAndroid", "ReactCommon", "README.md", "third-party-podspecs", "template", "local-cli", "template.config.js", "!template/node_modules", "!template/yarn.lock", "!template/package-lock.json" ], "jest": { "preset": "react-native" } }
android/app/build.gradle
apply plugin: "com.android.application" apply plugin: 'com.google.gms.google-services' import com.android.build.OutputFile project.ext.react = [ enableHermes: false, ] apply from: "../../node_modules/react-native/react.gradle" apply from: "../../node_modules/@sentry/react-native/sentry.gradle" apply from: "../../node_modules/react-native-vector-icons/fonts.gradle" def enableSeparateBuildPerCPUArchitecture = false def enableProguardInReleaseBuilds = false def jscFlavor = 'org.webkit:android-jsc:+' def enableHermes = project.ext.react.get("enableHermes", false); android { compileSdkVersion rootProject.ext.compileSdkVersion compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } defaultConfig { applicationId "com.myapp" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 24 versionName "1.24" } splits { abi { reset() enable enableSeparateBuildPerCPUArchitecture universalApk false include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" } } signingConfigs { debug { storeFile file('debug.keystore') storePassword 'android' keyAlias 'androiddebugkey' keyPassword 'android' } } buildTypes { debug { signingConfig signingConfigs.debug } release { signingConfig signingConfigs.debug minifyEnabled enableProguardInReleaseBuilds proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } applicationVariants.all { variant -> variant.outputs.each { output -> def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] def abi = output.getFilter(OutputFile.ABI) if (abi != null) { // null for the universal-debug, universal-release variants output.versionCodeOverride = versionCodes.get(abi) * 1048576 + defaultConfig.versionCode } } } } dependencies { implementation fileTree(dir: "libs", include: ["*.jar"]) implementation "com.facebook.react:react-native:+" // From node_modules implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" implementation platform('com.google.firebase:firebase-bom:30.0.1') implementation 'com.google.firebase:firebase-analytics' implementation("com.google.firebase:firebase-iid") implementation(project(':stripe_stripe-react-native')) { exclude module: 'appcompat' } debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { exclude group:'com.facebook.fbjni' } debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { exclude group:'com.facebook.flipper' exclude group:'com.squareup.okhttp3', module:'okhttp' } debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") { exclude group:'com.facebook.flipper' } if (enableHermes) { def hermesPath = "../../node_modules/hermes-engine/android/"; debugImplementation files(hermesPath + "hermes-debug.aar") releaseImplementation files(hermesPath + "hermes-release.aar") } else { implementation jscFlavor } } task copyDownloadableDepsToLibs(type: Copy) { from configurations.compile into 'libs' } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
android/build.gradle
buildscript { ext { googlePlayServicesVersion = "+" firebaseMessagingVersion = "21.1.0" buildToolsVersion = "29.0.2" minSdkVersion = 21 compileSdkVersion = 33 targetSdkVersion = 33 } repositories { google() jcenter() } dependencies { classpath("com.android.tools.build:gradle:4.1.0") classpath "com.google.gms:google-services:4.3.10" } } allprojects { repositories { mavenLocal() maven { url("$rootDir/../node_modules/react-native/android") } maven { url("$rootDir/../node_modules/jsc-android/dist") } google() jcenter() maven { url 'https://www.jitpack.io' } } }
解决方案
这个错误源于AndroidX的ViewTreeLifecycleOwner未被正确关联,属于旧版React Native与新版Stripe SDK的兼容性问题,可通过以下方式解决:
- 升级React Native版本:当前使用的RN 0.64.4版本较旧,建议升级到0.65+版本,新版RN已完善AndroidX LifecycleOwner的处理逻辑。
- 调整Stripe依赖配置:移除
android/app/build.gradle中Stripe依赖的exclude module: 'appcompat'配置,确保依赖统一的AndroidX库。 - 手动设置ViewTreeLifecycleOwner:若无法升级RN,可在
MainActivity中添加代码手动关联LifecycleOwner:
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleRegistry; import androidx.appcompat.app.AppCompatActivity; public class MainActivity extends ReactActivity { private LifecycleRegistry lifecycleRegistry; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); lifecycleRegistry = new LifecycleRegistry(this); lifecycleRegistry.markState(Lifecycle.State.CREATED); } @Override public LifecycleOwner getLifecycleOwner() { return this; } @Override
相关产品推荐
相关产品推荐

