Files
rnpay/docs/walletman前端对接.md
2026-06-16 11:29:27 +08:00

7.3 KiB
Raw Permalink Blame History

WalletMan 前端对接文档

后端协议见 walletman后端对接.md

宿主 Apprnpay)依赖 rnwalletman,负责 Proxy 常驻、WS 连接、FCM 收令、绑钱包 UI。


1. 职责

模块 职责
ProxyBackgroundService 启停 Proxy、WS 状态、FCM/rebind 配置
BaseProxyService 前台 Service、WS、TCP 代理、FCM 静默重绑
ProxyFcmService 收 FCM、拉活、通知点击 → prefs → JS
宿主 *ProxyService 实现 registerWallet → POST /register
Bind 组件 各钱包 token/OTP 绑定 UI

clientId DeviceInfo.getUniqueIdSync(),与后端 WS/FCM 一致。


2. 依赖

"rnwalletman": "file:libs/rnwalletman"

改 lib 后:

rsync -a --delete libs/rnwalletman/ node_modules/rnwalletman/

需 Firebasegoogle-services.json 与服务端 FCM 同项目。


3. Android 配置

Application

// MainApplication.onCreate
BaseProxyService.setServiceClass(RnpayProxyService.class);

Manifest

<service
  android:name=".RnpayProxyService"
  android:exported="false"
  android:foregroundServiceType="dataSync"
  android:stopWithTask="false" />
<!-- 避免 Firebase 默认 Service 抢 FCM -->
<service
  android:name="com.google.firebase.messaging.FirebaseMessagingService"
  tools:node="remove" />

ProxyFcmService 由 rnwalletman manifest merge宿主不用重复声明。

MainActivity

@Override protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  ProxyFcmService.handleLaunchIntent(this);
}
@Override protected void onResume() {
  super.onResume();
  ProxyFcmService.handleLaunchIntent(this);
}
@Override public void onNewIntent(Intent intent) {
  super.onNewIntent(intent);
  setIntent(intent);
  ProxyFcmService.handleLaunchIntent(this);
}

launchMode="singleTask" 推荐。


4. 宿主 registerWallet

FCM 静默重绑成功后 native 调用:

@Override
protected void registerWallet(Context ctx, String walletId, String walletType,
                              String phone, JSONObject params) throws Exception {
  // POST {baseUrl}/register
  // body: { "walletType": walletType, "params": params }
  // header: X-User-ID
}

baseUrl/userId/userToken 来自 JS syncRebindConfigproxy_service_prefs

参考:android/app/src/main/java/com/rnpay/RnpayProxyService.java


5. JS 对接

启动顺序

import {
  proxyBackgroundService,
  type RebindConfig,
  type PatchConfig,
  type FcmNotificationTapPayload,
} from 'rnwalletman';
import DeviceInfo from 'react-native-device-info';

const PATCH_EXPECT: PatchConfig = {
  chType: 'ipay',
  paytmChVersion: '3',
  phonepeChVersion: '1',
  mobikwikChVersion: '1',
};

async function bootstrap(userId: number, userToken: string) {
  const clientId = DeviceInfo.getUniqueIdSync();

  // ① 尽早注册componentDidMount 第一行)
  proxyBackgroundService.setNotificationTapHandler(handleNotificationTap);

  await proxyBackgroundService.syncPatchConfig(PATCH_EXPECT);

  await proxyBackgroundService.syncRebindConfig({
    baseUrl: Api.BASE_URL,
    userId,
    userToken,
    onRebound: () => fetchWallets(),
  });

  await proxyBackgroundService.start({
    wsUrl: Api.WS_URL,
    clientId,
    userId,
    heartbeatInterval: 10000,
    reconnectInterval: 5000,
    registerFcmToken: (cid, token) =>
      Api.instance.registerFcmToken(cid, token),
    onConnected: () => setProxyStatus('connected'),
    onDisconnected: () => setProxyStatus('disconnected'),
    onError: (msg) => setProxyStatus('error', msg),
  });
}

function handleNotificationTap(payload: FcmNotificationTapPayload) {
  if (payload.cmd !== 'rebind_wallet') return;
  const { walletId, walletType, phone } = payload.params;
  // 按 walletType 打开 Bind 弹窗
}

App 回前台时补读 pending

AppState.addEventListener('change', (s) => {
  if (s === 'active') void proxyBackgroundService.syncPendingNotificationTap();
});

API

方法 作用
start(config) 前台 Proxy + WS
stop() 停止
syncRebindConfig(config | null) native 重绑 HTTP 配置
syncPatchConfig(config) ipay chType/chVersion 校验
setNotificationTapHandler(fn | null) 通知点击回调
syncPendingNotificationTap() 消费 prefs pending

Native 事件

事件 data
ProxyServiceConnected -
ProxyServiceDisconnected -
ProxyServiceRebound walletId
ProxyServiceNotificationTap JSON {cmd,params}
ProxyServiceCustomCommand WS 自定义消息

6. 绑钱包

Token 模式

  1. 打开 PaytmPersonalBind / PhonePePersonalBind
  2. 校验 chType/chVersion === PATCH_EXPECT
  3. POST /register

OTP 模式

POST /request-otpPOST /verify-otp

HTTP 封装参考: services/api.ts


7. FCM 客户端行为

收到 FCM

cmd 行为
wake_proxy BaseProxyService.wakeFromPrefs()
rebind_wallet 先静默 AIDL → 成功 registerWallet;失败弹本地通知

点击通知

PendingIntent(cmd+params)
  → MainActivity onCreate/onNewIntent/onResume
  → handleLaunchIntent 读 extra
  → 写 prefs pending_notif_tap
  → emit 或等 JS syncPendingNotificationTap
  → setNotificationTapHandler 回调

Intent 负责拉起 Appprefs 解决 JS 未 ready 的时序问题。


8. 时序(客户端视角)

冷启动

componentDidMount
  → setNotificationTapHandler
  → login → syncPatch/Rebind → start
  → WS register { clientId, userId, fcmToken }
  → POST /fcm/register
  → GET /wallets

代理

收到 proxyRequest
  → TCP host:port
  → proxyReady → proxyData 双向

重绑

FCM rebind_wallet
  → 静默 AIDL → registerWallet → POST /register → ProxyServiceRebound
  → 失败 → 本地通知 → 点击 → handleNotificationTap → 打开 Bind

9. 调试

adb logcat -s ProxyFcmService ProxyService WalletRebind ProxyServiceModule
adb shell run-as com.rnpay cat shared_prefs/proxy_service_prefs.xml | grep pending
现象 排查
FCM 无日志 manifest 去掉默认 MessagingService勿 force-stop
通知点击无回调 logcat notification taphandler 是否第一行注册
Proxy Connecting 卡住 重启后 WS 已连但未 emit Connected已修复 sync
version outdated PATCH_EXPECT 与 ipay 包不一致
代理失败 WS 是否 connected等 wake 后再试

服务端测试页可发 wake/rebindhttp://server:16000/test/index.html


10. rnpay 参考

文件 职责
services/api.ts BASE_URL / WS_URL / HTTP
screens/HomeScreen.tsx Proxy、PATCH_EXPECT、notificationTap
RnpayProxyService.java registerWallet
MainApplication.java setServiceClass
MainActivity.java handleLaunchIntent

11. 新宿主 checklist

  1. 依赖 rnwalletman + Firebase
  2. setServiceClass + Manifest Service + 去默认 FCM Service
  3. MainActivity 处理 launch intent
  4. 继承 BaseProxyService 实现 registerWallet
  5. JSsetNotificationTapHandlersyncPatchsyncRebindstart
  6. 各钱包 Bind UI + POST /register