ykxmz 1.5.0:修复手表端 TLS 证书校验 + MTU 修复网络稳定性

被控端
- 修复 MTU 问题:夹 MSS + 路径 MTU 探测(公网可用率 48% -> 100%)
- 复用 HTTP 连接(免掉每次新建 TLS 的 30% 握手失败)
- 每分钟回头找局域网,自动切回快 400 倍的路径
- 画面心跳帧:静止时省流量,客户端仍知道流是活的
- 锁屏时给出可操作的提示

手表端
- 内置 GTS Root R4 / GlobalSign Root CA,修 SSLHandshakeException
- 连接错误翻译成人话(证书/时间/解析/超时分别提示)
- 经中转连上后用服务器报的地址刷新已配对记录
- 新增局域网连接页面、服务器延迟检测

服务器端
- 支持 chunked 请求体(修每 16 秒一次的连接错乱与大面积 502)
- 网络调优脚本 net-tune.sh(开机自动应用)
- 管理页:批量删除、网络体检、下载区
- 隧道改 HTTP/2 + 双连接

文档
- 许可协议 / 安装前必读 / 安装后须知(作者:小麦子)
This commit is contained in:
xmz7891
2026-10-06 19:01:05 +08:00
commit b62ac865ea
3195 changed files with 203292 additions and 0 deletions
@@ -0,0 +1,142 @@
package com.lanremote.watch;
import android.content.Context;
import android.content.SharedPreferences;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
/**
* 设备与连接信息持久化。
*
* 配对成功后保存令牌,下次打开直接从设备列表一键连接,无需再输配对码。
*/
public class DeviceStore {
private static final String PREFS = "lanremote";
private static final String KEY_DEVICES = "devices";
private static final String KEY_DEVICE_ID = "device_id";
private static final String KEY_DEVICE_NAME = "device_name";
private static final String KEY_LAST_HOST = "last_host";
private static final String KEY_LAST_PORT = "last_port";
private final SharedPreferences prefs;
public DeviceStore(Context context) {
this.prefs = context.getApplicationContext()
.getSharedPreferences(PREFS, Context.MODE_PRIVATE);
}
// ---------------- 本机标识 ----------------
public String deviceId() {
String id = prefs.getString(KEY_DEVICE_ID, "");
if (id == null || id.isEmpty()) {
id = "watch-" + UUID.randomUUID().toString().replace("-", "").substring(0, 16);
prefs.edit().putString(KEY_DEVICE_ID, id).apply();
}
return id;
}
public String deviceName() {
String name = prefs.getString(KEY_DEVICE_NAME, "");
if (name == null || name.isEmpty()) {
name = android.os.Build.MODEL;
if (name == null || name.trim().isEmpty()) {
name = "手表";
}
prefs.edit().putString(KEY_DEVICE_NAME, name).apply();
}
return name;
}
public void setDeviceName(String name) {
prefs.edit().putString(KEY_DEVICE_NAME, name == null ? "手表" : name.trim()).apply();
}
// ---------------- 上次连接 ----------------
public String lastHost() {
return prefs.getString(KEY_LAST_HOST, "");
}
public int lastPort() {
return prefs.getInt(KEY_LAST_PORT, RemoteClient.DEFAULT_PORT);
}
public void setLastEndpoint(String host, int port) {
prefs.edit().putString(KEY_LAST_HOST, host).putInt(KEY_LAST_PORT, port).apply();
}
// ---------------- 已配对设备 ----------------
public List<Map<String, Object>> devices() {
return readDevices();
}
private List<Map<String, Object>> readDevices() {
String raw = prefs.getString(KEY_DEVICES, "");
if (raw == null || raw.isEmpty()) {
return new ArrayList<Map<String, Object>>();
}
try {
Object parsed = Json.parse(raw);
if (parsed instanceof List) {
List<Map<String, Object>> result = new ArrayList<Map<String, Object>>();
for (Object item : (List<?>) parsed) {
Map<String, Object> map = Json.asMap(item);
if (map != null) {
result.add(map);
}
}
return result;
}
} catch (RuntimeException ignored) {
// 存储损坏时当作空列表,不崩溃
}
return new ArrayList<Map<String, Object>>();
}
private void writeDevices(List<Map<String, Object>> devices) {
prefs.edit().putString(KEY_DEVICES, Json.write(devices)).apply();
}
/** 保存或更新一台设备(按 key = 地址:端口:设备ID 去重)。 */
public void saveDevice(String key, String label, String host, int port, String token) {
List<Map<String, Object>> devices = readDevices();
List<Map<String, Object>> updated = new ArrayList<Map<String, Object>>();
for (Map<String, Object> device : devices) {
if (!key.equals(Json.str(device, "key", ""))) {
updated.add(device);
}
}
updated.add(0, Json.obj(
"key", key,
"label", label,
"host", host,
"port", port,
"token", token,
"savedAt", System.currentTimeMillis()));
while (updated.size() > 12) {
updated.remove(updated.size() - 1);
}
writeDevices(updated);
}
public void removeDevice(String key) {
List<Map<String, Object>> devices = readDevices();
List<Map<String, Object>> updated = new ArrayList<Map<String, Object>>();
for (Map<String, Object> device : devices) {
if (!key.equals(Json.str(device, "key", ""))) {
updated.add(device);
}
}
writeDevices(updated);
}
public static String deviceKey(String host, int port, String deviceId) {
return host + ":" + port + ":" + deviceId;
}
}