From 2d32653f5b388ff6f23156f6388f5fbbd060716e Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:01:25 +0900 Subject: [PATCH 01/18] update core --- buildScript/lib/core/get_source_env.sh | 2 +- libcore/go.mod | 2 +- libcore/go.sum | 4 ++-- nb4a.properties | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/buildScript/lib/core/get_source_env.sh b/buildScript/lib/core/get_source_env.sh index 886a8f05d..2c4bbef03 100644 --- a/buildScript/lib/core/get_source_env.sh +++ b/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="b250e570fe32ff8fd2e34f29afb8e87f83d3cab3" +export COMMIT_SING_BOX="3330efd23adeb2d7453da4e99c2fd4f06c76e9e7" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/libcore/go.mod b/libcore/go.mod index a46e0e1d1..a314c56d9 100644 --- a/libcore/go.mod +++ b/libcore/go.mod @@ -43,7 +43,7 @@ require ( github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/socket v0.5.1 // indirect github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect - github.com/metacubex/utls v1.8.0 // indirect + github.com/metacubex/utls v1.8.2 // indirect github.com/mholt/acmez/v3 v3.1.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect diff --git a/libcore/go.sum b/libcore/go.sum index aeb360f85..593788223 100644 --- a/libcore/go.sum +++ b/libcore/go.sum @@ -61,8 +61,8 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc= github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= -github.com/metacubex/utls v1.8.0 h1:mSYi6FMnmc5riARl5UZDmWVy710z+P5b7xuGW0lV9ac= -github.com/metacubex/utls v1.8.0/go.mod h1:FdjYzVfCtgtna19hX0ER1Xsa5uJInwdQ4IcaaI98lEQ= +github.com/metacubex/utls v1.8.2 h1:d7KalMZ5hnOJ6lThMz8Ykd+5dvmXH3Eoeyfv2jUuG3w= +github.com/metacubex/utls v1.8.2/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0= diff --git a/nb4a.properties b/nb4a.properties index 3fda6cf07..09d606d8d 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a VERSION_NAME=1.4.0 -PRE_VERSION_NAME=pre-1.4.1-20251007-1 +PRE_VERSION_NAME=pre-1.4.1-20251015-1 VERSION_CODE=44 From 596b9ebfbb5394b5b6092a7c07cb7202f1fe511b Mon Sep 17 00:00:00 2001 From: xymopen_Official <8053733+xymopen@users.noreply.github.com> Date: Tue, 21 Oct 2025 20:31:41 +0800 Subject: [PATCH 02/18] fix: Certain single-label domain names can only be resolved by `InetAddress.getAllByName()` but not `Network.getAllByName()` (#1050) --- .../java/moe/matsuri/nb4a/net/LocalResolverImpl.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt b/app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt index 7de35b44e..9b125aeea 100644 --- a/app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt +++ b/app/src/main/java/moe/matsuri/nb4a/net/LocalResolverImpl.kt @@ -128,11 +128,11 @@ object LocalResolverImpl : LocalDNSTransport { // 老版本系统,继续用阻塞的 InetAddress try { val u = SagerNet.underlyingNetwork - val answer = if (u != null) { - u.getAllByName(domain) - } else { - InetAddress.getAllByName(domain) - } + val answer = try { + u?.getAllByName(domain) + } catch (e: UnknownHostException) { + null + } ?: InetAddress.getAllByName(domain) if (answer != null) { ctx.success(answer.mapNotNull { it.hostAddress }.joinToString("\n")) } else { From 110f3b21b2e77b1ad45abf21c9fa3d8f1beff30a Mon Sep 17 00:00:00 2001 From: mak7im01 <99025360+mak7im01@users.noreply.github.com> Date: Tue, 21 Oct 2025 15:32:11 +0300 Subject: [PATCH 03/18] Update Russian translation (#1052) Added new lines with translation --- app/src/main/res/values-ru/strings.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 8d47da455..274652f20 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -75,6 +75,9 @@ Настройки цепочки Введено символов: %1$d из %2$d Превышено ограничение на количество символов (%1$d из %2$d) +Обновления не найдены. +Проверить наличие обновлений предварительной версии +Проверить наличие обновлений релизнойной версии Циклическая ссылка Маршрут не может содержать сам себя. Очистить журнал @@ -250,6 +253,7 @@ Трафик Подсказка о соединении с лимитным тарифным планом Подсказывать системе, что VPN следует рассматривать как сеть с лимитным тарифным планом +Свернуть Отсутствующий плагин Переместить Новое уведомление @@ -319,6 +323,7 @@ Транспрокси-порт Предпочитать Текст "%1$s" скопирован в буфер обмена +Это приложение является предварительной версией и может содержать множество проблем. Если вы не хотите тестировать его, скачайте релизную версию с GitHub! Конфигурация профиля Пожалуйста, выберите профиль Импортировать профиль @@ -342,6 +347,8 @@ Удаленный DNS Удалить дубликаты серверов Сбросить соединения +Восстановить настройки по умолчанию +Восстановить настройки по умолчанию, такие данные, как узлы и группы, будут сохранены. Для полной очистки данных, очистите данные приложения непосредственно в системных настройках. Определить адрес назначения Если адрес назначения является доменом, то он передается в соответствии с правилом IPv6. Создать маршрут @@ -453,6 +460,8 @@ Есть несохраненные изменения. Сохранить? Обновить все подписки Обновить подписку текущей группы +Текущая версия: %1$s\nДоступная версия: %2$s\nХотите загрузить её? +Доступна новая версия Обновить настройки Прокси-сервер не подключен, вы уверены, что хотите продолжить обновление? Обновлять только при подключении From 4326aab16d53635326ac5bc5065f8eb30278c1b9 Mon Sep 17 00:00:00 2001 From: starifly <2003879+starifly@users.noreply.github.com> Date: Mon, 20 Oct 2025 22:14:56 +0800 Subject: [PATCH 04/18] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=20grpc=20case?= =?UTF-8?q?=20=E7=BC=BA=E5=B0=91=20break=20=E5=AF=BC=E8=87=B4=E5=BA=8F?= =?UTF-8?q?=E5=88=97=E5=8C=96=E6=95=B0=E6=8D=AE=E9=94=99=E4=B9=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java index 61a2a7323..b30925712 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java @@ -140,6 +140,7 @@ public void serialize(ByteBufferOutput output) { } case "grpc": { output.writeString(path); + break; } case "httpupgrade": { output.writeString(host); @@ -200,6 +201,7 @@ public void deserialize(ByteBufferInput input) { } case "grpc": { path = input.readString(); + break; } case "httpupgrade": { host = input.readString(); From aa275d5e100c909ae4e815ab168f86f6e06c24ef Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Tue, 21 Oct 2025 21:42:44 +0900 Subject: [PATCH 05/18] update preview version --- app/src/main/res/values-fa/strings.xml | 4 ---- app/src/main/res/values-ru/strings.xml | 2 +- libcore/go.mod | 2 +- libcore/go.sum | 4 ++-- nb4a.properties | 2 +- 5 files changed, 5 insertions(+), 9 deletions(-) diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index bb9291cb2..de972072d 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -208,7 +208,6 @@ Trojan Go Mieru Naïve - Ping Tunnel Hysteria SSH WireGuard @@ -521,10 +520,7 @@ فعال کردن ECH فعال کردن ECH تنظیمات ECH - فعال کردن پشتیبانی از امضای مجوز post-quantum همتا - اندازه تطبیقی ​​رکوردهای TLS را غیرفعال می‌کند پیکربندی ECH - اگر فعال باشد، همیشه از بزرگترین اندازه رکورد TLS ممکن استفاده می‌شود. در صورت غیرفعال کردن، اندازه رکوردهای TLS ممکن است در تلاش برای بهبود تاخیر تنظیم شود. میزبان HTTPUpgrade مسیر HTTPUpgrade به‌روزرسانی اشتراک این گروه diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 274652f20..c45db7492 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -460,7 +460,7 @@ Есть несохраненные изменения. Сохранить? Обновить все подписки Обновить подписку текущей группы -Текущая версия: %1$s\nДоступная версия: %2$s\nХотите загрузить её? +Текущая версия: %1$s\nДоступная версия: %2$s\nХотите загрузить её? Доступна новая версия Обновить настройки Прокси-сервер не подключен, вы уверены, что хотите продолжить обновление? diff --git a/libcore/go.mod b/libcore/go.mod index a314c56d9..0afc344d6 100644 --- a/libcore/go.mod +++ b/libcore/go.mod @@ -12,7 +12,7 @@ require ( github.com/sagernet/sing v0.7.12 github.com/sagernet/sing-box v1.0.0 // replaced github.com/sagernet/sing-tun v0.7.2 - github.com/ulikunitz/xz v0.5.11 + github.com/ulikunitz/xz v0.5.15 golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da golang.org/x/sys v0.35.0 ) diff --git a/libcore/go.sum b/libcore/go.sum index 593788223..acf71ab3b 100644 --- a/libcore/go.sum +++ b/libcore/go.sum @@ -122,8 +122,8 @@ github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXl github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= -github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= +github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/vishvananda/netns v0.0.5 h1:DfiHV+j8bA32MFM7bfEunvT8IAqQ/NzSJHtcmW5zdEY= github.com/vishvananda/netns v0.0.5/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/zeebo/assert v1.1.0 h1:hU1L1vLTHsnO8x8c9KAR5GmM5QscxHg5RNU5z5qbUWY= diff --git a/nb4a.properties b/nb4a.properties index 09d606d8d..0701e3f13 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a VERSION_NAME=1.4.0 -PRE_VERSION_NAME=pre-1.4.1-20251015-1 +PRE_VERSION_NAME=pre-1.4.1-20251021-1 VERSION_CODE=44 From b39ac9a8f0eaa35978aad3d31e94aea2fd5c2420 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Tue, 21 Oct 2025 21:58:37 +0900 Subject: [PATCH 06/18] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E8=80=81?= =?UTF-8?q?=E7=89=88=E6=9C=AC=20grpc=20=E6=95=B0=E6=8D=AE=E8=AF=BB?= =?UTF-8?q?=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sagernet/fmt/v2ray/StandardV2RayBean.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java index b30925712..2f32c50f4 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java @@ -112,7 +112,7 @@ public void initializeDefaultValues() { @Override public void serialize(ByteBufferOutput output) { - output.writeInt(3); + output.writeInt(4); super.serialize(output); output.writeString(uuid); output.writeString(encryption); @@ -133,7 +133,8 @@ public void serialize(ByteBufferOutput output) { output.writeString(earlyDataHeaderName); break; } - case "http": { + case "http": + case "httpupgrade": { output.writeString(host); output.writeString(path); break; @@ -142,11 +143,6 @@ public void serialize(ByteBufferOutput output) { output.writeString(path); break; } - case "httpupgrade": { - output.writeString(host); - output.writeString(path); - - } } output.writeString(security); @@ -194,19 +190,21 @@ public void deserialize(ByteBufferInput input) { earlyDataHeaderName = input.readString(); break; } - case "http": { + case "http": + case "httpupgrade": { host = input.readString(); path = input.readString(); break; } case "grpc": { path = input.readString(); + if (version < 4) { + // 解决老版本数据的读取问题 + input.readString(); + input.readString(); + } break; } - case "httpupgrade": { - host = input.readString(); - path = input.readString(); - } } security = input.readString(); From e6071e35f235debca1cdd72518d58a467800b226 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Thu, 23 Oct 2025 11:23:09 +0900 Subject: [PATCH 07/18] update core --- buildScript/lib/core/get_source_env.sh | 2 +- libcore/go.mod | 6 +++--- libcore/go.sum | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/buildScript/lib/core/get_source_env.sh b/buildScript/lib/core/get_source_env.sh index 2c4bbef03..5c7bc0be9 100644 --- a/buildScript/lib/core/get_source_env.sh +++ b/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="3330efd23adeb2d7453da4e99c2fd4f06c76e9e7" +export COMMIT_SING_BOX="98c74d272a6b61abc120ff8163ab2ead0bb0ce96" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/libcore/go.mod b/libcore/go.mod index 0afc344d6..daaf48eee 100644 --- a/libcore/go.mod +++ b/libcore/go.mod @@ -11,7 +11,7 @@ require ( github.com/sagernet/quic-go v0.52.0-sing-box-mod.2 github.com/sagernet/sing v0.7.12 github.com/sagernet/sing-box v1.0.0 // replaced - github.com/sagernet/sing-tun v0.7.2 + github.com/sagernet/sing-tun v0.7.3 github.com/ulikunitz/xz v0.5.15 golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da golang.org/x/sys v0.35.0 @@ -42,8 +42,8 @@ require ( github.com/logrusorgru/aurora v2.0.3+incompatible // indirect github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/socket v0.5.1 // indirect - github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 // indirect - github.com/metacubex/utls v1.8.2 // indirect + github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 // indirect + github.com/metacubex/utls v1.8.3 // indirect github.com/mholt/acmez/v3 v3.1.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect diff --git a/libcore/go.sum b/libcore/go.sum index acf71ab3b..b516d865b 100644 --- a/libcore/go.sum +++ b/libcore/go.sum @@ -59,10 +59,10 @@ github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 h1:A1Cq6Ysb0GM0 github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42/go.mod h1:BB4YCPDOzfy7FniQ/lxuYQ3dgmM2cZumHbK8RpTjN2o= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4 h1:j1VRTiC9JLR4nUbSikx9OGdu/3AgFDqgcLj4GoqyQkc= -github.com/metacubex/tfo-go v0.0.0-20250516165257-e29c16ae41d4/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= -github.com/metacubex/utls v1.8.2 h1:d7KalMZ5hnOJ6lThMz8Ykd+5dvmXH3Eoeyfv2jUuG3w= -github.com/metacubex/utls v1.8.2/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= +github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 h1:Ui+/2s5Qz0lSnDUBmEL12M5Oi/PzvFxGTNohm8ZcsmE= +github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= +github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= +github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0= @@ -101,8 +101,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnq github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.7.2 h1:uJkAZM0KBqIYzrq077QGqdvj/+4i/pMOx6Pnx0jYqAs= -github.com/sagernet/sing-tun v0.7.2/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= +github.com/sagernet/sing-tun v0.7.3 h1:MFnAir+l24ElEyxdfwtY8mqvUUL9nPnL9TDYLkOmVes= +github.com/sagernet/sing-tun v0.7.3/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= From 963418f9e33f0264cd5958b76bab85e79c96cd49 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Sun, 26 Oct 2025 13:28:30 +0900 Subject: [PATCH 08/18] Add permission for some CN ROMs --- app/src/main/AndroidManifest.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f969dea48..def29c24c 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,7 +22,9 @@ + tools:ignore="PackageVisibilityPolicy" /> + + From ec76238dd1f9522675d1e1be89df7e00648f8856 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:29:08 +0900 Subject: [PATCH 09/18] Add a hint for an empty app list --- .../sagernet/ui/AppListActivity.kt | 32 ++++++++++++------- .../sagernet/ui/AppManagerActivity.kt | 15 ++++++++- app/src/main/res/layout/layout_app_list.xml | 4 +++ .../res/layout/layout_app_placeholder.xml | 25 +++++++++++++++ app/src/main/res/layout/layout_apps.xml | 4 +++ app/src/main/res/values-zh-rCN/strings.xml | 2 ++ app/src/main/res/values/strings.xml | 2 ++ 7 files changed, 72 insertions(+), 12 deletions(-) create mode 100644 app/src/main/res/layout/layout_app_placeholder.xml diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt index 107b27e3d..86eb9a705 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt @@ -2,7 +2,6 @@ package io.nekohasekai.sagernet.ui import android.content.Intent import android.content.pm.ApplicationInfo -import android.content.pm.PackageInfo import android.content.pm.PackageManager import android.graphics.drawable.Drawable import android.os.Bundle @@ -45,6 +44,11 @@ import kotlin.coroutines.coroutineContext class AppListActivity : ThemedActivity() { companion object { private const val SWITCH = "switch" + + private val cachedApps + get() = PackageCache.installedPackages.toMutableMap().apply { + remove(BuildConfig.APPLICATION_ID) + } } private class ProxiedApp( @@ -96,7 +100,7 @@ class AppListActivity : ThemedActivity() { var filteredApps = apps suspend fun reload() { - apps = getCachedApps().mapNotNull { (packageName, packageInfo) -> + apps = cachedApps.mapNotNull { (packageName, packageInfo) -> coroutineContext[Job]!!.ensureActive() packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) } }.sortedWith(compareBy({ !isProxiedApp(it) }, { it.name.toString() })) @@ -156,7 +160,7 @@ class AppListActivity : ThemedActivity() { private fun initProxiedUids(str: String = DataStore.routePackages) { proxiedUids.clear() - val apps = getCachedApps() + val apps = cachedApps for (line in str.lineSequence()) { val app = (apps[line] ?: continue) val uid = app.applicationInfo?.uid ?: continue @@ -174,14 +178,12 @@ class AppListActivity : ThemedActivity() { val adapter = binding.list.adapter as AppsAdapter withContext(Dispatchers.IO) { adapter.reload() } adapter.filter.filter(binding.search.text?.toString() ?: "") - binding.list.crossFadeFrom(loading) - } - } - - fun getCachedApps(): MutableMap { - val packages = PackageCache.installedPackages - return packages.toMutableMap().apply { - remove(BuildConfig.APPLICATION_ID) + if (apps.isEmpty()) { + binding.list.visibility = View.GONE + binding.appPlaceholder.root.crossFadeFrom(loading) + } else { + binding.list.crossFadeFrom(loading) + } } } @@ -191,6 +193,14 @@ class AppListActivity : ThemedActivity() { binding = LayoutAppListBinding.inflate(layoutInflater) setContentView(binding.root) + binding.appPlaceholder.openSettings.setOnClickListener { + val intent = + Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = android.net.Uri.fromParts("package", packageName, null) + } + startActivity(intent) + } + setSupportActionBar(binding.toolbar) supportActionBar?.apply { setTitle(R.string.select_apps) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt index e212cbe9c..e5eb258ce 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt @@ -184,7 +184,12 @@ class AppManagerActivity : ThemedActivity() { val adapter = binding.list.adapter as AppsAdapter withContext(Dispatchers.IO) { adapter.reload() } adapter.filter.filter(binding.search.text?.toString() ?: "") - binding.list.crossFadeFrom(loading) + if (apps.isEmpty()) { + binding.list.visibility = View.GONE + binding.appPlaceholder.root.crossFadeFrom(loading) + } else { + binding.list.crossFadeFrom(loading) + } } } @@ -194,6 +199,14 @@ class AppManagerActivity : ThemedActivity() { binding = LayoutAppsBinding.inflate(layoutInflater) setContentView(binding.root) + binding.appPlaceholder.openSettings.setOnClickListener { + val intent = + Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply { + data = android.net.Uri.fromParts("package", packageName, null) + } + startActivity(intent) + } + setSupportActionBar(binding.toolbar) supportActionBar?.apply { setTitle(R.string.proxied_apps) diff --git a/app/src/main/res/layout/layout_app_list.xml b/app/src/main/res/layout/layout_app_list.xml index 45432fa45..4128a887f 100644 --- a/app/src/main/res/layout/layout_app_list.xml +++ b/app/src/main/res/layout/layout_app_list.xml @@ -116,4 +116,8 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:listitem="@layout/layout_apps_item" /> + + diff --git a/app/src/main/res/layout/layout_app_placeholder.xml b/app/src/main/res/layout/layout_app_placeholder.xml new file mode 100644 index 000000000..456ac8a2b --- /dev/null +++ b/app/src/main/res/layout/layout_app_placeholder.xml @@ -0,0 +1,25 @@ + + + + + + + diff --git a/app/src/main/res/layout/layout_apps.xml b/app/src/main/res/layout/layout_apps.xml index 1dd32b265..e648248a2 100644 --- a/app/src/main/res/layout/layout_apps.xml +++ b/app/src/main/res/layout/layout_apps.xml @@ -153,4 +153,8 @@ app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:listitem="@layout/layout_apps_item" /> + + diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index cd92b7e10..29ee46388 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -495,4 +495,6 @@ 恢复默认设置 恢复默认设置,但节点、分组等数据将保留。如需完全清除数据,请在系统设置中直接清除应用数据。 最小化 + 无法读取已安装的应用。\n这通常是由于系统限制了应用的读取权限(例如某些中国厂商系统)。\n请在系统设置中授予权限。 + 打开系统设置 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a30c70328..cd2701bca 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -575,4 +575,6 @@ Restore default settings Restore default settings, but data such as nodes and groups will be retained. To completely clear data, clear application data directly in the system settings. Minimize + Unable to read installed apps.\nThis is usually because the system has restricted app read permissions.\nPlease grant permissions in the system settings. + Open System Settings \ No newline at end of file From 731064cf88d9bbf0fa89c0fbccd84df8f350806c Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:55:29 +0900 Subject: [PATCH 10/18] Reload package cache when entering the app list --- .../java/io/nekohasekai/sagernet/ui/AppListActivity.kt | 1 + .../io/nekohasekai/sagernet/ui/AppManagerActivity.kt | 1 + .../java/io/nekohasekai/sagernet/utils/PackageCache.kt | 9 --------- 3 files changed, 2 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt index 86eb9a705..7f3892430 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppListActivity.kt @@ -100,6 +100,7 @@ class AppListActivity : ThemedActivity() { var filteredApps = apps suspend fun reload() { + PackageCache.reload() apps = cachedApps.mapNotNull { (packageName, packageInfo) -> coroutineContext[Job]!!.ensureActive() packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) } diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt index e5eb258ce..effbc5823 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AppManagerActivity.kt @@ -106,6 +106,7 @@ class AppManagerActivity : ThemedActivity() { var filteredApps = apps suspend fun reload() { + PackageCache.reload() apps = cachedApps.mapNotNull { (packageName, packageInfo) -> coroutineContext[Job]!!.ensureActive() packageInfo.applicationInfo?.let { ProxiedApp(packageManager, it, packageName) } diff --git a/app/src/main/java/io/nekohasekai/sagernet/utils/PackageCache.kt b/app/src/main/java/io/nekohasekai/sagernet/utils/PackageCache.kt index a2e09ef58..c5e9370c7 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/utils/PackageCache.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/utils/PackageCache.kt @@ -67,15 +67,6 @@ object PackageCache { operator fun get(uid: Int) = uidMap[uid] operator fun get(packageName: String) = packageMap[packageName] - suspend fun awaitLoad() { - if (::packageMap.isInitialized) { - return - } - loaded.withLock { - // just await - } - } - fun awaitLoadSync() { if (::packageMap.isInitialized) { return From 6c0b8dd450106895a6fc9dd817537373e689bad7 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Sun, 26 Oct 2025 14:55:39 +0900 Subject: [PATCH 11/18] update preview version --- nb4a.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nb4a.properties b/nb4a.properties index 0701e3f13..c032774fd 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a VERSION_NAME=1.4.0 -PRE_VERSION_NAME=pre-1.4.1-20251021-1 +PRE_VERSION_NAME=pre-1.4.1-20251026-2 VERSION_CODE=44 From 2c2b6dc1a839d24b08f3d8f384e4a88e84f1bfd2 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:22:25 +0900 Subject: [PATCH 12/18] 1.4.1 --- buildScript/lib/core/get_source_env.sh | 2 +- libcore/go.mod | 4 ++-- libcore/go.sum | 8 ++++---- nb4a.properties | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/buildScript/lib/core/get_source_env.sh b/buildScript/lib/core/get_source_env.sh index 5c7bc0be9..d3851c00c 100644 --- a/buildScript/lib/core/get_source_env.sh +++ b/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="98c74d272a6b61abc120ff8163ab2ead0bb0ce96" +export COMMIT_SING_BOX="9beb42f553ebdf575f497c01c33ffa7b6df17efb" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/libcore/go.mod b/libcore/go.mod index daaf48eee..12b9d8298 100644 --- a/libcore/go.mod +++ b/libcore/go.mod @@ -8,8 +8,8 @@ require ( github.com/matsuridayo/libneko v1.0.0 // replaced github.com/miekg/dns v1.1.67 github.com/oschwald/maxminddb-golang v1.13.1 - github.com/sagernet/quic-go v0.52.0-sing-box-mod.2 - github.com/sagernet/sing v0.7.12 + github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 + github.com/sagernet/sing v0.7.13 github.com/sagernet/sing-box v1.0.0 // replaced github.com/sagernet/sing-tun v0.7.3 github.com/ulikunitz/xz v0.5.15 diff --git a/libcore/go.sum b/libcore/go.sum index b516d865b..55e9d7d7c 100644 --- a/libcore/go.sum +++ b/libcore/go.sum @@ -86,11 +86,11 @@ github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZN github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNenDW2zaXr8I= github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= -github.com/sagernet/quic-go v0.52.0-sing-box-mod.2 h1:QTPr/ptUPsgregVfFXReBFrhv/8U83deZG8urQ7pWYI= -github.com/sagernet/quic-go v0.52.0-sing-box-mod.2/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= +github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 h1:ySqffGm82rPqI1TUPqmtHIYd12pfEGScygnOxjTL56w= +github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing v0.7.12 h1:MpMbO56crPRZTbltoj1wGk4Xj9+GiwH1wTO4s3fz1EA= -github.com/sagernet/sing v0.7.12/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing v0.7.13 h1:XNYgd8e3cxMULs/LLJspdn/deHrnPWyrrglNHeCUAYM= +github.com/sagernet/sing v0.7.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb h1:5Wx3XeTiKrrrcrAky7Hc1bO3CGxrvho2Vu5b/adlEIM= diff --git a/nb4a.properties b/nb4a.properties index c032774fd..aab000694 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a -VERSION_NAME=1.4.0 +VERSION_NAME=1.4.1 PRE_VERSION_NAME=pre-1.4.1-20251026-2 -VERSION_CODE=44 +VERSION_CODE=45 From 894933b483353865fac5348dccd4e82071bd5a61 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Mon, 2 Feb 2026 14:57:53 +0900 Subject: [PATCH 13/18] update core --- buildScript/lib/core/get_source_env.sh | 2 +- libcore/go.mod | 12 ++++----- libcore/go.sum | 34 +++++++++----------------- 3 files changed, 19 insertions(+), 29 deletions(-) diff --git a/buildScript/lib/core/get_source_env.sh b/buildScript/lib/core/get_source_env.sh index d3851c00c..2a369106f 100644 --- a/buildScript/lib/core/get_source_env.sh +++ b/buildScript/lib/core/get_source_env.sh @@ -1,2 +1,2 @@ -export COMMIT_SING_BOX="9beb42f553ebdf575f497c01c33ffa7b6df17efb" +export COMMIT_SING_BOX="aed32ee3066cdbc7d471e3e0415c5134088962df" export COMMIT_LIBNEKO="1c47a3af71990a7b2192e03292b4d246c308ef0b" diff --git a/libcore/go.mod b/libcore/go.mod index 12b9d8298..ddf89a1f6 100644 --- a/libcore/go.mod +++ b/libcore/go.mod @@ -9,9 +9,9 @@ require ( github.com/miekg/dns v1.1.67 github.com/oschwald/maxminddb-golang v1.13.1 github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 - github.com/sagernet/sing v0.7.13 + github.com/sagernet/sing v0.7.18 github.com/sagernet/sing-box v1.0.0 // replaced - github.com/sagernet/sing-tun v0.7.3 + github.com/sagernet/sing-tun v0.7.10 github.com/ulikunitz/xz v0.5.15 golang.org/x/mobile v0.0.0-20231108233038-35478a0c49da golang.org/x/sys v0.35.0 @@ -43,7 +43,7 @@ require ( github.com/mdlayher/netlink v1.7.3-0.20250113171957-fbb4dce95f42 // indirect github.com/mdlayher/socket v0.5.1 // indirect github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 // indirect - github.com/metacubex/utls v1.8.3 // indirect + github.com/metacubex/utls v1.8.4 // indirect github.com/mholt/acmez/v3 v3.1.2 // indirect github.com/quic-go/qpack v0.5.1 // indirect github.com/sagernet/bbolt v0.0.0-20231014093535-ea5cb2fe9f0a // indirect @@ -52,13 +52,13 @@ require ( github.com/sagernet/gvisor v0.0.0-20250325023245-7a9c0f5725fb // indirect github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect github.com/sagernet/nftables v0.3.0-beta.4 // indirect - github.com/sagernet/sing-mux v0.3.3 // indirect - github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb // indirect + github.com/sagernet/sing-mux v0.3.4 // indirect + github.com/sagernet/sing-quic v0.5.2 // indirect github.com/sagernet/sing-shadowsocks v0.2.8 // indirect github.com/sagernet/sing-shadowsocks2 v0.2.1 // indirect github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 // indirect github.com/sagernet/sing-vmess v0.2.7 // indirect - github.com/sagernet/smux v1.5.34-mod.2 // indirect + github.com/sagernet/smux v1.5.50-sing-box-mod.1 // indirect github.com/sagernet/wireguard-go v0.0.1-beta.7 // indirect github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 // indirect github.com/vishvananda/netns v0.0.5 // indirect diff --git a/libcore/go.sum b/libcore/go.sum index 55e9d7d7c..dcef8d1db 100644 --- a/libcore/go.sum +++ b/libcore/go.sum @@ -11,7 +11,6 @@ github.com/caddyserver/zerossl v0.1.3/go.mod h1:CxA0acn7oEGO6//4rtrRjYgEoa4MFw/X github.com/cretz/bine v0.2.0 h1:8GiDRGlTgz+o8H9DSnsl+5MeBK4HsExxgl6WgzOCuZo= github.com/cretz/bine v0.2.0/go.mod h1:WU4o9QR9wWp8AVKtTM1XD5vUHkEqnf2vVSo6dBqbetI= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -61,8 +60,8 @@ github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0 h1:Ui+/2s5Qz0lSnDUBmEL12M5Oi/PzvFxGTNohm8ZcsmE= github.com/metacubex/tfo-go v0.0.0-20250921095601-b102db4216c0/go.mod h1:l9oLnLoEXyGZ5RVLsh7QCC5XsouTUyKk4F2nLm2DHLw= -github.com/metacubex/utls v1.8.3 h1:0m/yCxm3SK6kWve2lKiFb1pue1wHitJ8sQQD4Ikqde4= -github.com/metacubex/utls v1.8.3/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= +github.com/metacubex/utls v1.8.4 h1:HmL9nUApDdWSkgUyodfwF6hSjtiwCGGdyhaSpEejKpg= +github.com/metacubex/utls v1.8.4/go.mod h1:kncGGVhFaoGn5M3pFe3SXhZCzsbCJayNOH4UEqTKTko= github.com/mholt/acmez/v3 v3.1.2 h1:auob8J/0FhmdClQicvJvuDavgd5ezwLBfKuYmynhYzc= github.com/mholt/acmez/v3 v3.1.2/go.mod h1:L1wOU06KKvq7tswuMDwKdcHeKpFFgkppZy/y0DFxagQ= github.com/miekg/dns v1.1.67 h1:kg0EHj0G4bfT5/oOys6HhZw4vmMlnoZ+gDu8tJ/AlI0= @@ -88,38 +87,30 @@ github.com/sagernet/nftables v0.3.0-beta.4 h1:kbULlAwAC3jvdGAC1P5Fa3GSxVwQJibNen github.com/sagernet/nftables v0.3.0-beta.4/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8= github.com/sagernet/quic-go v0.52.0-sing-box-mod.3 h1:ySqffGm82rPqI1TUPqmtHIYd12pfEGScygnOxjTL56w= github.com/sagernet/quic-go v0.52.0-sing-box-mod.3/go.mod h1:OV+V5kEBb8kJS7k29MzDu6oj9GyMc7HA07sE1tedxz4= -github.com/sagernet/sing v0.6.9/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing v0.7.13 h1:XNYgd8e3cxMULs/LLJspdn/deHrnPWyrrglNHeCUAYM= -github.com/sagernet/sing v0.7.13/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= -github.com/sagernet/sing-mux v0.3.3 h1:YFgt9plMWzH994BMZLmyKL37PdIVaIilwP0Jg+EcLfw= -github.com/sagernet/sing-mux v0.3.3/go.mod h1:pht8iFY4c9Xltj7rhVd208npkNaeCxzyXCgulDPLUDA= -github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb h1:5Wx3XeTiKrrrcrAky7Hc1bO3CGxrvho2Vu5b/adlEIM= -github.com/sagernet/sing-quic v0.5.2-0.20250909083218-00a55617c0fb/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI= +github.com/sagernet/sing v0.7.18 h1:iZHkaru1/MoHugx3G+9S3WG4owMewKO/KvieE2Pzk4E= +github.com/sagernet/sing v0.7.18/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak= +github.com/sagernet/sing-mux v0.3.4 h1:ZQplKl8MNXutjzbMVtWvWG31fohhgOfCuUZR4dVQ8+s= +github.com/sagernet/sing-mux v0.3.4/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= +github.com/sagernet/sing-quic v0.5.2 h1:I3vlfRImhr0uLwRS3b3ib70RMG9FcXtOKKUDz3eKRWc= +github.com/sagernet/sing-quic v0.5.2/go.mod h1:evP1e++ZG8TJHVV5HudXV4vWeYzGfCdF4HwSJZcdqkI= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8/go.mod h1:lo7TWEMDcN5/h5B8S0ew+r78ZODn6SwVaFhvB6H+PTI= github.com/sagernet/sing-shadowsocks2 v0.2.1 h1:dWV9OXCeFPuYGHb6IRqlSptVnSzOelnqqs2gQ2/Qioo= github.com/sagernet/sing-shadowsocks2 v0.2.1/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11 h1:tK+75l64tm9WvEFrYRE1t0YxoFdWQqw/h7Uhzj0vJ+w= github.com/sagernet/sing-shadowtls v0.2.1-0.20250503051639-fcd445d33c11/go.mod h1:sWqKnGlMipCHaGsw1sTTlimyUpgzP4WP3pjhCsYt9oA= -github.com/sagernet/sing-tun v0.7.3 h1:MFnAir+l24ElEyxdfwtY8mqvUUL9nPnL9TDYLkOmVes= -github.com/sagernet/sing-tun v0.7.3/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= +github.com/sagernet/sing-tun v0.7.10 h1:lLBaS9uL0mK/FCGDe3N4oKQxjMGfmv3u2/6jKtmq4Pw= +github.com/sagernet/sing-tun v0.7.10/go.mod h1:pUEjh9YHQ2gJT6Lk0TYDklh3WJy7lz+848vleGM3JPM= github.com/sagernet/sing-vmess v0.2.7 h1:2ee+9kO0xW5P4mfe6TYVWf9VtY8k1JhNysBqsiYj0sk= github.com/sagernet/sing-vmess v0.2.7/go.mod h1:5aYoOtYksAyS0NXDm0qKeTYW1yoE1bJVcv+XLcVoyJs= -github.com/sagernet/smux v1.5.34-mod.2 h1:gkmBjIjlJ2zQKpLigOkFur5kBKdV6bNRoFu2WkltRQ4= -github.com/sagernet/smux v1.5.34-mod.2/go.mod h1:0KW0+R+ycvA2INW4gbsd7BNyg+HEfLIAxa5N02/28Zc= +github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478= +github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8= github.com/sagernet/wireguard-go v0.0.1-beta.7 h1:ltgBwYHfr+9Wz1eG59NiWnHrYEkDKHG7otNZvu85DXI= github.com/sagernet/wireguard-go v0.0.1-beta.7/go.mod h1:jGXij2Gn2wbrWuYNUmmNhf1dwcZtvyAvQoe8Xd8MbUo= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc= github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854/go.mod h1:LtfoSK3+NG57tvnVEHgcuBW9ujgE8enPSgzgwStwCAA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/ulikunitz/xz v0.5.15 h1:9DNdB5s+SgV3bQ2ApL10xRc35ck0DuIX/isZvIk+ubY= @@ -173,7 +164,6 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From 01bf49f76569ebf705d89f1d9d78d1fcf5c8773e Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Mon, 2 Feb 2026 15:16:18 +0900 Subject: [PATCH 14/18] refactor configuration overriding during subscription updates --- .../io/nekohasekai/sagernet/fmt/AbstractBean.java | 4 ---- .../sagernet/fmt/hysteria/HysteriaBean.java | 11 ----------- .../sagernet/fmt/shadowsocks/ShadowsocksBean.java | 7 ------- .../sagernet/fmt/trojan_go/TrojanGoBean.java | 9 --------- .../io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt | 14 ++++++++++++-- .../sagernet/fmt/v2ray/StandardV2RayBean.java | 15 --------------- .../io/nekohasekai/sagernet/group/RawUpdater.kt | 4 +++- 7 files changed, 15 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java index 53dda06c2..86e6fca9e 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/AbstractBean.java @@ -144,8 +144,4 @@ public int hashCode() { public String toString() { return getClass().getSimpleName() + " " + JavaUtil.gson.toJson(this); } - - public void applyFeatureSettings(AbstractBean other) { - } - } diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java index 6a5f83c03..2d2e19e1d 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/hysteria/HysteriaBean.java @@ -150,17 +150,6 @@ public void deserialize(ByteBufferInput input) { } } - @Override - public void applyFeatureSettings(AbstractBean other) { - if (!(other instanceof HysteriaBean)) return; - HysteriaBean bean = ((HysteriaBean) other); - bean.uploadMbps = uploadMbps; - bean.downloadMbps = downloadMbps; - bean.allowInsecure = allowInsecure; - bean.disableMtuDiscovery = disableMtuDiscovery; - bean.hopInterval = hopInterval; - } - @Override public String displayAddress() { return NetsKt.wrapIPV6Host(serverAddress) + ":" + serverPorts; diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java index 326662ffb..10c394f59 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/shadowsocks/ShadowsocksBean.java @@ -50,13 +50,6 @@ public void deserialize(ByteBufferInput input) { sUoT = input.readBoolean(); } - @Override - public void applyFeatureSettings(AbstractBean other) { - if (!(other instanceof ShadowsocksBean)) return; - ShadowsocksBean bean = ((ShadowsocksBean) other); - bean.sUoT = sUoT; - } - @NotNull @Override public ShadowsocksBean clone() { diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java index f02f36388..fa4aaf4e5 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/trojan_go/TrojanGoBean.java @@ -146,15 +146,6 @@ public void deserialize(ByteBufferInput input) { } } - @Override - public void applyFeatureSettings(AbstractBean other) { - if (!(other instanceof TrojanGoBean)) return; - TrojanGoBean bean = ((TrojanGoBean) other); - if (allowInsecure) { - bean.allowInsecure = true; - } - } - @NotNull @Override public TrojanGoBean clone() { diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt b/app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt index cad2147e6..b418a1b63 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/tuic/TuicFmt.kt @@ -17,11 +17,21 @@ fun parseTuic(url: String): TuicBean { protocolVersion = 5 name = link.fragment - uuid = link.username - token = link.password serverAddress = link.host serverPort = link.port + val rawUser = link.username + val rawPass = link.password + + if (rawUser.contains(":")) { + val parts = rawUser.split(":", limit = 2) + uuid = parts[0] + token = parts.getOrElse(1) { "" } + } else { + uuid = rawUser + token = rawPass + } + link.queryParameter("sni")?.let { sni = it } diff --git a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java index 2f32c50f4..22adb2539 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java +++ b/app/src/main/java/io/nekohasekai/sagernet/fmt/v2ray/StandardV2RayBean.java @@ -258,21 +258,6 @@ public void deserialize(ByteBufferInput input) { } } - @Override - public void applyFeatureSettings(AbstractBean other) { - if (!(other instanceof StandardV2RayBean)) return; - StandardV2RayBean bean = ((StandardV2RayBean) other); - bean.allowInsecure = allowInsecure; - bean.utlsFingerprint = utlsFingerprint; - bean.packetEncoding = packetEncoding; - bean.enableECH = enableECH; - bean.echConfig = echConfig; - bean.enableMux = enableMux; - bean.muxPadding = muxPadding; - bean.muxType = muxType; - bean.muxConcurrency = muxConcurrency; - } - public boolean isVLESS() { if (this instanceof VMessBean) { Integer aid = ((VMessBean) this).alterId; diff --git a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt index 28213489a..7ea0021e8 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt @@ -161,7 +161,9 @@ object RawUpdater : GroupUpdater() { if (toReplace.contains(name)) { val entity = toReplace[name]!! val existsBean = entity.requireBean() - existsBean.applyFeatureSettings(bean) + // 更新订阅,保留自定义覆写设置 + bean.customOutboundJson = existsBean.customOutboundJson + bean.customConfigJson = existsBean.customConfigJson when { existsBean != bean -> { changed++ From 3211dc167c37a170aba001def3a3f43b55550a1e Mon Sep 17 00:00:00 2001 From: Svyatoslav Shchipunov Date: Thu, 15 Jan 2026 01:59:07 +0700 Subject: [PATCH 15/18] feat: add on and off shortcuts for automatizations --- app/src/main/AndroidManifest.xml | 18 ++++++ .../sagernet/ui/QuickDisableShortcut.kt | 58 +++++++++++++++++++ .../sagernet/ui/QuickEnableShortcut.kt | 58 +++++++++++++++++++ app/src/main/res/values-ar/strings.xml | 2 + app/src/main/res/values-be/strings.xml | 2 + app/src/main/res/values-de/strings.xml | 2 + app/src/main/res/values-es/strings.xml | 4 +- app/src/main/res/values-fa/strings.xml | 2 + app/src/main/res/values-fr/strings.xml | 2 + app/src/main/res/values-in/strings.xml | 2 + app/src/main/res/values-ja/strings.xml | 2 + app/src/main/res/values-ko/strings.xml | 2 + app/src/main/res/values-nb-rNO/strings.xml | 2 + app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values-tr/strings.xml | 2 + app/src/main/res/values-uk/strings.xml | 2 + app/src/main/res/values-zh-rCN/strings.xml | 2 + app/src/main/res/values-zh-rHK/strings.xml | 2 + app/src/main/res/values-zh-rTW/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/shortcuts.xml | 20 +++++++ 21 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/io/nekohasekai/sagernet/ui/QuickDisableShortcut.kt create mode 100644 app/src/main/java/io/nekohasekai/sagernet/ui/QuickEnableShortcut.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index def29c24c..69818c852 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -221,6 +221,24 @@ + + * + * Copyright (C) 2017 by Mygod Studio <[Email1]> * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +package io.nekohasekai.sagernet.ui + +import android.app.Activity +import android.content.pm.ShortcutManager +import android.os.Build +import android.os.Bundle +import androidx.core.content.getSystemService +import io.nekohasekai.sagernet.SagerNet +import io.nekohasekai.sagernet.aidl.ISagerNetService +import io.nekohasekai.sagernet.bg.BaseService +import io.nekohasekai.sagernet.bg.SagerConnection + +class QuickDisableShortcut : Activity(), SagerConnection.Callback { + private val connection = SagerConnection(SagerConnection.CONNECTION_ID_SHORTCUT) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + connection.connect(this, this) + if (Build.VERSION.SDK_INT >= 25) { + getSystemService()!!.reportShortcutUsed("disable") + } + } + + override fun onServiceConnected(service: ISagerNetService) { + val state = BaseService.State.values()[service.state] + if (state.canStop) { + SagerNet.stopService() + } + finish() + } + + override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) {} + + override fun onDestroy() { + connection.disconnect(this) + super.onDestroy() + } +} diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/QuickEnableShortcut.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/QuickEnableShortcut.kt new file mode 100644 index 000000000..590868d18 --- /dev/null +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/QuickEnableShortcut.kt @@ -0,0 +1,58 @@ +/******************************************************************************* + * * + * Copyright (C) 2017 by Max Lv <[Email0]> * + * Copyright (C) 2017 by Mygod Studio <[Email1]> * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + * * + *******************************************************************************/ + +package io.nekohasekai.sagernet.ui + +import android.app.Activity +import android.content.pm.ShortcutManager +import android.os.Build +import android.os.Bundle +import androidx.core.content.getSystemService +import io.nekohasekai.sagernet.SagerNet +import io.nekohasekai.sagernet.aidl.ISagerNetService +import io.nekohasekai.sagernet.bg.BaseService +import io.nekohasekai.sagernet.bg.SagerConnection + +class QuickEnableShortcut : Activity(), SagerConnection.Callback { + private val connection = SagerConnection(SagerConnection.CONNECTION_ID_SHORTCUT) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + connection.connect(this, this) + if (Build.VERSION.SDK_INT >= 25) { + getSystemService()!!.reportShortcutUsed("enable") + } + } + + override fun onServiceConnected(service: ISagerNetService) { + val state = BaseService.State.values()[service.state] + if (state == BaseService.State.Stopped) { + SagerNet.startService() + } + finish() + } + + override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) {} + + override fun onDestroy() { + connection.disconnect(this) + super.onDestroy() + } +} diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 0d7e634ea..b756ddc32 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -23,6 +23,8 @@ أسم المجموعة الجلاد تبديل + تمكين + تعطيل غير مجمعة وثيقة موضوع diff --git a/app/src/main/res/values-be/strings.xml b/app/src/main/res/values-be/strings.xml index 56567ae01..a140392cc 100644 --- a/app/src/main/res/values-be/strings.xml +++ b/app/src/main/res/values-be/strings.xml @@ -100,6 +100,8 @@ Трафік Перамыкач Пераключыць + Уключыць + Выключыць Разгрупаваны Дакумент Тэма diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index baa382951..4bd07aeb5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -5,6 +5,8 @@ Gruppen name Umschalter Umschalten + Aktivieren + Deaktivieren Ungruppiert Dokument Style diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index e0301bcf7..fda3913b3 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -14,7 +14,9 @@ Tema Documento Desagrupado - Alternar + Alternar + Habilitar + Deshabilitar Conmutador Tráfico diff --git a/app/src/main/res/values-fa/strings.xml b/app/src/main/res/values-fa/strings.xml index de972072d..5e61ffe05 100644 --- a/app/src/main/res/values-fa/strings.xml +++ b/app/src/main/res/values-fa/strings.xml @@ -17,6 +17,8 @@ مستندات گروه پیش‌فرض تغییر وضعیت + فعال‌سازی + غیرفعال‌سازی سوییچر ترافیک sing-box تنظیمات diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 86f4728be..8a69b076d 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -57,6 +57,8 @@ Mettre à jour Nom du groupe Basculer + Activer + Désactiver Dégroupé Document Thème diff --git a/app/src/main/res/values-in/strings.xml b/app/src/main/res/values-in/strings.xml index b52bb0c11..d09ed3ca7 100644 --- a/app/src/main/res/values-in/strings.xml +++ b/app/src/main/res/values-in/strings.xml @@ -83,6 +83,8 @@ Nama grup Pengalih Beralih + Aktifkan + Nonaktifkan Tidak bergrup Dokumen Tema diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index bcd7649b9..10f7b36c1 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -35,6 +35,8 @@ グループ名 スイッチャー トグル + 有効化 + 無効化 グループ化されていない ドキュメント(英語) テーマ diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 742d825ff..edc95c6d6 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -9,6 +9,8 @@ 프로젝트 코틀린에 기록 된 안드로이드에 대한 보편적 인 프록시 도구 체인. 비녀장 + 활성화 + 비활성화 그룹 해제 문서 테마 diff --git a/app/src/main/res/values-nb-rNO/strings.xml b/app/src/main/res/values-nb-rNO/strings.xml index f9472e690..8b07363b1 100644 --- a/app/src/main/res/values-nb-rNO/strings.xml +++ b/app/src/main/res/values-nb-rNO/strings.xml @@ -319,6 +319,8 @@ Oppdater Bytter Veksle + Aktiver + Deaktiver Konfigurasjon Den universelle proxy -verktøykjeden for Android, skrevet i Kotlin. Raffinering diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index c45db7492..bc8c4b2ae 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -342,6 +342,8 @@ Настройки сервера Прокси-цепочка Переключить +Включить +Выключить Не удалось запустить службу VPN. Возможно, вам потребуется перезагрузить устройство. Отключить WakeLock Удаленный DNS diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 2afcf4b51..891a0a128 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -71,6 +71,8 @@ Değiştirici Grup adı Aç/Kapat + Etkinleştir + Devre Dışı Bırak Gruplandırılmamış Döküman Tema diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 023942460..400d69374 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -17,6 +17,8 @@ Документація Без групи Перемикач + Увімкнути + Вимкнути Перемикач Трафік Панель керування sing-box diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 29ee46388..a9f0c1cba 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -12,6 +12,8 @@ 关于 未分组 切换 + 启用 + 禁用 分组名 更新 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 840ee0f1c..bcf2c79dc 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -75,6 +75,8 @@ 密碼(可選) 開始 切換 + 啟用 + 停用 編輯 WebSocket 設定 顯示直連速度 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 695e6cf58..de521bcbd 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -11,6 +11,8 @@ 群組 關於 切換 + 啟用 + 停用 群組名稱 更新 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cd2701bca..1995ff051 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -17,6 +17,8 @@ Document Ungrouped Toggle + Enable + Disable Switcher Traffic sing-box Dashboard diff --git a/app/src/main/res/xml/shortcuts.xml b/app/src/main/res/xml/shortcuts.xml index c4a2badf9..b6b9b2b9b 100644 --- a/app/src/main/res/xml/shortcuts.xml +++ b/app/src/main/res/xml/shortcuts.xml @@ -10,6 +10,26 @@ android:targetClass="io.nekohasekai.sagernet.QuickToggleShortcut" android:targetPackage="moe.nb4a" /> + + + + + + Date: Mon, 2 Feb 2026 16:59:06 +0900 Subject: [PATCH 16/18] many optimize --- .../nekohasekai/sagernet/group/RawUpdater.kt | 9 +++++++ .../nekohasekai/sagernet/ui/AssetsActivity.kt | 7 ++++- .../nekohasekai/sagernet/ui/GroupFragment.kt | 15 +++++++---- .../matsuri/nb4a/proxy/config/ConfigBean.java | 12 ++++++++- libcore/ech/ech.go | 26 ++++++++----------- libcore/http.go | 18 +++---------- 6 files changed, 50 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt index 7ea0021e8..a7597999e 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/group/RawUpdater.kt @@ -477,6 +477,15 @@ object RawUpdater : GroupUpdater() { } } } + + "ech-opts" -> (opt.value as? Map)?.also { + for (echOpt in it) { + when (echOpt.key) { + "enable" -> bean.enableECH = + echOpt.value.toString() == "true" + } + } + } } } proxies.add(bean) diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt index d63848289..25f2b6644 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/AssetsActivity.kt @@ -211,7 +211,12 @@ class AssetsActivity : ThemedActivity() { val localVersion = if (file.isFile) { if (versionFile.isFile) { - versionFile.readText().trim() + try { + versionFile.readText().trim() + } catch (e: Throwable) { + snackbar(e.readableMessage) + "" + } } else { "Unknown-" + DateFormat.getDateFormat(app).format(Date(file.lastModified())) } diff --git a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt index ffc1f55ba..840234b54 100644 --- a/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt +++ b/app/src/main/java/io/nekohasekai/sagernet/ui/GroupFragment.kt @@ -476,12 +476,17 @@ class GroupFragment : ToolbarFragment(R.layout.layout_group), used += toLong() } val total = get("total=([0-9]+)")?.toLong() ?: 0 + val remain = total - used if (used > 0 || total > 0) { - text += getString( - R.string.subscription_traffic, - used.toBytesString(), - (total - used).toBytesString() - ) + text += if (remain > 0) { + getString( + R.string.subscription_traffic, + used.toBytesString(), + remain.toBytesString() + ) + } else { + getString(R.string.subscription_used, used.toBytesString()) + } } get("expire=([0-9]+)")?.apply { text += "\n" diff --git a/app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java b/app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java index b3f18a0f2..df436de76 100644 --- a/app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java +++ b/app/src/main/java/moe/matsuri/nb4a/proxy/config/ConfigBean.java @@ -4,6 +4,7 @@ import com.esotericsoftware.kryo.io.ByteBufferInput; import com.esotericsoftware.kryo.io.ByteBufferOutput; +import com.google.gson.JsonObject; import org.jetbrains.annotations.NotNull; @@ -49,7 +50,16 @@ public String displayName() { } public String displayType() { - return type == 0 ? "sing-box config" : "sing-box outbound"; + if (type != null && type == 1 && JavaUtil.isNotBlank(config)) { + try { + JsonObject json = JavaUtil.gson.fromJson(config, JsonObject.class); + if (json != null && json.has("type")) { + return json.get("type").getAsString() + " (sing-box)"; + } + } catch (Exception ignored) { + } + } + return type != null && type == 0 ? "sing-box config" : "sing-box outbound"; } @NotNull diff --git a/libcore/ech/ech.go b/libcore/ech/ech.go index 1dbf50adb..0094208de 100644 --- a/libcore/ech/ech.go +++ b/libcore/ech/ech.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "encoding/base64" + "log" "net" "os" @@ -29,21 +30,16 @@ func NewECHClientConfig(domain string, tlsConfig *tls.Config, localDnsTransport } } -// ClientHandshake 封装 TLS 握手 -func (s *ECHClientConfig) ClientHandshake(ctx context.Context, conn net.Conn) (*tls.Conn, error) { - tlsConn, err := s.fetchAndHandshake(ctx, conn) +func (s *ECHClientConfig) Client(ctx context.Context, conn net.Conn) (*tls.Conn, error) { + err := s.fetchEchKeys(ctx, conn) if err != nil { - return nil, err + // allow empty ech keys + log.Println("fetchEchKeys:", err) } - err = tlsConn.HandshakeContext(ctx) - if err != nil { - return nil, err - } - return tlsConn, nil + return tls.Client(conn, s.Config), nil } -// fetchAndHandshake 查询 ECHConfigList 并完成 TLS 连接 -func (s *ECHClientConfig) fetchAndHandshake(ctx context.Context, conn net.Conn) (*tls.Conn, error) { +func (s *ECHClientConfig) fetchEchKeys(ctx context.Context, conn net.Conn) error { message := &mDNS.Msg{ MsgHdr: mDNS.MsgHdr{ RecursionDesired: true, @@ -57,14 +53,14 @@ func (s *ECHClientConfig) fetchAndHandshake(ctx context.Context, conn net.Conn) }, } if s.localDnsTransport == nil { - return nil, os.ErrInvalid + return os.ErrInvalid } response, err := s.localDnsTransport.Exchange(ctx, message) if err != nil { - return nil, exceptions.Cause(err, "fetch ECH config list") + return exceptions.Cause(err, "fetch ECH config list") } if response.Rcode != mDNS.RcodeSuccess { - return nil, exceptions.Cause(dns.RcodeError(response.Rcode), "fetch ECH config list") + return exceptions.Cause(dns.RcodeError(response.Rcode), "fetch ECH config list") } for _, rr := range response.Answer { switch resource := rr.(type) { @@ -79,5 +75,5 @@ func (s *ECHClientConfig) fetchAndHandshake(ctx context.Context, conn net.Conn) } } } - return tls.Client(conn, s.Config), nil + return nil } diff --git a/libcore/http.go b/libcore/http.go index ce6fba6e9..c4a8db500 100644 --- a/libcore/http.go +++ b/libcore/http.go @@ -240,17 +240,7 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) { var mu sync.Mutex funcs := []requestFunc{ - // 普通,不再重试 socks5 - func() (response *http.Response, err error) { - request := r.request.Clone(context.Background()) - h1h2Client := &http.Client{ - Transport: &http.Transport{ - DisableKeepAlives: true, - }, - } - return h1h2Client.Do(request) - }, - // ECH HTTPS + // Http(s) With Ech func() (response *http.Response, err error) { request := r.request.Clone(context.Background()) echClient := &http.Client{ @@ -266,7 +256,7 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) { domain = host } echTls := ech.NewECHClientConfig(domain, &r.tls, gLocalDNSTransport) - return echTls.ClientHandshake(ctx, c) + return echTls.Client(ctx, c) }, DisableKeepAlives: true, }, @@ -307,10 +297,8 @@ func (r *httpRequest) doH3Direct() (HTTPResponse, error) { var t string switch i { case 0: - t = "h1h2" + t = "http(s)" case 1: - t = "ech" - case 2: t = "h3" } From a75155c0fb8b5719ab2034efb787a910a574f8bf Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Mon, 2 Feb 2026 17:07:38 +0900 Subject: [PATCH 17/18] update preview version --- nb4a.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nb4a.properties b/nb4a.properties index aab000694..fb38d97eb 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a VERSION_NAME=1.4.1 -PRE_VERSION_NAME=pre-1.4.1-20251026-2 +PRE_VERSION_NAME=pre-1.4.2-20260202-1 VERSION_CODE=45 From 5768494d8ae3c74a057bb6d46c0f8dc071b0d821 Mon Sep 17 00:00:00 2001 From: armv9 <48624112+arm64v8a@users.noreply.github.com> Date: Mon, 9 Feb 2026 11:48:30 +0800 Subject: [PATCH 18/18] 1.4.2 --- nb4a.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nb4a.properties b/nb4a.properties index fb38d97eb..b2433289a 100644 --- a/nb4a.properties +++ b/nb4a.properties @@ -1,4 +1,4 @@ PACKAGE_NAME=moe.nb4a -VERSION_NAME=1.4.1 +VERSION_NAME=1.4.2 PRE_VERSION_NAME=pre-1.4.2-20260202-1 -VERSION_CODE=45 +VERSION_CODE=46