feat(tng): 红包领取台双通道推送,并修复金额/按包分组

Hook Quake RPC 抓 Money Packet;解析 Money 对象金额;调试台按单个红包展示排行;支持 USB 本机与共享网段双地址转发。
This commit is contained in:
mars
2026-08-04 15:09:28 +08:00
parent e80f7f908c
commit 88a2b319f8
4 changed files with 751 additions and 88 deletions

View File

@@ -12,11 +12,18 @@ public final class AppConfig {
public static final boolean ENABLE_DEBUG_FORWARD = true;
/**
* 调试服务地址。
* 调试服务地址(可同时配置 USB 本机 + 局域网)
* USB + adb reverse: http://127.0.0.1:8765
* Wi-Fi: http://<电脑局域网IP>:8765
* 会向列表中每个地址各推送一次;不可达的静默失败。
*/
public static final String DEBUG_SERVER_URL = "http://127.0.0.1:8765";
public static final String[] DEBUG_SERVER_URLS = {
"http://127.0.0.1:8765",
"http://10.151.104.25:8765",
};
/** 兼容旧引用:取第一个调试地址 */
public static final String DEBUG_SERVER_URL = DEBUG_SERVER_URLS[0];
/** 是否定期唤醒监听列表中的 App保持进程 / Hook 加载) */
public static final boolean ENABLE_MONITORED_APP_KEEP_ALIVE = true;

View File

@@ -10,6 +10,7 @@ import com.miraclegarden.smsmessage.MessageInfo;
import org.json.JSONObject;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import okhttp3.Call;
import okhttp3.Callback;
@@ -21,6 +22,7 @@ import okhttp3.Response;
/**
* 将抓取到的消息转发到 PC 本地调试服务,便于浏览器查看。
* 支持同时向本机USB/adb reverse和局域网地址推送。
*/
public final class DebugForwarder {
@@ -51,6 +53,14 @@ public final class DebugForwarder {
return;
}
String[] urls = AppConfig.DEBUG_SERVER_URLS;
if (urls == null || urls.length == 0) {
if (onComplete != null) {
onComplete.run();
}
return;
}
try {
JSONObject json = new JSONObject();
json.put("source", source != null ? source : "unknown");
@@ -60,39 +70,49 @@ public final class DebugForwarder {
json.put("group", resolveGroup(title, messageInfo));
json.put("content", content != null ? content : "");
json.put("timestamp", timestamp);
final String body = json.toString();
final AtomicInteger pending = new AtomicInteger(urls.length);
Request request = new Request.Builder()
.url(AppConfig.DEBUG_SERVER_URL + "/api/debug/push")
.header("Content-Type", "application/json")
.post(RequestBody.create(json.toString(), JSON))
.build();
Log.d(TAG, "forwarding [" + source + "] " + messageInfo.getPackageName()
+ " -> " + AppConfig.DEBUG_SERVER_URL);
CLIENT.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, java.io.IOException e) {
Log.w(TAG, "forward failed [" + source + "]: " + e.getMessage());
if (onComplete != null) {
onComplete.run();
}
for (String baseUrl : urls) {
if (TextUtils.isEmpty(baseUrl)) {
finishOne(pending, onComplete);
continue;
}
final String target = baseUrl.endsWith("/")
? baseUrl.substring(0, baseUrl.length() - 1)
: baseUrl;
Request request = new Request.Builder()
.url(target + "/api/debug/push")
.header("Content-Type", "application/json")
.post(RequestBody.create(body, JSON))
.build();
@Override
public void onResponse(Call call, Response response) {
int code = response.code();
response.close();
if (code >= 200 && code < 300) {
Log.d(TAG, "forward ok [" + source + "] " + title);
} else {
Log.w(TAG, "forward http " + code + " [" + source + "] " + title);
Log.d(TAG, "forwarding [" + source + "] " + messageInfo.getPackageName()
+ " -> " + target);
CLIENT.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, java.io.IOException e) {
Log.w(TAG, "forward failed [" + source + "] -> " + target
+ ": " + e.getMessage());
finishOne(pending, onComplete);
}
if (onComplete != null) {
onComplete.run();
@Override
public void onResponse(Call call, Response response) {
int code = response.code();
response.close();
if (code >= 200 && code < 300) {
Log.d(TAG, "forward ok [" + source + "] -> " + target
+ " " + title);
} else {
Log.w(TAG, "forward http " + code + " [" + source + "] -> "
+ target + " " + title);
}
finishOne(pending, onComplete);
}
}
});
});
}
} catch (Exception e) {
Log.w(TAG, "forward build failed: " + e.getMessage());
if (onComplete != null) {
@@ -101,6 +121,12 @@ public final class DebugForwarder {
}
}
private static void finishOne(AtomicInteger pending, Runnable onComplete) {
if (pending.decrementAndGet() == 0 && onComplete != null) {
onComplete.run();
}
}
private static String resolveGroup(String title, MessageInfo messageInfo) {
if (!TextUtils.isEmpty(title)) {
return title.trim();