Files
rnpay/docs/walletman前端对接.md
2026-06-17 01:57:49 +08:00

9.0 KiB
Raw Blame History

WalletMan 前端对接文档

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

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


1. 职责分工

模块 职责
ProxyBackgroundService JS 层启停 Proxy、WS 状态、rebind/patch 配置、通知点击
BaseProxyService Android 前台 Service、WS、TCP 代理、FCM 静默重绑
ProxyFcmService 收 FCM、拉活、静默重绑、失败弹通知、点击 → prefs → JS
宿主 *ProxyService 继承 BaseProxyService,实现 registerWallet → POST /register
Bind 组件 各钱包 token / webview / 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 同一项目

Personal 绑钱包需安装对应 ipay 魔改包chType/chVersion 与 PATCH_EXPECT 一致)。


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 调用宿主实现的 HTTP

@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,          // 如 wss://domain/ws
    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();
});

ProxyBackgroundService API

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

其他导出

导出 作用
proxySendMessage / onProxyMessage WS 自定义消息(ProxyBridge
startActivity / IntentFlags 拉起第三方 App deeplink
openPaytmPayToBank 银行转账 deeplink 封装

Native → JS 事件

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

6. 绑钱包

Token 模式Personalipay AIDL

组件 walletType
PaytmPersonalBind paytm
PhonePePersonalBind phonepe(需传 userToken
MobikwikPersonalBind mobikwik(需传 userToken
FreechargePersonalBind freecharge

流程:打开 Bind 组件 → native AIDL 取 token → 校验 chType/chVersion === PATCH_EXPECTPOST /register

Business 模式

组件 说明
PhonePeBusinessBind webview 绑 PhonePe Business
GooglePayBusinessBind Google Pay Business

Paytm / BharatPe Business 等在 rnpay 内走 OTP 组件,非 rnwalletman 导出。

OTP 模式

POST /request-otpPOST /verify-otp

HTTP 封装参考:services/api.ts


7. FCM 客户端行为

收到 FCM

cmd 行为
wake_proxy BaseProxyService.wakeFromPrefs() 重连 WS
rebind_wallet + msg 非空 handleRebindDeferredNotify:静默 AIDL → 成功 registerWallet;失败弹本地通知
rebind_wallet + msg 为空 直接后台跑重绑,失败不弹通知

PhonePeparams.retry=true 时走 gtkiwphonepegtk)→ 再 AIDL → register。

点击通知

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

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


8. 时序(客户端)

冷启动

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

TCP 代理

收到 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 是否可达;syncConnectionState
version outdated PATCH_EXPECT 与 ipay 包 chVersion 不一致
代理失败 WS 是否 connected等 wake 后再试
PhonePe 重绑 gtk 无效 后台 BAL 限制;需 App 在前台或用户点通知进 App

服务端测试页:http://server:16000/test/index.html


10. rnpay 参考文件

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

11. 新宿主 Checklist

  1. 依赖 rnwalletman + Firebase同项目 service account
  2. setServiceClass + Manifest Service + 移除默认 FCM MessagingService
  3. MainActivity 三处 handleLaunchIntent
  4. 继承 BaseProxyService,实现 registerWallet
  5. JSsetNotificationTapHandlersyncPatchConfigsyncRebindConfigstart
  6. 各钱包 Bind UI + POST /register(或 OTP 流程)
  7. 安装 ipay 魔改包PATCH 版本与服务端/文档一致