React Native WebView集成Paystack时取消支付按钮无响应问题
解决React Native WebView集成Paystack时取消按钮无响应的问题
问题根源分析
- 脚本注入时机错误:你在
onNavigationStateChange中注入JS时,Paystack页面可能还未完全渲染,导致找不到目标按钮。 - 按钮选择器不可靠:依赖
innerHTML.includes('Cancel Payment')判断按钮容易失效,Paystack的UI可能会更新文本或结构。 - HTMLCollection遍历问题:
getElementsByTagName('button')返回的是HTMLCollection,不能直接用forEach,需要先转为数组。 - 未阻止原按钮默认行为:原按钮可能自带跳转逻辑,导致你的监听事件还未执行就触发了页面跳转。
可行解决方案
方案1:劫持原按钮事件并发送消息到RN
修改脚本注入时机和内容,确保页面加载完成后再执行,同时修复遍历和事件逻辑:
- 更新WebView配置:使用
onLoadEnd事件注入脚本,确保页面完全渲染:
{isPaymentSuccess && paymentState && ( <WebView javaScriptEnabled={true} source={{ uri: paymentData }} style={{ marginTop: 50 }} onNavigationStateChange={handleNav} cacheEnabled={false} cacheMode={'LOAD_NO_CACHE'} ref={webView} onMessage={(e) => { const data = JSON.parse(e.nativeEvent.data); if (data.event === 'cancelled') { setPaymentState(false); // 这里可以添加取消后的逻辑 } }} onLoadEnd={() => { webView.current?.injectJavaScript(handleCancel); }} /> )}
- 修正
handleCancel脚本:
const handleCancel = ` // 将HTMLCollection转为数组遍历 const buttons = Array.from(document.getElementsByTagName('button')); buttons.forEach(button => { // 改用更可靠的选择方式,比如检查按钮的类或属性(实际可通过浏览器调试查看) if (button.textContent.includes('Cancel Payment') || button.classList.contains('paystack-close-button')) { // 移除原有事件(可选,避免冲突) button.replaceWith(button.cloneNode(true)); const newButton = document.querySelector('[textContent*="Cancel Payment"]'); // 添加新的点击事件 newButton.addEventListener('click', (e) => { e.preventDefault(); // 阻止默认跳转 window.ReactNativeWebView.postMessage(JSON.stringify({event: 'cancelled'})); // 触发Paystack的关闭逻辑 window.location.href = 'https://standard.paystack.co/close'; }); } }); `;
方案2:隐藏原按钮,添加自定义取消按钮
如果劫持原按钮不稳定,可以直接隐藏原按钮,在WebView上方叠加RN的自定义按钮:
{isPaymentSuccess && paymentState && ( <View style={{flex: 1}}> <WebView // 原有WebView配置 /> {/* 自定义取消按钮,覆盖在WebView顶部 */} <TouchableOpacity style={{position: 'absolute', top: 60, left: 20, padding: 10, backgroundColor: '#fff', borderRadius: 5}} onPress={() => { setPaymentState(false); // 如果需要触发Paystack的close逻辑,可以注入JS跳转 webView.current?.injectJavaScript(`window.location.href = 'https://standard.paystack.co/close';`); }} > <Text>Cancel Payment</Text> </TouchableOpacity> </View> )}
方案3:监听Paystack的close URL跳转
直接在onNavigationStateChange中检测是否跳转到https://standard.paystack.co/close,如果是则关闭WebView:
const handleNav = async (navState) => { const { url } = navState; if (url.includes('https://standard.paystack.co/close')) { setPaymentState(false); return; } // 原有回调URL验证逻辑 const customUrl = url.split('?'); const getCallBackURL = customUrl[0]; const queryStr = customUrl[1]; if (getCallBackURL === callback_url) { setPaymentState(false); try { const res = await axios.get(`${BASE_URL}/payverify/?${queryStr}`); if (res?.data?.status === 'success') { const payMentData = res?.data; navigation.navigate('ThankyouPage', {payMentData}); } } catch (error) { // 处理错误 } } };
关键注意事项
- 调试时可以用
console.log在注入的JS中输出信息,通过Chrome调试WebView查看执行情况。 - Paystack的UI结构可能会更新,建议通过浏览器开发者工具查看按钮的实际属性,调整选择器。
- 确保
window.ReactNativeWebView.postMessage能正常触发,RN端的onMessage能正确接收消息。
内容的提问来源于stack exchange,提问作者kingsJayson
相关产品推荐
相关产品推荐

