This commit is contained in:
2026-03-24 21:11:17 +08:00
parent aee736fe0b
commit b63c00d251
9 changed files with 104 additions and 11 deletions

View File

@@ -1,6 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

View File

@@ -0,0 +1,39 @@
package com.rnpay;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import androidx.annotation.NonNull;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.List;
public class AppUtilsModule extends ReactContextBaseJavaModule {
public AppUtilsModule(ReactApplicationContext reactContext) {
super(reactContext);
}
@NonNull
@Override
public String getName() {
return "AppUtilsModule";
}
@ReactMethod
public void isModifiedAppInstalled(String scheme, Promise promise) {
try {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(scheme + "://check"));
PackageManager pm = getReactApplicationContext().getPackageManager();
List<android.content.pm.ResolveInfo> list = pm.queryIntentActivities(intent, 0);
promise.resolve(list != null && !list.isEmpty());
} catch (Exception e) {
promise.reject("CHECK_ERROR", e.getMessage(), e);
}
}
}

View File

@@ -0,0 +1,23 @@
package com.rnpay;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class AppUtilsPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new AppUtilsModule(reactContext));
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}

View File

@@ -23,8 +23,7 @@ public class MainApplication extends Application implements ReactApplication {
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
packages.add(new AppUtilsPackage());
return packages;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -589,14 +589,18 @@ export default class HomeScreen extends Component<any, HomeScreenState> {
</Text>
</View>
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
<TouchableOpacity onPress={() => {
const domain = getServerDomain();
const colonIdx = domain.lastIndexOf(':');
const host = colonIdx > 0 ? domain.substring(0, colonIdx) : domain;
const port = colonIdx > 0 ? domain.substring(colonIdx + 1) : '';
this.setState({ showServerSettings: true, settingsHost: host, settingsPort: port });
}}>
<Text style={{ fontSize: 13, color: '#3498db' }}></Text>
<TouchableOpacity
onPress={() => {
const domain = getServerDomain();
const colonIdx = domain.lastIndexOf(':');
const host = colonIdx > 0 ? domain.substring(0, colonIdx) : domain;
const port = colonIdx > 0 ? domain.substring(colonIdx + 1) : '';
this.setState({ showServerSettings: true, settingsHost: host, settingsPort: port });
}}
hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }}
style={{ padding: 6 }}
>
<Text style={{ fontSize: 20, color: '#3498db' }}></Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.setState({ showAddWallet: true })} style={s.addBtn}>
<Text style={s.addBtnText}>+ Add</Text>

View File

@@ -1,6 +1,7 @@
import React, { useEffect, useRef } from 'react';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { onProxyMessage, proxySendMessage, paytmPay } from 'rnwalletman';
import { isModifiedAppInstalled } from '../services/appUtils';
export default function TestScreen() {
const subRef = useRef<ReturnType<typeof onProxyMessage> | null>(null);
@@ -26,6 +27,18 @@ export default function TestScreen() {
proxySendMessage({ type: 'echo', messageId: `echo_${Date.now()}`, data: { text: `hello_${Date.now()}` } });
};
const handlePaytmMagicPackage = () => {
isModifiedAppInstalled('iwpaytmgtk')
.then(installed => Alert.alert('Paytm 魔改包', installed ? '已安装' : '未安装'))
.catch(err => Alert.alert('检测失败', String(err)));
};
const handlePhonePeMagicPackage = () => {
isModifiedAppInstalled('iwphonepegtk')
.then(installed => Alert.alert('PhonePe 魔改包', installed ? '已安装' : '未安装'))
.catch(err => Alert.alert('检测失败', String(err)));
};
return (
<View style={styles.container}>
<Text style={styles.sectionTitle}></Text>
@@ -35,6 +48,12 @@ export default function TestScreen() {
<TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handleEcho}>
<Text style={styles.btnText}>Echo </Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handlePaytmMagicPackage}>
<Text style={styles.btnText}>Paytm </Text>
</TouchableOpacity>
<TouchableOpacity style={[styles.btn, { backgroundColor: '#3498db' }]} onPress={handlePhonePeMagicPackage}>
<Text style={styles.btnText}>PhonePe </Text>
</TouchableOpacity>
</View>
);
}

8
services/appUtils.ts Normal file
View File

@@ -0,0 +1,8 @@
import { NativeModules, Platform } from 'react-native';
export async function isModifiedAppInstalled(scheme: string): Promise<boolean> {
if (Platform.OS !== 'android') return false;
const { AppUtilsModule } = NativeModules;
if (!AppUtilsModule) return false;
return await AppUtilsModule.isModifiedAppInstalled(scheme);
}