如何通过React Native原生模块将Java监听的支付事件数据传至JS
React Native安卓刷卡机支付事件监听方案
问题背景
我正在开发基于Expo Bare Workflow的React Native应用,该应用运行在安卓刷卡机上。在支付过程中需要监听插卡、输入密码、交易批准等事件,需实现Java原生代码收集事件数据,并通过React Native原生模块在JavaScript中获取这些事件。
原Java核心模块代码
package com.myapp; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import android.util.Log; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPag; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagAppIdentification; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagEventData; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagEventListener; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagInitializationResult; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagPaymentData; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagActivationData; public class PlugPagModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; public PlugPagModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; } private final int TYPE_CREDITO = 1; public String transactionsEvents = ""; @NonNull @Override public String getName() { return "PlugPagModule"; } @ReactMethod public void startPayment() { // 定义支付数据 PlugPagPaymentData paymentData = new PlugPagPaymentData(TYPE_CREDITO,25000,PlugPag.INSTALLMENT_TYPE_A_VISTA,1,"CODVENDA"); // 创建应用标识 PlugPagAppIdentification appIdentification = new PlugPagAppIdentification("MeuApp", "1.0.7"); // 创建PlugPag实例 PlugPag plugpag = new PlugPag(reactContext, appIdentification); // 激活终端并发起支付 PlugPagInitializationResult initResult = plugpag.initializeAndActivatePinpad(new PlugPagActivationData("403938")); if(initResult.getResult() == PlugPag.RET_OK) { plugpag.setEventListener(new PlugPagEventListener() { @Override public void onEvent(@NonNull PlugPagEventData plugPagEventData) { Log.d("onEvent", String.valueOf(plugPagEventData.getCustomMessage())); transactionsEvents = plugPagEventData.getCustomMessage(); } }); plugpag.doPayment(paymentData); } } }
原React代码
import React from 'react'; import { NativeModules, NativeEventEmitter } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from 'styled-components'; import { Button } from '../../components/Button'; import { Container, Header, BackButtonContainer, TitleHeader, } from './styles'; interface NavigationProps { goBack(): void; } export function PayCommandWithCard() { const { PlugPagModule } = NativeModules; const theme = useTheme(); const navigation = useNavigation<NavigationProps>(); const events = new NativeEventEmitter(PlugPagModule.transactionsEvents); console.log(events); function handleBack() { navigation.goBack(); } async function handlePayment() { await PlugPagModule.startPayment(); } return ( <Container> <Header> <BackButtonContainer> <Button color="secondary" rounded onPress={handleBack} > <MaterialIcons name="arrow-back" size={20} color={theme.colors.primary} /> </Button> </BackButtonContainer> <TitleHeader>Pagar Comanda</TitleHeader> </Header> <Button title="test" onPress={handlePayment} /> </Container> ); }
解决方案
1. 修改Java原生模块:实时推送事件到JS端
当前代码仅将事件存储在字符串变量中,无法主动通知JS端。需要通过React Native的DeviceEventManagerModule将事件数据实时发送到JavaScript层。
修改后的Java代码:
package com.myapp; import androidx.annotation.NonNull; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.modules.core.DeviceEventManagerModule; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPag; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagAppIdentification; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagEventData; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagEventListener; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagInitializationResult; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagPaymentData; import br.com.uol.pagseguro.plugpagservice.wrapper.PlugPagActivationData; public class PlugPagModule extends ReactContextBaseJavaModule { private final ReactApplicationContext reactContext; private static final String PAYMENT_EVENT_NAME = "onPaymentEvent"; public PlugPagModule(ReactApplicationContext reactContext) { super(reactContext); this.reactContext = reactContext; } private final int TYPE_CREDITO = 1; @NonNull @Override public String getName() { return "PlugPagModule"; } // 发送事件到JS端的工具方法 private void sendEvent(String eventName, WritableMap params) { reactContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params); } @ReactMethod public void startPayment() { PlugPagPaymentData paymentData = new PlugPagPaymentData(TYPE_CREDITO,25000,PlugPag.INSTALLMENT_TYPE_A_VISTA,1,"CODVENDA"); PlugPagAppIdentification appIdentification = new PlugPagAppIdentification("MeuApp", "1.0.7"); PlugPag plugpag = new PlugPag(reactContext, appIdentification); PlugPagInitializationResult initResult = plugpag.initializeAndActivatePinpad(new PlugPagActivationData("403938")); if(initResult.getResult() == PlugPag.RET_OK) { plugpag.setEventListener(new PlugPagEventListener() { @Override public void onEvent(@NonNull PlugPagEventData plugPagEventData) { // 构造可被JS识别的事件数据 WritableMap eventData = new WritableNativeMap(); eventData.putString("customMessage", plugPagEventData.getCustomMessage()); eventData.putInt("eventCode", plugPagEventData.getEventCode()); eventData.putString("eventMessage", plugPagEventData.getMessage()); // 发送事件到JS端 sendEvent(PAYMENT_EVENT_NAME, eventData); } }); plugpag.doPayment(paymentData); } } }
关键修改点:
- 移除无用的
transactionsEvents变量 - 添加
sendEvent工具方法,通过DeviceEventManagerModule推送事件 - 在
onEvent回调中,将PlugPagEventData的关键字段封装成WritableMap推送到JS端
2. 修改React Native代码:监听原生事件
当前代码创建NativeEventEmitter的方式错误,需要传入原生模块实例,并正确监听事件。
修改后的React代码:
import React, { useEffect, useState } from 'react'; import { NativeModules, NativeEventEmitter } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import { MaterialIcons } from '@expo/vector-icons'; import { useTheme } from 'styled-components'; import { Button } from '../../components/Button'; import { Container, Header, BackButtonContainer, TitleHeader, } from './styles'; interface NavigationProps { goBack(): void; } // 定义事件数据类型 interface PaymentEventData { customMessage: string; eventCode: number; eventMessage: string; } export function PayCommandWithCard() { const { PlugPagModule } = NativeModules; const eventEmitter = new NativeEventEmitter(PlugPagModule); const theme = useTheme(); const navigation = useNavigation<NavigationProps>(); const [currentEvent, setCurrentEvent] = useState<PaymentEventData | null>(null); useEffect(() => { // 监听原生发送的支付事件 const eventListener = eventEmitter.addListener('onPaymentEvent', (event: PaymentEventData) => { console.log('收到支付事件:', event); setCurrentEvent(event); // 根据eventCode处理不同场景:插卡、输入密码、交易批准等 switch(event.eventCode) { case 1001: // 处理插卡事件 break; case 1002: // 处理输入密码事件 break; case 2000: // 处理交易批准事件 break; default: break; } }); // 组件卸载时移除监听器,避免内存泄漏 return () => { eventListener.remove(); }; }, [eventEmitter]); function handleBack() { navigation.goBack(); } async function handlePayment() { await PlugPagModule.startPayment(); } return ( <Container> <Header> <BackButtonContainer> <Button color="secondary" rounded onPress={handleBack} > <MaterialIcons name="arrow-back" size={20} color={theme.colors.primary} /> </Button> </BackButtonContainer> <TitleHeader>Pagar Comanda</TitleHeader> </Header> {/* 显示当前事件信息 */} {currentEvent && ( <div> <p>事件消息: {currentEvent.eventMessage}</p> <p>自定义消息: {currentEvent.customMessage}</p> </div> )} <Button title="发起支付" onPress={handlePayment} /> </Container> ); }
关键修改点:
- 正确创建
NativeEventEmitter实例,传入PlugPagModule - 使用
useEffect添加事件监听器,并在组件卸载时移除 - 定义
PaymentEventData类型规范事件数据结构 - 根据
eventCode区分不同支付阶段的事件(插卡、输密、交易批准等) - 添加事件展示UI,方便调试
内容的提问来源于stack exchange,提问作者Bruno Azevedo
相关产品推荐
相关产品推荐

