This commit is contained in:
2026-09-02 15:29:47 +08:00
parent 89f55cf884
commit bab8831732
7 changed files with 32 additions and 99 deletions
+1
View File
@@ -22,3 +22,4 @@ others
*.lock *.lock
**/fcm-service-account.json **/fcm-service-account.json
**/firebase-adminsdk*.json **/firebase-adminsdk*.json
logs/googlepay_business
+3 -3
View File
@@ -11,8 +11,8 @@ import {
import { saveServerDomain } from '../services/api'; import { saveServerDomain } from '../services/api';
const PRESETS = [ const PRESETS = [
{ label: '192.168.1.117:16000', host: '192.168.1.117', port: '16000' },
{ label: 'aa.pfgame.org', host: 'aa.pfgame.org', port: '443' }, { label: 'aa.pfgame.org', host: 'aa.pfgame.org', port: '443' },
{ label: '192.168.1.117:16000', host: '192.168.1.117', port: '16000' },
]; ];
type Props = { type Props = {
@@ -62,7 +62,7 @@ export const ServerSettingsModal: React.FC<Props> = ({
style={styles.textInput} style={styles.textInput}
value={host} value={host}
onChangeText={onHostChange} onChangeText={onHostChange}
placeholder="192.168.1.117" placeholder="aa.pfgame.org"
autoCapitalize="none" autoCapitalize="none"
/> />
<Text style={styles.inputLabel}>Port</Text> <Text style={styles.inputLabel}>Port</Text>
@@ -70,7 +70,7 @@ export const ServerSettingsModal: React.FC<Props> = ({
style={[styles.textInput, { marginBottom: 20 }]} style={[styles.textInput, { marginBottom: 20 }]}
value={port} value={port}
onChangeText={onPortChange} onChangeText={onPortChange}
placeholder="16000" placeholder="443"
keyboardType="number-pad" keyboardType="number-pad"
/> />
<View style={styles.actions}> <View style={styles.actions}>
+14 -57
View File
@@ -18,7 +18,6 @@ import {
} from 'react-native'; } from 'react-native';
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
import DeviceInfo from 'react-native-device-info'; import DeviceInfo from 'react-native-device-info';
import CookieManager from '@react-native-cookies/cookies';
import { import {
GooglePayBusinessBind, GooglePayBusinessBind,
PhonePeBusinessBind, PhonePeBusinessBind,
@@ -65,11 +64,14 @@ import { buildWalletCardId } from '../utils/walletCardId';
/** ipay patch 期望,bind 与 ProxyService FCM 重绑共用 */ /** ipay patch 期望,bind 与 ProxyService FCM 重绑共用 */
const PATCH_EXPECT: PatchConfig = { const PATCH_EXPECT: PatchConfig = {
chType: 'ipay', chType: 'ipay',
paytmChVersion: '3', paytmChVersion: '7',
phonepeChVersion: '2', phonepeChVersion: '2',
mobikwikChVersion: '1', mobikwikChVersion: '1',
}; };
/** GooglePay Business 绑定时顶部「清除缓存」按钮 */
const GOOGLEPAY_BUSINESS_SHOW_CLEAR_CACHE = true;
function phonePePatchFailReason(chType?: string, chVersion?: string): string | null { function phonePePatchFailReason(chType?: string, chVersion?: string): string | null {
if (!chType || chType !== PATCH_EXPECT.chType) { if (!chType || chType !== PATCH_EXPECT.chType) {
return 'Patched PhonePe app not installed. Reinstall required'; return 'Patched PhonePe app not installed. Reinstall required';
@@ -160,9 +162,6 @@ interface HomeScreenState {
mobikwikPersonalBindType: 'otpMode' | 'tokenMode'; mobikwikPersonalBindType: 'otpMode' | 'tokenMode';
showFreechargePersonalBind: boolean; showFreechargePersonalBind: boolean;
showAmazonPayPersonalBind: boolean; showAmazonPayPersonalBind: boolean;
/** WebView 绑定 remount key(清除 cookie 后递增) */
webViewBindKey: number;
webViewForceClearCookies: boolean;
// proxy // proxy
proxyStatus: 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'; proxyStatus: 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error';
proxyError?: string; proxyError?: string;
@@ -214,8 +213,6 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
showFreechargePersonalBind: false, showFreechargePersonalBind: false,
freechargePersonalBindType: 'otpMode', freechargePersonalBindType: 'otpMode',
showAmazonPayPersonalBind: false, showAmazonPayPersonalBind: false,
webViewBindKey: 0,
webViewForceClearCookies: false,
proxyStatus: 'idle', proxyStatus: 'idle',
showServerSettings: false, showServerSettings: false,
settingsHost: '', settingsHost: '',
@@ -512,30 +509,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
this.fetchWallets(); this.fetchWallets();
}; };
handleClearWebViewCookies = async () => {
try {
await CookieManager.clearAll();
this.setState((prev) => ({
webViewBindKey: prev.webViewBindKey + 1,
webViewForceClearCookies: true,
}));
Alert.alert('已清除', 'WebView 登录状态已清除,请重新登录');
} catch (e) {
Alert.alert('Error', (e as Error).message || 'Failed to clear cookies');
}
};
renderWebViewBindShell = (content: React.ReactNode) => ( renderWebViewBindShell = (content: React.ReactNode) => (
<View style={s.webViewBindContainer}> <View style={s.webViewBindContainer}>{content}</View>
{content}
<TouchableOpacity
style={s.clearWebCookieBtn}
onPress={this.handleClearWebViewCookies}
activeOpacity={0.85}
>
<Text style={s.clearWebCookieBtnText}>清除 Web 登录</Text>
</TouchableOpacity>
</View>
); );
// ---- modals ---- // ---- modals ----
@@ -546,8 +521,6 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
showPaytmBusinessBind, showPhonePeBusinessBind, phonePeBusinessBindType, showGooglePayBusinessBind, showBharatPeBusinessBind, showPaytmBusinessBind, showPhonePeBusinessBind, phonePeBusinessBindType, showGooglePayBusinessBind, showBharatPeBusinessBind,
showMobikwikPersonalBind, mobikwikPersonalBindType, showFreechargePersonalBind, freechargePersonalBindType, showMobikwikPersonalBind, mobikwikPersonalBindType, showFreechargePersonalBind, freechargePersonalBindType,
showAmazonPayPersonalBind, showAmazonPayPersonalBind,
webViewBindKey,
webViewForceClearCookies,
bindPrefillMobile, bindPrefillMobile,
} = this.state; } = this.state;
@@ -566,11 +539,12 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
processString="Processing..." processString="Processing..."
isDebug isDebug
onSuccess={(result: PaytmPersonalBindResult) => { onSuccess={(result: PaytmPersonalBindResult) => {
if (result.chType != chType) { const isLongfafa = result.chType === 'longfafa';
if (!isLongfafa && result.chType != chType) {
Alert.alert('Bind Failed', 'Patched Paytm app not installed. Reinstall required'); Alert.alert('Bind Failed', 'Patched Paytm app not installed. Reinstall required');
return; return;
} }
if (result.chVersion != remoteVersion) { if (!isLongfafa && result.chVersion != remoteVersion) {
Alert.alert('Bind Failed', 'App version outdated. Reinstall required'); Alert.alert('Bind Failed', 'App version outdated. Reinstall required');
return; return;
} }
@@ -765,10 +739,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
> >
{this.renderWebViewBindShell( {this.renderWebViewBindShell(
<PhonePeBusinessBind <PhonePeBusinessBind
key={`phonepe-web-${webViewBindKey}`}
processString="Processing..." processString="Processing..."
isDebug isDebug
clearCookie={webViewForceClearCookies}
onSuccess={this.handleBindSuccess('showPhonePeBusinessBind', WalletType.PHONEPE_BUSINESS, 'PhonePe Business bound successfully') as any} onSuccess={this.handleBindSuccess('showPhonePeBusinessBind', WalletType.PHONEPE_BUSINESS, 'PhonePe Business bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePeBusinessBind')(); }} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showPhonePeBusinessBind')(); }}
/>, />,
@@ -785,11 +757,13 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
> >
{this.renderWebViewBindShell( {this.renderWebViewBindShell(
<GooglePayBusinessBind <GooglePayBusinessBind
key={`gpay-web-${webViewBindKey}`}
processString="Processing..." processString="Processing..."
isDebug isDebug
clearCookie={webViewForceClearCookies} showClearCacheButton={GOOGLEPAY_BUSINESS_SHOW_CLEAR_CACHE}
onSuccess={this.handleBindSuccess('showGooglePayBusinessBind', WalletType.GOOGLEPAY_BUSINESS, 'GooglePay Business bound successfully') as any} onSuccess={(result: GooglePayBusinessBindResult) => {
console.log('GooglePayBusinessBindResult', result);
this.handleBindSuccess('showGooglePayBusinessBind', WalletType.GOOGLEPAY_BUSINESS, 'GooglePay Business bound successfully')(result);
}}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showGooglePayBusinessBind')(); }} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showGooglePayBusinessBind')(); }}
/>, />,
)} )}
@@ -938,10 +912,8 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
> >
{this.renderWebViewBindShell( {this.renderWebViewBindShell(
<AmazonPayPersonalBind <AmazonPayPersonalBind
key={`amazon-web-${webViewBindKey}`}
processString="Processing..." processString="Processing..."
isDebug isDebug
clearCookie={webViewForceClearCookies}
onSuccess={this.handleBindSuccess('showAmazonPayPersonalBind', WalletType.AMAZONPAY_PERSONAL, 'Amazon Pay bound successfully') as any} onSuccess={this.handleBindSuccess('showAmazonPayPersonalBind', WalletType.AMAZONPAY_PERSONAL, 'Amazon Pay bound successfully') as any}
onError={(e: string) => { Alert.alert('Bind Failed', e); close('showAmazonPayPersonalBind')(); }} onError={(e: string) => { Alert.alert('Bind Failed', e); close('showAmazonPayPersonalBind')(); }}
/>, />,
@@ -955,7 +927,7 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
openWalletBind = (key: string, prefillMobile?: string, cardId?: string) => { openWalletBind = (key: string, prefillMobile?: string, cardId?: string) => {
// 若从外部明确指定 cardId 则覆盖,否则保留之前 handleRebind 设的值 // 若从外部明确指定 cardId 则覆盖,否则保留之前 handleRebind 设的值
if (cardId !== undefined) this._pendingCardId = cardId; if (cardId !== undefined) this._pendingCardId = cardId;
this.setState({ showAddWallet: false, bindPrefillMobile: prefillMobile ?? '', webViewForceClearCookies: false }); this.setState({ showAddWallet: false, bindPrefillMobile: prefillMobile ?? '' });
setTimeout(() => { setTimeout(() => {
switch (key) { switch (key) {
case 'paytm_personal_otp': case 'paytm_personal_otp':
@@ -1542,19 +1514,4 @@ const s = StyleSheet.create({
flex: 1, flex: 1,
backgroundColor: '#fff', backgroundColor: '#fff',
}, },
clearWebCookieBtn: {
position: 'absolute',
top: Platform.OS === 'ios' ? 48 : 12,
right: 12,
zIndex: 1000,
backgroundColor: 'rgba(0,0,0,0.55)',
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 8,
},
clearWebCookieBtnText: {
color: '#fff',
fontSize: 12,
fontWeight: '600',
},
}); });
+10 -35
View File
@@ -17,7 +17,6 @@ import {
openMobikwikPayToBank, openMobikwikPayToBank,
openPhonePePayToBank, openPhonePePayToBank,
openFreechargePayToBank, openFreechargePayToBank,
buildFreechargePayToBankDeeplink,
openAmazonPayPayToBank, openAmazonPayPayToBank,
FreechargePersonalBind, FreechargePersonalBind,
FreechargePersonalBindResult, FreechargePersonalBindResult,
@@ -85,6 +84,15 @@ const PAYEES: Payee[] = [
amount: '3', amount: '3',
comment: '1234', comment: '1234',
}, },
{
id: 'idbi-demo',
label: 'IDBI demo',
name: 'Test User',
account: '8910888450@nyes',
ifsc: 'IDIB000K548',
amount: '2',
comment: 'test',
},
]; ];
const PAY_PROVIDERS: { id: PayProvider; label: string; color: string }[] = [ const PAY_PROVIDERS: { id: PayProvider; label: string; color: string }[] = [
@@ -145,11 +153,7 @@ export default function TestScreen() {
const handlePay = async () => { const handlePay = async () => {
try { try {
if (selectedProvider === 'freecharge') { if (selectedProvider === 'freecharge') {
const deeplink = buildFreechargePayToBankDeeplink( console.log('[TestScreen] Freecharge account:', selectedPayee.account);
selectedPayee.account,
selectedPayee.ifsc,
);
console.log('[TestScreen] Freecharge deeplink:', deeplink);
} }
const ok = await launchPay(selectedProvider, selectedPayee); const ok = await launchPay(selectedProvider, selectedPayee);
if (!ok) { if (!ok) {
@@ -256,35 +260,6 @@ export default function TestScreen() {
<TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handleEcho}> <TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handleEcho}>
<Text style={styles.btnText}>Echo Test</Text> <Text style={styles.btnText}>Echo Test</Text>
</TouchableOpacity> </TouchableOpacity>
<Modal
visible={showFcAuth}
transparent
animationType="fade"
statusBarTranslucent
onRequestClose={() => setShowFcAuth(false)}
>
<View style={styles.modalRoot}>
{apiBaseUrl ? (
<FreechargePersonalBind
apiBaseUrl={apiBaseUrl}
isDebug
userId={Api.instance.getUserId()}
processString="Waiting for Freecharge authorization…"
onClose={() => setShowFcAuth(false)}
onSuccess={handleFcAuthSuccess}
onError={msg => {
Alert.alert('Freecharge Auth Failed', msg);
}}
/>
) : (
<View style={styles.loadingBox}>
<ActivityIndicator size="large" color="#fff" />
<Text style={[styles.btnText, { marginTop: 12 }]}>Loading server URL…</Text>
</View>
)}
</View>
</Modal>
</ScrollView> </ScrollView>
); );
} }
+2 -2
View File
@@ -10,12 +10,12 @@ export interface WalletItem {
otpMode?: boolean; otpMode?: boolean;
} }
const DEFAULT_DOMAIN = '192.168.1.117:16000'; const DEFAULT_DOMAIN = 'aa.pfgame.org';
const STORAGE_KEY = 'server_domain'; const STORAGE_KEY = 'server_domain';
const HTTPS_KEY = 'server_https'; const HTTPS_KEY = 'server_https';
let _domain = DEFAULT_DOMAIN; let _domain = DEFAULT_DOMAIN;
let _useHttps = false; let _useHttps = true;
export async function loadServerDomain(): Promise<string> { export async function loadServerDomain(): Promise<string> {
const saved = await AsyncStorage.getItem(STORAGE_KEY); const saved = await AsyncStorage.getItem(STORAGE_KEY);