Compare commits

...

67 Commits

Author SHA1 Message Date
2dust
c0141225d3 Add allowInsecure and insecure to the shared URI
https://github.com/2dust/v2rayN/issues/8267
2025-11-09 17:33:40 +08:00
2dust
026bf6a37b up 1.10.27 2025-11-06 18:21:43 +08:00
solokot
c117a334ce Russian translation improvements (#4997) 2025-11-02 10:15:59 +08:00
2dust
051520de37 Set HEV tunnel preference default to true
Changed the default value of the HEV tunnel setting to true across the app, including preference XML, settings UI, config manager, and view model. This ensures that the HEV tunnel is enabled by default for new users and maintains consistent default behavior throughout the application.
2025-11-01 11:29:08 +08:00
2dust
b5146e4712 Comment out per-app proxy setting in preferences 2025-11-01 11:12:15 +08:00
2dust
4457b6b2c9 Refactor PerAppProxyActivity and add auto-enable logic 2025-11-01 11:08:41 +08:00
2dust
12edb051c3 Update config-related strings for clarity and consistency 2025-11-01 10:13:03 +08:00
2dust
923e3f32d1 up 1.10.26 2025-10-26 17:46:30 +08:00
2dust
5490db90c0 up 1.10.25 2025-10-26 17:39:37 +08:00
2dust
cb68d42291 Check for update to add fdroid 2025-10-26 17:38:51 +08:00
2dust
ec3a8e80d6 up 1.10.25 2025-10-26 16:30:28 +08:00
2dust
eb0960125b Update build.yml 2025-10-26 16:29:40 +08:00
2dust
12b70e2088 Adjust the adapter that can modify APPLICATION_ID
Add APPLICATION_ID to the About page
2025-10-26 16:08:44 +08:00
2dust
0c473dea19 up 1.10.24 2025-10-15 17:57:41 +08:00
2dust
e71dd7342a Update AndroidLibXrayLite 2025-10-15 17:56:33 +08:00
2dust
a765215dda Update libs.versions.toml 2025-10-10 19:14:46 +08:00
2dust
edea3027f7 Fix
https://github.com/2dust/v2rayN/issues/8060
2025-10-03 14:28:31 +08:00
2dust
305219c3bc Update libs.versions.toml 2025-10-03 14:28:24 +08:00
DHR60
9c4188fba7 Adjust DNS routing (#4905) 2025-09-13 13:55:53 +08:00
2dust
0f3124bece up 1.10.23 2025-09-11 19:09:59 +08:00
2dust
2614f72a36 Update AndroidLibXrayLite 2025-09-11 19:08:56 +08:00
2dust
480c7fc8a1 up 1.10.22 2025-09-05 18:37:08 +08:00
2dust
302e7f148e Update libs.versions.toml 2025-09-05 18:36:42 +08:00
2dust
98d6da983b Update AndroidLibXrayLite 2025-09-05 18:36:27 +08:00
2dust
f6f60f77d3 up 1.10.21 2025-09-01 09:41:04 +08:00
2dust
7be0fb3ecd Update AndroidLibXrayLite 2025-09-01 09:40:27 +08:00
2dust
d53a9f9ecd up 1.10.20 2025-08-30 11:20:23 +08:00
2dust
9eb03eece2 Update AndroidLibXrayLite 2025-08-30 11:12:44 +08:00
2dust
6632ba3b6e Update libs.versions.toml 2025-08-25 18:39:00 +08:00
2dust
bd582f1d90 Update libs.versions.toml 2025-08-25 18:32:15 +08:00
Evgenii Pravda
f5f1e12565 Reasonable app sorting order (#4869) 2025-08-25 17:49:24 +08:00
2dust
207d6f4f8c Revert "Update build.yml"
This reverts commit fc0e60a097.
2025-08-17 11:15:48 +08:00
2dust
52e0a19826 up 1.10.19 2025-08-17 10:22:04 +08:00
2dust
fc0e60a097 Update build.yml 2025-08-17 09:41:41 +08:00
Hossin Asaadi
65d6b4aaa8 fix redirect infinite loop (#4857) 2025-08-17 09:27:22 +08:00
Hossin Asaadi
7b11755e7f IPv6 Unreachability Fallback for TLS Configs (#4846)
* fix unreachable ipv6 fallback

* add UseIP domainStrategy

* fix DNS query loop
2025-08-16 14:34:53 +08:00
fuilloi
2d0de4860c fix (#4855) 2025-08-16 14:06:35 +08:00
solokot
7406ef16ff Update Russian translation (#4845) 2025-08-14 17:33:24 +08:00
DHR60
a084b21d50 Improves intelligent selection toast and DNS routing (#4838)
* Improves intelligent selection toast and DNS routing

* rename
2025-08-13 16:59:22 +08:00
2dust
bf01fe2bdb up 1.10.18 2025-08-13 08:48:33 +08:00
Skh-web6982
519cc2a4b5 Bump actions/checkout from 4 to 5 (#4837)
Bump actions/checkout from 4 to 5
2025-08-13 08:38:18 +08:00
Tamim Hossain
c21653d40f Feat/add mtu in settings (#4836)
* Added MTU In Settings

Added MTU In Settings.
Closes  #4824

* Update SettingsViewModel.kt
2025-08-13 08:38:07 +08:00
solokot
1919c5e05f Update Russian translation (#4833) 2025-08-13 08:37:52 +08:00
2dust
8a17d93882 up 1.10.17 2025-08-12 18:04:41 +08:00
2dust
21ed008c7b up strings 2025-08-12 18:02:22 +08:00
Tamim Hossain
d83cfa28c2 Added MTU In Settings (#4828)
Added MTU In Settings.
Closes  #4824
2025-08-12 17:33:04 +08:00
2dust
d27e2091a7 up 1.10.16 2025-08-09 20:14:11 +08:00
solokot
c545678e47 Update Russian translation (#4823) 2025-08-09 19:48:31 +08:00
Hossein Abaspanah
05cba9b0fe Update Luri Bakhtiari translation (#4822) 2025-08-09 09:17:36 +08:00
Skh-web6982
b472aa0e6b Update Persian translation (#4821)
* Update Persian translation

* Update strings.xml
2025-08-09 09:17:28 +08:00
2dust
1ad840851a Adjust settings options 2025-08-08 19:44:03 +08:00
Skh-web6982
ffc74f479c Update gradle to 9.0.0 (#4820) 2025-08-08 18:45:08 +08:00
Skh-web6982
81c0087ac1 Update mmkvstatic v1.3.14 (#4819)
v1.3.14 / 2025-05-13
This is a Long Term Support (LTS) release.
This is a hot-fix release for Android/iOS/macOS users. So it is only available on Maven Central and CocoaPods.

Android
Support 16K pagesize.
Fix a potential log callback OOM crash.
Upgrade to NDK r28.1 to have full support of 16K pagesize.
iOS
Retain the callback handler to prevent a potential short-lived callback handler from crashing.
2025-08-08 17:11:24 +08:00
Skh-web6982
97327a0101 Update kotlin version to v2.2.0 (#4818)
* Update kotlin version to 2.2.0

* Update README.md : Update kotlin version to 2.2.0
2025-08-08 17:04:11 +08:00
fuilloi
6318dd554b add hevtun option (#4817) 2025-08-08 17:03:27 +08:00
2dust
785aa7eb8a up 1.10.15 2025-08-07 09:38:42 +08:00
fuilloi
872e926132 Update V2rayConfigManager.kt (#4813) 2025-08-07 09:37:06 +08:00
2dust
b278180eb5 up 1.10.14 2025-08-06 19:27:28 +08:00
2dust
ce64ffbf3b Update hev-socks5-tunnel 2025-08-06 17:46:04 +08:00
2dust
5ad8605a41 Update AndroidLibXrayLite 2025-08-06 17:46:02 +08:00
fuilloi
95f7e99752 fix hev-socks5-tunnel CustomLocalDns route (#4806)
* fix hev-socks5-tunnel dns route

* update
2025-08-06 16:54:04 +08:00
Peyman
f703a41778 Update Persian translation (#4804) 2025-08-05 19:30:19 +08:00
fuilloi
2251c59c0b fix type (#4805) 2025-08-05 18:18:00 +08:00
2dust
edd0ce96b1 remove libhev-socks5-tunnel.so 2025-08-05 18:03:18 +08:00
fuilloi
562283b3cc ndkbuild hev-socks5-tunnel (#4800) 2025-08-05 18:00:13 +08:00
solokot
bb04953845 Update Russian translation (#4797) 2025-08-05 17:13:10 +08:00
Hossein Abaspanah
208a93a917 Update Luri Bakhtiari translation (#4796) 2025-08-05 17:13:00 +08:00
49 changed files with 555 additions and 259 deletions

View File

@@ -16,7 +16,7 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v4.2.2
uses: actions/checkout@v5
with:
submodules: 'recursive'
fetch-depth: '0'
@@ -31,31 +31,31 @@ jobs:
- name: Install NDK
run: |
echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
--channel=3 \
--install "ndk;29.0.13113456"
echo "NDK_HOME=$ANDROID_HOME/ndk/29.0.13113456" >> $GITHUB_ENV
--channel=0 \
--install "ndk;28.2.13676358"
echo "NDK_HOME=$ANDROID_HOME/ndk/28.2.13676358" >> $GITHUB_ENV
sed -i '10i\
\
ndkVersion = "29.0.13113456"' ${{ github.workspace }}/V2rayNG/app/build.gradle.kts
ndkVersion = "28.2.13676358"' ${{ github.workspace }}/V2rayNG/app/build.gradle.kts
- name: Restore cached libtun2socks
id: cache-libtun2socks-restore
uses: actions/cache/restore@v4
with:
path: ${{ github.workspace }}/libs
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/hev-socks5-tunnel/HEAD') }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
- name: Build libtun2socks
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
run: |
bash compile-tun2socks.sh
- name: Save libtun2socks
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ github.workspace }}/libs
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/hev-socks5-tunnel/HEAD') }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
- name: Copy libtun2socks
run: |
@@ -153,7 +153,7 @@ jobs:
uses: svenstaro/upload-release-action@v2
if: github.event.inputs.release_tag != ''
with:
file: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*playstore*/release/*.apk
file: ${{ github.workspace }}/V2rayNG/app/build/outputs/apk/*/release/*.apk
tag: ${{ github.event.inputs.release_tag }}
file_glob: true
prerelease: true

4
.gitmodules vendored
View File

@@ -10,3 +10,7 @@
[submodule "libancillary"]
path = libancillary
url = https://github.com/shadowsocks/libancillary
[submodule "hev-socks5-tunnel"]
path = hev-socks5-tunnel
url = https://github.com/heiher/hev-socks5-tunnel
branch = master

View File

@@ -3,7 +3,7 @@
A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-core) and [v2fly core](https://github.com/v2fly/v2ray-core)
[![API](https://img.shields.io/badge/API-21%2B-yellow.svg?style=flat)](https://developer.android.com/about/versions/lollipop)
[![Kotlin Version](https://img.shields.io/badge/Kotlin-2.1.21-blue.svg)](https://kotlinlang.org)
[![Kotlin Version](https://img.shields.io/badge/Kotlin-2.2.0-blue.svg)](https://kotlinlang.org)
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/2dust/v2rayNG)](https://github.com/2dust/v2rayNG/commits/master)
[![CodeFactor](https://www.codefactor.io/repository/github/2dust/v2rayng/badge)](https://www.codefactor.io/repository/github/2dust/v2rayng)
[![GitHub Releases](https://img.shields.io/github/downloads/2dust/v2rayNG/latest/total?logo=github)](https://github.com/2dust/v2rayNG/releases)

View File

@@ -12,8 +12,8 @@ android {
applicationId = "com.v2ray.ang"
minSdk = 21
targetSdk = 35
versionCode = 663
versionName = "1.10.13"
versionCode = 678
versionName = "1.10.27"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name" translatable="false">v2rayNG (F-Droid)</string>
</resources>

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
<shortcut
android:enabled="true"
android:icon="@drawable/ic_qu_switch_24dp"
android:shortcutDisabledMessage="@string/app_widget_name"
android:shortcutId="shortcuts_switch"
android:shortcutLongLabel="@string/app_widget_name"
android:shortcutShortLabel="@string/app_widget_name">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.v2ray.ang.ui.ScSwitchActivity"
android:targetPackage="com.v2ray.ang.fdroid" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
<shortcut
android:enabled="true"
android:icon="@drawable/ic_qu_scan_24dp"
android:shortcutDisabledMessage="@string/menu_item_import_config_qrcode"
android:shortcutId="shortcuts_scan"
android:shortcutLongLabel="@string/menu_item_import_config_qrcode"
android:shortcutShortLabel="@string/menu_item_import_config_qrcode">
<intent
android:action="android.intent.action.VIEW"
android:targetClass="com.v2ray.ang.ui.ScScannerActivity"
android:targetPackage="com.v2ray.ang.fdroid" />
<categories android:name="android.shortcut.conversation" />
</shortcut>
</shortcuts>

View File

@@ -195,8 +195,8 @@
android:resource="@xml/app_widget_provider" />
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="com.v2ray.ang.action.widget.click" />
<action android:name="com.v2ray.ang.action.activity" />
<action android:name="${applicationId}.action.widget.click" />
<action android:name="${applicationId}.action.activity" />
</intent-filter>
</receiver>
<receiver

View File

@@ -27,6 +27,7 @@ object AppConfig {
const val PREF_VPN_DNS = "pref_vpn_dns"
const val PREF_VPN_BYPASS_LAN = "pref_vpn_bypass_lan"
const val PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX = "pref_vpn_interface_address_config_index"
const val PREF_VPN_MTU = "pref_vpn_mtu"
const val PREF_ROUTING_DOMAIN_STRATEGY = "pref_routing_domain_strategy"
const val PREF_ROUTING_RULESET = "pref_routing_ruleset"
const val PREF_MUX_ENABLED = "pref_mux_enabled"
@@ -63,6 +64,8 @@ object AppConfig {
const val PREF_CHECK_UPDATE_PRE_RELEASE = "pref_check_update_pre_release"
const val PREF_GEO_FILES_SOURCES = "pref_geo_files_sources"
const val PREF_USE_HEV_TUNNEL = "pref_use_hev_tunnel"
const val PREF_HEV_TUNNEL_LOGLEVEL = "pref_hev_tunnel_loglevel"
const val PREF_HEV_TUNNEL_RW_TIMEOUT = "pref_hev_tunnel_rw_timeout"
/** Cache keys. */
const val CACHE_SUBSCRIPTION_ID = "cache_subscription_id"
@@ -72,9 +75,9 @@ object AppConfig {
const val PROTOCOL_FREEDOM = "freedom"
/** Broadcast actions. */
const val BROADCAST_ACTION_SERVICE = "com.v2ray.ang.action.service"
const val BROADCAST_ACTION_ACTIVITY = "com.v2ray.ang.action.activity"
const val BROADCAST_ACTION_WIDGET_CLICK = "com.v2ray.ang.action.widget.click"
const val BROADCAST_ACTION_SERVICE = "$ANG_PACKAGE.action.service"
const val BROADCAST_ACTION_ACTIVITY = "$ANG_PACKAGE.action.activity"
const val BROADCAST_ACTION_WIDGET_CLICK = "$ANG_PACKAGE.action.widget.click"
/** Tasker extras. */
const val TASKER_EXTRA_BUNDLE = "com.twofortyfouram.locale.intent.extra.BUNDLE"
@@ -88,6 +91,8 @@ object AppConfig {
const val TAG_DIRECT = "direct"
const val TAG_BLOCKED = "block"
const val TAG_FRAGMENT = "fragment"
const val TAG_DNS = "dns-module"
const val TAG_DOMESTIC_DNS = "domestic-dns"
/** Network-related constants. */
const val UPLINK = "uplink"
@@ -166,6 +171,9 @@ object AppConfig {
const val VPN = "VPN"
const val VPN_MTU = 1500
/** hev-sock5-tunnel read-write-timeout value */
const val HEVTUN_RW_TIMEOUT = "300000"
// Google API rule constants
const val GOOGLEAPIS_CN_DOMAIN = "domain:googleapis.cn"
const val GOOGLEAPIS_COM_DOMAIN = "googleapis.com"

View File

@@ -245,7 +245,14 @@ data class V2rayConfig(
var tproxy: String? = null,
var mark: Int? = null,
var dialerProxy: String? = null,
var domainStrategy: String? = null
var domainStrategy: String? = null,
var happyEyeballs: happyEyeballsBean? = null,
)
data class happyEyeballsBean(
var prioritizeIPv6: Boolean? = null,
var maxConcurrentTry: Int? = 4,
var tryDelayMs: Int? = 250, // ms
var interleave: Int? = null,
)
data class TlsSettingsBean(
@@ -490,6 +497,7 @@ data class V2rayConfig(
var expectIPs: List<String>? = null,
val clientIp: String? = null,
val skipFallback: Boolean? = null,
val tag: String? = null,
)
}

View File

@@ -15,5 +15,6 @@ data class VmessQRCode(
var tls: String = "",
var sni: String = "",
var alpn: String = "",
var fp: String = ""
var fp: String = "",
var insecure: String = ""
)

View File

@@ -72,10 +72,12 @@ open class FmtBase {
if (config.security != AppConfig.TLS && config.security != AppConfig.REALITY) {
config.security = null
}
config.insecure = if (queryParam["allowInsecure"].isNullOrEmpty()) {
allowInsecure
} else {
queryParam["allowInsecure"].orEmpty() == "1"
// Support multiple possible query keys for allowInsecure like the C# implementation
val allowInsecureKeys = arrayOf("insecure", "allowInsecure", "allow_insecure", "verify")
config.insecure = when {
allowInsecureKeys.any { queryParam[it] == "1" } -> true
allowInsecureKeys.any { queryParam[it] == "0" } -> false
else -> allowInsecure
}
config.sni = queryParam["sni"]
config.fingerPrint = queryParam["fp"]
@@ -104,6 +106,12 @@ open class FmtBase {
config.spiderX.let { if (it.isNotNullEmpty()) dicQuery["spx"] = it.orEmpty() }
config.mldsa65Verify.let { if (it.isNotNullEmpty()) dicQuery["pqv"] = it.orEmpty() }
config.flow.let { if (it.isNotNullEmpty()) dicQuery["flow"] = it.orEmpty() }
// Add two keys for compatibility: "insecure" and "allowInsecure"
if (config.security == AppConfig.TLS) {
val insecureFlag = if (config.insecure == true) "1" else "0"
dicQuery["insecure"] = insecureFlag
dicQuery["allowInsecure"] = insecureFlag
}
val networkType = NetworkType.fromString(config.network)
dicQuery["type"] = networkType.type

View File

@@ -34,15 +34,9 @@ object Hysteria2Fmt : FmtBase() {
if (!uri.rawQuery.isNullOrEmpty()) {
val queryParam = getQueryParam(uri)
getItemFormQuery(config, queryParam, allowInsecure)
config.security = queryParam["security"] ?: AppConfig.TLS
config.insecure = if (queryParam["insecure"].isNullOrEmpty()) {
allowInsecure
} else {
queryParam["insecure"].orEmpty() == "1"
}
config.sni = queryParam["sni"]
config.alpn = queryParam["alpn"]
config.obfsPassword = queryParam["obfs-password"]
config.portHopping = queryParam["mport"]
config.pinSHA256 = queryParam["pinSHA256"]

View File

@@ -122,7 +122,7 @@ object ShadowsocksFmt : FmtBase() {
fun toUri(config: ProfileItem): String {
val pw = "${config.method}:${config.password}"
return toUri(config, Utils.encode(pw), null)
return toUri(config, Utils.encode(pw, true), null)
}
/**

View File

@@ -51,7 +51,7 @@ object SocksFmt : FmtBase() {
else
":"
return toUri(config, Utils.encode(pw), null)
return toUri(config, Utils.encode(pw, true), null)
}
/**

View File

@@ -28,7 +28,7 @@ object VmessFmt : FmtBase() {
return parseVmessStd(str)
}
var allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
val allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
val config = ProfileItem.create(EConfigType.VMESS)
var result = str.replace(EConfigType.VMESS.protocolScheme, "")
@@ -78,12 +78,15 @@ object VmessFmt : FmtBase() {
else -> {}
}
config.security = vmessQRCode.tls
config.insecure = allowInsecure
config.security = vmessQRCode.tls
config.sni = vmessQRCode.sni
config.fingerPrint = vmessQRCode.fp
config.alpn = vmessQRCode.alpn
config.insecure = when (vmessQRCode.insecure) {
"1" -> true
"0" -> false
else -> allowInsecure
}
return config
}
@@ -132,6 +135,11 @@ object VmessFmt : FmtBase() {
vmessQRCode.sni = config.sni.orEmpty()
vmessQRCode.fp = config.fingerPrint.orEmpty()
vmessQRCode.alpn = config.alpn.orEmpty()
vmessQRCode.insecure = when (config.insecure) {
true -> "1"
false -> "0"
else -> ""
}
val json = JsonUtil.toJson(vmessQRCode)
return Utils.encode(json)

View File

@@ -370,4 +370,11 @@ object SettingsManager {
val selectedIndex = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX, "0")?.toInt()
return VpnInterfaceAddressConfig.getConfigByIndex(selectedIndex ?: 0)
}
/**
* Get the VPN MTU from settings, defaulting to AppConfig.VPN_MTU.
*/
fun getVpnMtu(): Int {
return Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_MTU), AppConfig.VPN_MTU)
}
}

View File

@@ -100,8 +100,19 @@ object UpdateCheckerManager {
}
private fun getDownloadUrl(release: GitHubRelease, abi: String): String {
return release.assets.find { it.name.contains(abi) }?.browserDownloadUrl
?: release.assets.firstOrNull()?.browserDownloadUrl
val fDroid = "fdroid"
val assetsByAbi = release.assets.filter {
(it.name.contains(abi, true))
}
val asset = if (BuildConfig.APPLICATION_ID.contains(fDroid, ignoreCase = true)) {
assetsByAbi.firstOrNull { it.name.contains(fDroid) }
} else {
assetsByAbi.firstOrNull { !it.name.contains(fDroid) }
}
return asset?.browserDownloadUrl
?: throw IllegalStateException("No compatible APK found")
}
}

View File

@@ -470,27 +470,49 @@ object V2rayConfigManager {
)
}
// DNS inbound
val remoteDns = SettingsManager.getRemoteDnsServers()
if (v2rayConfig.inbounds.none { e -> e.protocol == "dokodemo-door" && e.tag == "dns-in" }) {
val dnsInboundSettings = V2rayConfig.InboundBean.InSettingsBean(
address = if (Utils.isPureIpAddress(remoteDns.first())) remoteDns.first() else AppConfig.DNS_PROXY,
port = 53,
network = "tcp,udp"
)
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_USE_HEV_TUNNEL ,true) == false) {
val localDnsPort = Utils.parseInt(
MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT),
AppConfig.PORT_LOCAL_DNS.toInt()
// DNS inbound
val remoteDns = SettingsManager.getRemoteDnsServers()
if (v2rayConfig.inbounds.none { e -> e.protocol == "dokodemo-door" && e.tag == "dns-in" }) {
val dnsInboundSettings = V2rayConfig.InboundBean.InSettingsBean(
address = if (Utils.isPureIpAddress(remoteDns.first())) remoteDns.first() else AppConfig.DNS_PROXY,
port = 53,
network = "tcp,udp"
)
val localDnsPort = Utils.parseInt(
MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT),
AppConfig.PORT_LOCAL_DNS.toInt()
)
v2rayConfig.inbounds.add(
V2rayConfig.InboundBean(
tag = "dns-in",
port = localDnsPort,
listen = AppConfig.LOOPBACK,
protocol = "dokodemo-door",
settings = dnsInboundSettings,
sniffing = null
)
)
}
// DNS routing tag
v2rayConfig.routing.rules.add(
0, RulesBean(
inboundTag = arrayListOf("dns-in"),
outboundTag = "dns-out",
domain = null
)
)
v2rayConfig.inbounds.add(
V2rayConfig.InboundBean(
tag = "dns-in",
port = localDnsPort,
listen = AppConfig.LOOPBACK,
protocol = "dokodemo-door",
settings = dnsInboundSettings,
sniffing = null
} else {
//hev-socks5-tunnel dns routing
v2rayConfig.routing.rules.add(
0, RulesBean(
inboundTag = arrayListOf("socks"),
outboundTag = "dns-out",
port = "53",
type = "field"
)
)
}
@@ -507,15 +529,6 @@ object V2rayConfigManager {
)
)
}
// DNS routing tag
v2rayConfig.routing.rules.add(
0, RulesBean(
inboundTag = arrayListOf("dns-in"),
outboundTag = "dns-out",
domain = null
)
)
} catch (e: Exception) {
Log.e(AppConfig.TAG, "Failed to configure custom local DNS", e)
return false
@@ -562,18 +575,8 @@ object V2rayConfigManager {
address = domesticDns.first(),
domains = directDomain,
expectIPs = if (isCnRoutingMode) geoipCn else null,
skipFallback = true
)
)
}
if (Utils.isPureIpAddress(domesticDns.first())) {
v2rayConfig.routing.rules.add(
0, RulesBean(
outboundTag = AppConfig.TAG_DIRECT,
port = "53",
ip = arrayListOf(domesticDns.first()),
domain = null
skipFallback = true,
tag = AppConfig.TAG_DOMESTIC_DNS
)
)
}
@@ -614,20 +617,25 @@ object V2rayConfigManager {
// DNS dns
v2rayConfig.dns = V2rayConfig.DnsBean(
servers = servers,
hosts = hosts
hosts = hosts,
tag = AppConfig.TAG_DNS
)
// DNS routing
if (Utils.isPureIpAddress(remoteDns.first())) {
v2rayConfig.routing.rules.add(
0, RulesBean(
outboundTag = AppConfig.TAG_PROXY,
port = "53",
ip = arrayListOf(remoteDns.first()),
domain = null
)
v2rayConfig.routing.rules.add(
RulesBean(
outboundTag = AppConfig.TAG_DIRECT,
inboundTag = arrayListOf(AppConfig.TAG_DOMESTIC_DNS),
domain = null
)
}
)
v2rayConfig.routing.rules.add(
RulesBean(
outboundTag = AppConfig.TAG_PROXY,
inboundTag = arrayListOf(AppConfig.TAG_DNS),
domain = null
)
)
} catch (e: Exception) {
Log.e(AppConfig.TAG, "Failed to configure DNS", e)
return false
@@ -1002,14 +1010,22 @@ object V2rayConfigManager {
if (domain.isNullOrEmpty()) continue
if (newHosts.containsKey(domain)) {
item.ensureSockopt().domainStrategy = if (preferIpv6) "UseIPv6v4" else "UseIPv4v6"
item.ensureSockopt().domainStrategy = "UseIP"
item.ensureSockopt().happyEyeballs = StreamSettingsBean.happyEyeballsBean(
prioritizeIPv6 = preferIpv6,
interleave = 2
)
continue
}
val resolvedIps = HttpUtil.resolveHostToIP(domain, preferIpv6)
if (resolvedIps.isNullOrEmpty()) continue
item.ensureSockopt().domainStrategy = if (preferIpv6) "UseIPv6v4" else "UseIPv4v6"
item.ensureSockopt().domainStrategy = "UseIP"
item.ensureSockopt().happyEyeballs = StreamSettingsBean.happyEyeballsBean(
prioritizeIPv6 = preferIpv6,
interleave = 2
)
newHosts[domain] = if (resolvedIps.size == 1) {
resolvedIps[0]
} else {

View File

@@ -4,7 +4,6 @@ import android.content.Context
import android.os.ParcelFileDescriptor
import android.util.Log
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.VPN_MTU
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsManager
import java.io.File
@@ -60,7 +59,7 @@ class TProxyService(
val vpnConfig = SettingsManager.getCurrentVpnInterfaceAddressConfig()
return buildString {
appendLine("tunnel:")
appendLine(" mtu: $VPN_MTU")
appendLine(" mtu: ${SettingsManager.getVpnMtu()}")
appendLine(" ipv4: ${vpnConfig.ipv4Client}")
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) {
@@ -72,12 +71,11 @@ class TProxyService(
appendLine(" address: ${AppConfig.LOOPBACK}")
appendLine(" udp: 'udp'")
MmkvManager.decodeSettingsString(AppConfig.PREF_LOGLEVEL)?.let { logPref ->
if (logPref != "none") {
val logLevel = if (logPref == "warning") "warn" else logPref
appendLine("misc:")
appendLine(" log-level: $logLevel")
}
appendLine("misc:")
appendLine(" read-write-timeout: ${MmkvManager.decodeSettingsString(AppConfig.PREF_HEV_TUNNEL_RW_TIMEOUT) ?: AppConfig.HEVTUN_RW_TIMEOUT}")
val hevTunLogLevel = MmkvManager.decodeSettingsString(AppConfig.PREF_HEV_TUNNEL_LOGLEVEL) ?: "none"
if (hevTunLogLevel != "none") {
appendLine(" log-level: $hevTunLogLevel")
}
}
}

View File

@@ -6,7 +6,6 @@ import android.net.LocalSocketAddress
import android.os.ParcelFileDescriptor
import android.util.Log
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.VPN_MTU
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.SettingsManager
import com.v2ray.ang.util.Utils
@@ -42,7 +41,7 @@ class Tun2SocksService(
"--netif-ipaddr", vpnConfig.ipv4Router,
"--netif-netmask", "255.255.255.252",
"--socks-server-addr", "${AppConfig.LOOPBACK}:${socksPort}",
"--tunmtu", VPN_MTU.toString(),
"--tunmtu", SettingsManager.getVpnMtu().toString(),
"--sock-path", "sock_path",
"--enable-udprelay",
"--loglevel", "notice"

View File

@@ -17,7 +17,6 @@ import android.util.Log
import androidx.annotation.RequiresApi
import com.v2ray.ang.AppConfig
import com.v2ray.ang.AppConfig.LOOPBACK
import com.v2ray.ang.AppConfig.VPN_MTU
import com.v2ray.ang.BuildConfig
import com.v2ray.ang.handler.MmkvManager
import com.v2ray.ang.handler.NotificationManager
@@ -185,7 +184,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
val bypassLan = SettingsManager.routingRulesetsBypassLan()
// Configure IPv4 settings
builder.setMtu(VPN_MTU)
builder.setMtu(SettingsManager.getVpnMtu())
builder.addAddress(vpnConfig.ipv4Client, 30)
// Configure routing rules
@@ -296,7 +295,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
* Starts the tun2socks process with the appropriate parameters.
*/
private fun runTun2socks() {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_USE_HEV_TUNNEL) == true) {
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_USE_HEV_TUNNEL, true) == true) {
tun2SocksService = TProxyService(
context = applicationContext,
vpnInterface = mInterface,

View File

@@ -127,6 +127,9 @@ class AboutActivity : BaseActivity() {
"v${BuildConfig.VERSION_NAME} (${SpeedtestManager.getLibVersion()})".also {
binding.tvVersion.text = it
}
BuildConfig.APPLICATION_ID.also {
binding.tvAppId.text = it
}
}
private fun backupConfiguration(outputZipFilePos: String): Pair<Boolean, String> {

View File

@@ -386,6 +386,9 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
}
R.id.intelligent_selection_all -> {
if (MmkvManager.decodeSettingsString(AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD, "1") != "0") {
toast(getString(R.string.pre_resolving_domain))
}
mainViewModel.createIntelligentSelectionAll()
true
}

View File

@@ -42,39 +42,7 @@ class PerAppProxyActivity : BaseActivity() {
addCustomDividerToRecyclerView(binding.recyclerView, this, R.drawable.custom_divider)
lifecycleScope.launch {
try {
binding.pbWaiting.show()
val blacklist = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
val apps = withContext(Dispatchers.IO) {
val appsList = AppManagerUtil.loadNetworkAppList(this@PerAppProxyActivity)
if (blacklist != null) {
appsList.forEach { app ->
app.isSelected = if (blacklist.contains(app.packageName)) 1 else 0
}
appsList.sortedWith { p1, p2 ->
when {
p1.isSelected > p2.isSelected -> -1
p1.isSelected == p2.isSelected -> 0
else -> 1
}
}
} else {
val collator = Collator.getInstance()
appsList.sortedWith(compareBy(collator) { it.appName })
}
}
appsAll = apps
adapter = PerAppProxyAdapter(this@PerAppProxyActivity, apps, blacklist)
binding.recyclerView.adapter = adapter
binding.pbWaiting.hide()
} catch (e: Exception) {
binding.pbWaiting.hide()
Log.e(ANG_PACKAGE, "Error loading apps", e)
}
}
initList()
binding.switchPerAppProxy.setOnCheckedChangeListener { _, isChecked ->
MmkvManager.encodeSettings(AppConfig.PREF_PER_APP_PROXY, isChecked)
@@ -91,6 +59,50 @@ class PerAppProxyActivity : BaseActivity() {
}
}
private fun initList() {
binding.pbWaiting.show()
lifecycleScope.launch {
try {
val blacklist =
MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
val apps = withContext(Dispatchers.IO) {
val appsList = AppManagerUtil.loadNetworkAppList(this@PerAppProxyActivity)
if (blacklist != null) {
appsList.forEach { app ->
app.isSelected = if (blacklist.contains(app.packageName)) 1 else 0
}
appsList.sortedWith { p1, p2 ->
when {
p1.isSelected > p2.isSelected -> -1
p1.isSelected < p2.isSelected -> 1
p1.isSystemApp > p2.isSystemApp -> 1
p1.isSystemApp < p2.isSystemApp -> -1
p1.appName.lowercase() > p2.appName.lowercase() -> 1
p1.appName.lowercase() < p2.appName.lowercase() -> -1
p1.packageName > p2.packageName -> 1
p1.packageName < p2.packageName -> -1
else -> 0
}
}
} else {
val collator = Collator.getInstance()
appsList.sortedWith(compareBy(collator) { it.appName })
}
}
appsAll = apps
adapter = PerAppProxyAdapter(this@PerAppProxyActivity, apps, blacklist)
binding.recyclerView.adapter = adapter
} catch (e: Exception) {
Log.e(ANG_PACKAGE, "Error loading apps", e)
} finally {
binding.pbWaiting.hide()
}
}
}
override fun onPause() {
super.onPause()
adapter?.let {
@@ -114,14 +126,40 @@ class PerAppProxyActivity : BaseActivity() {
})
}
return super.onCreateOptionsMenu(menu)
}
@SuppressLint("NotifyDataSetChanged")
override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) {
R.id.select_all -> adapter?.let { it ->
R.id.select_all -> {
selectAllApp()
allowPerAppProxy()
true
}
R.id.select_proxy_app -> {
selectProxyAppAuto()
allowPerAppProxy()
true
}
R.id.import_proxy_app -> {
importProxyApp()
allowPerAppProxy()
true
}
R.id.export_proxy_app -> {
exportProxyApp()
true
}
else -> super.onOptionsItemSelected(item)
}
private fun selectAllApp() {
adapter?.let { it ->
val pkgNames = it.apps.map { it.packageName }
if (it.blacklist.containsAll(pkgNames)) {
it.apps.forEach {
@@ -136,27 +174,10 @@ class PerAppProxyActivity : BaseActivity() {
}
it.notifyDataSetChanged()
true
} == true
R.id.select_proxy_app -> {
selectProxyApp()
true
}
R.id.import_proxy_app -> {
importProxyApp()
true
}
R.id.export_proxy_app -> {
exportProxyApp()
true
}
else -> super.onOptionsItemSelected(item)
}
private fun selectProxyApp() {
private fun selectProxyAppAuto() {
toast(R.string.msg_downloading_content)
binding.pbWaiting.show()
@@ -193,6 +214,10 @@ class PerAppProxyActivity : BaseActivity() {
toastSuccess(R.string.toast_success)
}
private fun allowPerAppProxy() {
binding.switchPerAppProxy.isChecked = true
}
@SuppressLint("NotifyDataSetChanged")
private fun selectProxyApp(content: String, force: Boolean): Boolean {
try {

View File

@@ -37,7 +37,7 @@ class SettingsActivity : BaseActivity() {
class SettingsFragment : PreferenceFragmentCompat() {
private val perAppProxy by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_PER_APP_PROXY) }
// private val perAppProxy by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_PER_APP_PROXY) }
private val localDns by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_LOCAL_DNS_ENABLED) }
private val fakeDns by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_FAKE_DNS_ENABLED) }
private val appendHttpProxy by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_APPEND_HTTP_PROXY) }
@@ -45,6 +45,7 @@ class SettingsActivity : BaseActivity() {
private val vpnDns by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_DNS) }
private val vpnBypassLan by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_BYPASS_LAN) }
private val vpnInterfaceAddress by lazy { findPreference<ListPreference>(AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX) }
private val vpnMtu by lazy { findPreference<EditTextPreference>(AppConfig.PREF_VPN_MTU) }
private val mux by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_MUX_ENABLED) }
private val muxConcurrency by lazy { findPreference<EditTextPreference>(AppConfig.PREF_MUX_CONCURRENCY) }
@@ -66,14 +67,18 @@ class SettingsActivity : BaseActivity() {
private val delayTestUrl by lazy { findPreference<EditTextPreference>(AppConfig.PREF_DELAY_TEST_URL) }
private val mode by lazy { findPreference<ListPreference>(AppConfig.PREF_MODE) }
private val hevTunLogLevel by lazy { findPreference<ListPreference>(AppConfig.PREF_HEV_TUNNEL_LOGLEVEL) }
private val hevTunRwTimeout by lazy { findPreference<EditTextPreference>(AppConfig.PREF_HEV_TUNNEL_RW_TIMEOUT) }
private val useHevTun by lazy { findPreference<CheckBoxPreference>(AppConfig.PREF_USE_HEV_TUNNEL) }
override fun onCreatePreferences(bundle: Bundle?, s: String?) {
addPreferencesFromResource(R.xml.pref_settings)
perAppProxy?.setOnPreferenceClickListener {
startActivity(Intent(activity, PerAppProxyActivity::class.java))
perAppProxy?.isChecked = true
false
}
// perAppProxy?.setOnPreferenceClickListener {
// startActivity(Intent(activity, PerAppProxyActivity::class.java))
// perAppProxy?.isChecked = true
// false
// }
localDns?.setOnPreferenceChangeListener { _, any ->
updateLocalDns(any as Boolean)
true
@@ -89,6 +94,12 @@ class SettingsActivity : BaseActivity() {
true
}
vpnMtu?.setOnPreferenceChangeListener { _, any ->
val nval = any as String
vpnMtu?.summary = if (TextUtils.isEmpty(nval)) AppConfig.VPN_MTU.toString() else nval
true
}
mux?.setOnPreferenceChangeListener { _, newValue ->
updateMux(newValue as Boolean)
true
@@ -172,6 +183,16 @@ class SettingsActivity : BaseActivity() {
mode?.dialogLayoutResource = R.layout.preference_with_help_link
//loglevel.summary = "LogLevel"
useHevTun?.setOnPreferenceChangeListener { _, newValue ->
updateHevTunSettings(newValue as Boolean)
true
}
hevTunRwTimeout?.setOnPreferenceChangeListener { _, any ->
val nval = any as String
hevTunRwTimeout?.summary = if (TextUtils.isEmpty(nval)) AppConfig.HEVTUN_RW_TIMEOUT else nval
true
}
}
override fun onStart() {
@@ -182,6 +203,7 @@ class SettingsActivity : BaseActivity() {
appendHttpProxy?.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_APPEND_HTTP_PROXY, false)
localDnsPort?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT, AppConfig.PORT_LOCAL_DNS)
vpnDns?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_DNS, AppConfig.DNS_VPN)
vpnMtu?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_VPN_MTU, AppConfig.VPN_MTU.toString())
updateMux(MmkvManager.decodeSettingsBool(AppConfig.PREF_MUX_ENABLED, false))
mux?.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_MUX_ENABLED, false)
@@ -205,6 +227,9 @@ class SettingsActivity : BaseActivity() {
dnsHosts?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_DNS_HOSTS)
delayTestUrl?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_DELAY_TEST_URL, AppConfig.DELAY_TEST_URL)
updateHevTunSettings(MmkvManager.decodeSettingsBool(AppConfig.PREF_USE_HEV_TUNNEL, true))
hevTunRwTimeout?.summary = MmkvManager.decodeSettingsString(AppConfig.PREF_HEV_TUNNEL_RW_TIMEOUT, AppConfig.HEVTUN_RW_TIMEOUT)
initSharedPreference()
}
@@ -212,6 +237,7 @@ class SettingsActivity : BaseActivity() {
listOf(
localDnsPort,
vpnDns,
vpnMtu,
muxConcurrency,
muxXudpConcurrency,
fragmentLength,
@@ -220,13 +246,15 @@ class SettingsActivity : BaseActivity() {
socksPort,
remoteDns,
domesticDns,
delayTestUrl
delayTestUrl,
hevTunRwTimeout
).forEach { key ->
key?.text = key?.summary.toString()
}
listOf(
AppConfig.PREF_SNIFFING_ENABLED,
AppConfig.PREF_USE_HEV_TUNNEL
).forEach { key ->
findPreference<CheckBoxPreference>(key)?.isChecked =
MmkvManager.decodeSettingsBool(key, true)
@@ -242,8 +270,7 @@ class SettingsActivity : BaseActivity() {
AppConfig.PREF_DOUBLE_COLUMN_DISPLAY,
AppConfig.PREF_PREFER_IPV6,
AppConfig.PREF_PROXY_SHARING,
AppConfig.PREF_ALLOW_INSECURE,
AppConfig.PREF_USE_HEV_TUNNEL
AppConfig.PREF_ALLOW_INSECURE
).forEach { key ->
findPreference<CheckBoxPreference>(key)?.isChecked =
MmkvManager.decodeSettingsBool(key, false)
@@ -260,7 +287,8 @@ class SettingsActivity : BaseActivity() {
AppConfig.PREF_LOGLEVEL,
AppConfig.PREF_OUTBOUND_DOMAIN_RESOLVE_METHOD,
AppConfig.PREF_INTELLIGENT_SELECTION_METHOD,
AppConfig.PREF_MODE
AppConfig.PREF_MODE,
AppConfig.PREF_HEV_TUNNEL_LOGLEVEL
).forEach { key ->
if (MmkvManager.decodeSettingsString(key) != null) {
findPreference<ListPreference>(key)?.value = MmkvManager.decodeSettingsString(key)
@@ -270,8 +298,8 @@ class SettingsActivity : BaseActivity() {
private fun updateMode(mode: String?) {
val vpn = mode == VPN
perAppProxy?.isEnabled = vpn
perAppProxy?.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY, false)
// perAppProxy?.isEnabled = vpn
// perAppProxy?.isChecked = MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY, false)
localDns?.isEnabled = vpn
fakeDns?.isEnabled = vpn
appendHttpProxy?.isEnabled = vpn
@@ -279,6 +307,7 @@ class SettingsActivity : BaseActivity() {
vpnDns?.isEnabled = vpn
vpnBypassLan?.isEnabled = vpn
vpnInterfaceAddress?.isEnabled = vpn
vpnMtu?.isEnabled = vpn
if (vpn) {
updateLocalDns(
MmkvManager.decodeSettingsBool(
@@ -366,6 +395,11 @@ class SettingsActivity : BaseActivity() {
private fun updateFragmentInterval(value: String?) {
fragmentInterval?.summary = value.toString()
}
private fun updateHevTunSettings(enabled: Boolean) {
hevTunLogLevel?.isEnabled = enabled
hevTunRwTimeout?.isEnabled = enabled
}
}
fun onModeHelpClicked(view: View) {

View File

@@ -12,7 +12,9 @@ import java.net.IDN
import java.net.Inet6Address
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.MalformedURLException
import java.net.Proxy
import java.net.URI
import java.net.URL
object HttpUtil {
@@ -140,7 +142,7 @@ object HttpUtil {
val responseCode = conn.responseCode
when (responseCode) {
in 300..399 -> {
val location = conn.getHeaderField("Location")
val location = resolveLocation(conn)
conn.disconnect()
if (location.isNullOrEmpty()) {
throw IOException("Redirect location not found")
@@ -219,5 +221,29 @@ object HttpUtil {
}
return conn
}
// Returns absolute URL string location header sets
fun resolveLocation(conn: HttpURLConnection): String? {
val raw = conn.getHeaderField("Location")?.trim()?.takeIf { it.isNotEmpty() } ?: return null
// Try check url is relative or absolute
return try {
val locUri = URI(raw)
val baseUri = conn.url.toURI()
val resolved = if (locUri.isAbsolute) locUri else baseUri.resolve(locUri)
resolved.toURL().toString()
} catch (_: Exception) {
// Fallback: url resolver, also should handles //host/...
try {
URL(raw).toString() // absolute with protocol
} catch (_: MalformedURLException) {
try {
URL(conn.url, raw).toString()
} catch (_: MalformedURLException) {
null
}
}
}
}
}

View File

@@ -134,11 +134,16 @@ object Utils {
* Encode a string to base64.
*
* @param text The string to encode.
* @param removePadding
* @return The base64 encoded string, or an empty string if encoding fails.
*/
fun encode(text: String): String {
fun encode(text: String, removePadding : Boolean = false): String {
return try {
Base64.encodeToString(text.toByteArray(Charsets.UTF_8), Base64.NO_WRAP)
var encoded = Base64.encodeToString(text.toByteArray(Charsets.UTF_8), Base64.NO_WRAP)
if (removePadding) {
encoded = encoded.trimEnd('=')
}
encoded
} catch (e: Exception) {
Log.e(AppConfig.TAG, "Failed to encode text to base64", e)
""

View File

@@ -42,6 +42,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_VPN_DNS,
AppConfig.PREF_VPN_BYPASS_LAN,
AppConfig.PREF_VPN_INTERFACE_ADDRESS_CONFIG_INDEX,
AppConfig.PREF_VPN_MTU,
AppConfig.PREF_REMOTE_DNS,
AppConfig.PREF_DOMESTIC_DNS,
AppConfig.PREF_DNS_HOSTS,
@@ -59,6 +60,8 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_FRAGMENT_LENGTH,
AppConfig.PREF_FRAGMENT_INTERVAL,
AppConfig.PREF_MUX_XUDP_QUIC,
AppConfig.PREF_HEV_TUNNEL_LOGLEVEL,
AppConfig.PREF_HEV_TUNNEL_RW_TIMEOUT
-> {
MmkvManager.encodeSettings(key, sharedPreferences.getString(key, ""))
}
@@ -72,20 +75,20 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application
AppConfig.PREF_APPEND_HTTP_PROXY,
AppConfig.PREF_ALLOW_INSECURE,
AppConfig.PREF_PREFER_IPV6,
AppConfig.PREF_PER_APP_PROXY,
// AppConfig.PREF_PER_APP_PROXY,
AppConfig.PREF_BYPASS_APPS,
AppConfig.PREF_CONFIRM_REMOVE,
AppConfig.PREF_START_SCAN_IMMEDIATE,
AppConfig.PREF_DOUBLE_COLUMN_DISPLAY,
AppConfig.SUBSCRIPTION_AUTO_UPDATE,
AppConfig.PREF_FRAGMENT_ENABLED,
AppConfig.PREF_MUX_ENABLED,
AppConfig.PREF_USE_HEV_TUNNEL
AppConfig.PREF_MUX_ENABLED
-> {
MmkvManager.encodeSettings(key, sharedPreferences.getBoolean(key, false))
}
AppConfig.PREF_SNIFFING_ENABLED -> {
AppConfig.PREF_SNIFFING_ENABLED,
AppConfig.PREF_USE_HEV_TUNNEL -> {
MmkvManager.encodeSettings(key, sharedPreferences.getBoolean(key, true))
}

View File

@@ -236,7 +236,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:orientation="vertical"
android:padding="@dimen/padding_spacing_dp16">
<TextView
@@ -245,6 +245,13 @@
android:layout_height="wrap_content"
android:text="@string/title_about"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
<TextView
android:id="@+id/tv_app_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/title_about"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
</LinearLayout>
</LinearLayout>

View File

@@ -81,6 +81,7 @@
<string name="server_lab_preshared_key">PreSharedKey(optional)</string>
<string name="server_lab_short_id" translatable="false">المعرّف القصير</string>
<string name="server_lab_spider_x" translatable="false">SpiderX</string>
<string name="server_lab_mldsa65_verify">Mldsa65Verify</string>
<string name="server_lab_secret_key" translatable="false">المفتاح السري</string>
<string name="server_lab_reserved">محجوز (اختياري)</string>
<string name="server_lab_local_address">العنوان المحلي (اختياري IPv4/IPv6، مفصولة بفواصل)</string>
@@ -183,6 +184,7 @@
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">DNS المحلي (اختياري)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -249,6 +251,8 @@
<string name="title_pref_ui_mode_night">إعدادات وضع واجهة المستخدم ليلاً</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev Tun Log Level</string>
<string name="title_pref_hev_tunnel_rw_timeout">Hev Tun Read/Write Timeout (ms, default 300000)</string>
<string name="title_logcat">Logcat</string>
<string name="logcat_copy">نسخ</string>
@@ -373,5 +377,6 @@
<item>Least Ping</item>
<item>Least Load</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -184,6 +184,7 @@
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">ঘরোয়া DNS (ঐচ্ছিক)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -250,6 +251,8 @@
<string name="title_pref_ui_mode_night">ইউআই মোড সেটিংস</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev Tun Log Level</string>
<string name="title_pref_hev_tunnel_rw_timeout">Hev Tun Read/Write Timeout (ms, default 300000)</string>
<string name="title_logcat">লগক্যাট</string>
<string name="logcat_copy">কপি করুন</string>
@@ -379,5 +382,6 @@
<item>Least Ping</item>
<item>Least Load</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -184,6 +184,7 @@
<string name="title_pref_vpn_bypass_lan">VPN ز شبکه مهلی اگوڌرته؟</string>
<string name="title_pref_vpn_interface_address">نشۊوی رابت VPN</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">DNS منی (اختیاری)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -222,7 +223,7 @@
<!-- AboutActivity -->
<string name="title_pref_feedback">فشناڌن منشڌ</string>
<string name="summary_pref_feedback">فشناڌن منشڌ یا داسووݩ موشکلا من Github</string>
<string name="summary_pref_tg_group">ٱووڌن من جرگه تلگرام</string>
<string name="summary_pref_tg_group">ٱووڌن من بونکۊ تلگرام</string>
<string name="toast_tg_app_not_found">برنومه تلگرامن نجوست</string>
<string name="title_privacy_policy">هریم سیخومی</string>
<string name="title_about">زبار</string>
@@ -248,18 +249,20 @@
<string name="title_language">زووݩ</string>
<string name="title_ui_settings">سامووا رابت منتوری</string>
<string name="title_pref_ui_mode_night">سامووا هالت رابت منتوری</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_use_hev_tunnel">فعال کردن ویژیی نۊ TUN</string>
<string name="summary_pref_use_hev_tunnel">ٱر ک فعال بۊ، TUN ایا hev-socks5-tunnel ن و کار اگره؛ ٱندی ز badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev Tun سئت گوزارشا</string>
<string name="title_pref_hev_tunnel_rw_timeout">Hev Tun زمووݩ مندیر بیڌن خوندن وو هؽل کردن (میلی سانیه، پؽش فرز 300000)</string>
<string name="title_logcat">داسووا</string>
<string name="logcat_copy">لف گیری</string>
<string name="logcat_clear">روفتن</string>
<string name="title_service_restart">ر وندن دووارته خدمات</string>
<string name="title_del_all_config">پاک کردن پوی کانفیگا جرگه سکویی</string>
<string name="title_del_duplicate_config">پاک کردن کانفیگا تکراری جرگه سکویی</string>
<string name="title_del_invalid_config">پاک کردن کانفیگا نا موئتبر جرگه سکویی</string>
<string name="title_export_all">و در کشیڌن کانفیگا غیر سفارشی جرگه سکویی من کلیپ بورد</string>
<string name="title_sub_setting">سامووا جرگه اشتراک</string>
<string name="title_del_all_config">پاک کردن پوی کانفیگا بونکۊ سکویی</string>
<string name="title_del_duplicate_config">پاک کردن کانفیگا تکراری بونکۊ سکویی</string>
<string name="title_del_invalid_config">پاک کردن کانفیگا نا موئتبر بونکۊ سکویی</string>
<string name="title_export_all">و در کشیڌن کانفیگا غیر سفارشی بونکۊ سکویی من کلیپ بورد</string>
<string name="title_sub_setting">سامووا بونکۊ اشتراک</string>
<string name="sub_setting_remarks">نیشتنا</string>
<string name="sub_setting_url">نشۊوی اینترنتی اختیاری</string>
<string name="sub_setting_filter">نوم موستعار فیلتر</string>
@@ -269,14 +272,14 @@
<string name="sub_setting_pre_profile">نوم موستعار پروکسی دیندایی</string>
<string name="sub_setting_next_profile">نوم موستعار پروکسی نیایی</string>
<string name="sub_setting_pre_profile_tip">موتمعن بۊ ک نوم موستعار هڌس وو جۊرس نی</string>
<string name="title_sub_update">ورۊ کردن اشتراک جرگه سکویی</string>
<string name="title_ping_all_server">Tcping کانفیگا جرگه سکویی</string>
<string name="title_real_ping_all_server">تئخیر واقعی کانفیگا جرگه سکویی</string>
<string name="title_create_intelligent_selection_all_server">وورکل پسند هۊشمند کانفیگ جرگه سکویی</string>
<string name="title_sub_update">ورۊ کردن اشتراک بونکۊ سکویی</string>
<string name="title_ping_all_server">Tcping کانفیگا بونکۊ سکویی</string>
<string name="title_real_ping_all_server">تئخیر واقعی کانفیگا بونکۊ سکویی</string>
<string name="title_create_intelligent_selection_all_server">وورکل پسند هۊشمند کانفیگ بونکۊ سکویی</string>
<string name="title_user_asset_setting">فایلا بونچک جوقرافیایی</string>
<string name="title_sort_by_test_results">ترتیب و ری نتیجه یل آزمایش</string>
<string name="title_filter_config">فیلتر کردن کانفیگا</string>
<string name="filter_config_all">پوی جرگه یل کانفیگ</string>
<string name="filter_config_all">پوی بونکۊ یل کانفیگ</string>
<string name="title_del_duplicate_config_count">پاک کردن %d کانفیگ تکراری</string>
<string name="title_del_config_count">پاک کردن %d کانفیگ</string>
@@ -386,8 +389,9 @@
<string name="sub_setting_intelligent_selection_filter">گوڌنا دیاری پسند هۊشمند فیلتر مئمۊلی</string>
<string name="title_intelligent_selection_method">بارت پسند هۊشمند</string>
<string-array name="intelligent_selection_method">
<item>بلم ترین پینگ</item>
<item>هدقل بار</item>
<item>کم ترین پینگ</item>
<item>کم ترین بار(لود)</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -181,7 +181,8 @@
<string name="title_pref_vpn_dns">VPN DNS (فقط IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">آیا VPN از شبکه محلی عبور می کند؟</string>
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
<string name="title_pref_vpn_interface_address">آدرس واسط VPN</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">DNS داخلی (اختیاری)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -245,8 +246,10 @@
<string name="title_language">زبان</string>
<string name="title_ui_settings">تنظیمات رابط کاربری</string>
<string name="title_pref_ui_mode_night">تنظیمات حالت رابط کاربری</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_use_hev_tunnel">فعالسازی قابلیت TUN جدید</string>
<string name="summary_pref_use_hev_tunnel">در صورت فعال بودن، TUN از hev-socks5-tunnel استفاده می‌کند؛ در غیر این صورت از badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">سطح گزارشات Hev Tun</string>
<string name="title_pref_hev_tunnel_rw_timeout">زمان انتظار خواندن/نوشتن (میلی‌ثانیه، پیش‌فرض ۳۰۰۰۰۰) Hev Tun</string>
<string name="title_logcat">گزارشات</string>
<string name="logcat_copy">کپی</string>
@@ -388,5 +391,6 @@
<item>کمترین پینگ</item>
<item>کمترین بار(لود)</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -80,7 +80,7 @@
<string name="server_lab_preshared_key">Дополнительный ключ шифрования (необязательно)</string>
<string name="server_lab_short_id">ShortID</string>
<string name="server_lab_spider_x">SpiderX</string>
<string name="server_lab_mldsa65_verify">Mldsa65Verify</string>
<string name="server_lab_mldsa65_verify">mldsa65Verify</string>
<string name="server_lab_secret_key">Закрытый ключ</string>
<string name="server_lab_reserved">Reserved (необязательно, через запятую)</string>
<string name="server_lab_local_address">Локальный адрес (необязательно, IPv4/IPv6 через запятую)</string>
@@ -90,7 +90,7 @@
<string name="toast_none_data">Ничего нет</string>
<string name="toast_incorrect_protocol">Неправильный протокол</string>
<string name="toast_decoding_failed">Невозможно декодировать</string>
<string name="title_file_chooser">Выберите файл профиля</string>
<string name="title_file_chooser">Выберите профиль</string>
<string name="toast_require_file_manager">Установите файловый менеджер</string>
<string name="server_customize_config">Изменить профиль</string>
<string name="toast_config_file_invalid">Неправильный профиль</string>
@@ -159,11 +159,11 @@
<item>Пропускать</item>
</string-array>
<string name="title_pref_speed_enabled">Отображение скорости</string>
<string name="title_pref_speed_enabled">Показывать скорость</string>
<string name="summary_pref_speed_enabled">Показывать текущую скорость в уведомлении.\nЗначок будет меняться в зависимости от использования.</string>
<string name="title_pref_sniffing_enabled">Анализ пакетов</string>
<string name="summary_pref_sniffing_enabled">Использовать определение доменных имён в пакетах (по умолчанию включено)</string>
<string name="title_pref_sniffing_enabled">Анализировать пакеты</string>
<string name="summary_pref_sniffing_enabled">Пытаться определелять доменные имена в пакетах (по умолчанию включено)</string>
<string name="title_pref_route_only_enabled">Домен только для маршрутизации</string>
<string name="summary_pref_route_only_enabled">Использовать доменное имя только для маршрутизации и сохранять целевой адрес в виде IP.</string>
@@ -182,7 +182,8 @@
<string name="title_pref_vpn_dns">VPN DNS (только IPv4/v6)</string>
<string name="title_pref_vpn_bypass_lan">VPN обходит LAN</string>
<string name="title_pref_vpn_interface_address">VPN частный IP</string>
<string name="title_pref_vpn_interface_address">Адрес интерфейса VPN</string>
<string name="title_pref_vpn_mtu">VPN MTU (по умолчанию 1500)</string>
<string name="title_pref_domestic_dns">Внутренняя DNS (необязательно)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -190,14 +191,14 @@
<string name="title_pref_dns_hosts">Узлы DNS (формат: домен:адрес,…)</string>
<string name="summary_pref_dns_hosts">домен:адрес,…</string>
<string name="title_pref_delay_test_url">Сервис проверки времени отклика (HTTP/HTTPS)</string>
<string name="title_pref_delay_test_url">Сервис проверки задержки (HTTP/HTTPS)</string>
<string name="summary_pref_delay_test_url">URL</string>
<string name="title_pref_proxy_sharing_enabled">Разрешать подключения из LAN</string>
<string name="summary_pref_proxy_sharing_enabled">Другие устройства могут подключаться, используя ваш IP-адрес, чтобы использовать локальный прокси. Используйте только в доверенной сети, чтобы избежать несанкционированного подключения.</string>
<string name="toast_warning_pref_proxysharing_short">Доступ из LAN разрешён, убедитесь, что вы находитесь в доверенной сети</string>
<string name="title_pref_allow_insecure">Разрешать небезопасные</string>
<string name="title_pref_allow_insecure">Разрешать небезопасные соединения</string>
<string name="summary_pref_allow_insecure">Для TLS по умолчанию разрешены небезопасные соединения</string>
<string name="title_pref_socks_port">Порт локального прокси</string>
@@ -206,17 +207,17 @@
<string name="title_pref_local_dns_port">Порт локальной DNS</string>
<string name="summary_pref_local_dns_port">Порт локальной DNS</string>
<string name="title_pref_confirm_remove">Подтверждение удаления профиля</string>
<string name="summary_pref_confirm_remove">Требовать двойное подтверждение удаления профиля</string>
<string name="title_pref_confirm_remove">Подтверждать удаление профиля</string>
<string name="summary_pref_confirm_remove">Обязательное подтверждение удаления профиля</string>
<string name="title_pref_start_scan_immediate">Сканирование при запуске</string>
<string name="title_pref_start_scan_immediate">Сканировать при запуске</string>
<string name="summary_pref_start_scan_immediate">Начинать сканирование сразу при запуске приложения или запускать функцию сканирования камерой или из изображения через панель инструментов</string>
<string name="title_pref_append_http_proxy">Дополнительный HTTP-прокси</string>
<string name="summary_pref_append_http_proxy">HTTP-прокси будет использоваться напрямую (из браузера и других поддерживающих приложений), минуя виртуальный сетевой адаптер (Android 10+)</string>
<string name="title_pref_double_column_display">Отображение в два столбца</string>
<string name="summary_pref_double_column_display">Список профилей выводится в виде двух столбцов, что позволяет показать больше информации на экране. Требуется перезапуск приложения.</string>
<string name="title_pref_double_column_display">Профили в два столбца</string>
<string name="summary_pref_double_column_display">Список профилей отображается двумя столбцами, что позволяет показать больше информации на экране. Требуется перезапуск приложения.</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">Обратная связь</string>
@@ -236,19 +237,21 @@
<string name="title_pref_promotion">Содействие</string>
<string name="summary_pref_promotion">Содействие, нажмите для получения подробной информации (пожертвование может быть удалено)</string>
<string name="title_pref_auto_update_subscription">Автоматическое обновление подписок</string>
<string name="title_pref_auto_update_subscription">Автоматически обновлять подписки</string>
<string name="summary_pref_auto_update_subscription">Автоматическое обновление подписок в фоновом режиме с указанным интервалом. В зависимости от устройства эта функция может работать не всегда.</string>
<string name="title_pref_auto_update_interval">Интервал автообновления (минут, не менее 15)</string>
<string name="title_core_loglevel">Подробность ведения журнала</string>
<string name="title_outbound_domain_resolve_method">Предварительное определение исходящего домена</string>
<string name="title_outbound_domain_resolve_method">Предопределение исходящего домена</string>
<string name="title_mode">Режим</string>
<string name="title_mode_help">Нажмите для получения дополнительной информации</string>
<string name="title_language">Язык</string>
<string name="title_ui_settings">Настройки интерфейса</string>
<string name="title_pref_ui_mode_night">Тема интерфейса</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_use_hev_tunnel">Использовать новую версию TUN</string>
<string name="summary_pref_use_hev_tunnel">Если включено, TUN будет использовать hev-socks5-tunnel, иначе будет использоваться badvpn-tun2socks</string>
<string name="title_pref_hev_tunnel_loglevel">Подробность журнала HevTun</string>
<string name="title_pref_hev_tunnel_rw_timeout">Время ожидания чтения/записи HevTun (мс, по умолчанию 300000)</string>
<string name="title_logcat">Журнал</string>
<string name="logcat_copy">Копировать</string>
@@ -270,11 +273,11 @@
<string name="sub_setting_pre_profile_tip">Конфигурация должна быть уникальной</string>
<string name="title_sub_update">Обновить подписку группы</string>
<string name="title_ping_all_server">Проверить профили группы</string>
<string name="title_real_ping_all_server">Время отклика профилей группы</string>
<string name="title_real_ping_all_server">Проверить задержку профилей группы</string>
<string name="title_create_intelligent_selection_all_server">Создать конфигурацию умного выбора</string>
<string name="title_user_asset_setting">Файлы ресурсов</string>
<string name="title_sort_by_test_results">Сортировать по результатам теста</string>
<string name="title_filter_config">Фильтр групп</string>
<string name="title_filter_config">Фильтр профилей</string>
<string name="filter_config_all">Все группы</string>
<string name="title_del_duplicate_config_count">Удалено дубликатов профилей: %d</string>
<string name="title_del_config_count">Удалено профилей: %d</string>
@@ -388,5 +391,6 @@
<item>Наименьшая задержка</item>
<item>Наименьшая нагрузка</item>
</string-array>
<string name="pre_resolving_domain">Предварительное определение домена…</string>
</resources>

View File

@@ -184,6 +184,7 @@
<string name="title_pref_vpn_bypass_lan">Does VPN bypass LAN</string>
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">DNS nội địa (Không bắt buộc)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -250,6 +251,8 @@
<string name="title_pref_ui_mode_night">Cài đặt chế độ UI</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev Tun Log Level</string>
<string name="title_pref_hev_tunnel_rw_timeout">Hev Tun Read/Write Timeout (ms, default 300000)</string>
<string name="title_logcat">Logcat</string>
<string name="logcat_copy">Sao chép</string>
@@ -376,5 +379,6 @@
<item>Least Ping</item>
<item>Least Load</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -20,7 +20,7 @@
<string name="toast_services_failure">启动服务失败</string>
<!--ServerActivity-->
<string name="title_server">配置文件</string>
<string name="title_server">配置</string>
<string name="menu_item_add_config">添加配置</string>
<string name="menu_item_save_config">保存配置</string>
<string name="menu_item_del_config">删除配置</string>
@@ -90,10 +90,10 @@
<string name="toast_none_data">没有数据</string>
<string name="toast_incorrect_protocol">不正确的协议</string>
<string name="toast_decoding_failed">解码失败</string>
<string name="title_file_chooser">选择一个配置文件</string>
<string name="title_file_chooser">选择一个配置</string>
<string name="toast_require_file_manager">请安装一个文件管理器</string>
<string name="server_customize_config">自定义配置</string>
<string name="toast_config_file_invalid">无效的配置文件</string>
<string name="toast_config_file_invalid">无效的配置</string>
<string name="server_lab_content">内容</string>
<string name="toast_none_data_clipboard">剪贴板中没有数据</string>
<string name="toast_invalid_url">无效的网址</string>
@@ -181,6 +181,7 @@
<string name="title_pref_vpn_bypass_lan">VPN 是否绕过局域网</string>
<string name="title_pref_vpn_interface_address">VPN 接口地址</string>
<string name="title_pref_vpn_mtu">VPN MTU (默认 1500)</string>
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -204,8 +205,8 @@
<string name="title_pref_local_dns_port">本地 DNS 端口</string>
<string name="summary_pref_local_dns_port">本地 DNS 端口</string>
<string name="title_pref_confirm_remove">删除配置文件确认</string>
<string name="summary_pref_confirm_remove">删除配置文件是否需要用户二次确认</string>
<string name="title_pref_confirm_remove">删除配置确认</string>
<string name="summary_pref_confirm_remove">删除配置是否需要用户二次确认</string>
<string name="title_pref_start_scan_immediate">立即启动扫码</string>
<string name="summary_pref_start_scan_immediate">启动时立即打开相机扫描,否则可在工具栏选择扫码或选照片</string>
@@ -214,7 +215,7 @@
<string name="summary_pref_append_http_proxy">浏览器 / 一些支持的应用 将直接使用 HTTP 代理, 而不经过虚拟网卡设备 (Android 10+)</string>
<string name="title_pref_double_column_display">启用双列显示</string>
<string name="summary_pref_double_column_display">配置文件列表以双列显示,允许在屏幕上显示更多内容。需要重启应用生效。</string>
<string name="summary_pref_double_column_display">配置列表以双列显示,允许在屏幕上显示更多内容。需要重启应用生效。</string>
<!-- AboutActivity -->
<string name="title_pref_feedback">反馈</string>
@@ -247,6 +248,8 @@
<string name="title_pref_ui_mode_night">界面颜色设置</string>
<string name="title_pref_use_hev_tunnel">启用新的 TUN 功能</string>
<string name="summary_pref_use_hev_tunnel">选择启用后 TUN 将使用 hev-socks5-tunnel 否则使用 badvpn-tun2socks</string>
<string name="title_pref_hev_tunnel_loglevel">HevTun 日志级别</string>
<string name="title_pref_hev_tunnel_rw_timeout">HevTun 读写超时 (ms, 默认 300000)</string>
<string name="title_logcat">Logcat</string>
<string name="logcat_copy">复制</string>
@@ -263,16 +266,16 @@
<string name="sub_setting_enable">启用更新</string>
<string name="sub_auto_update">启用自动更新</string>
<string name="sub_allow_insecure_url">允许不安全的 HTTP 地址</string>
<string name="sub_setting_pre_profile">前置代理配置文件别名</string>
<string name="sub_setting_next_profile">落地代理配置文件別名</string>
<string name="sub_setting_pre_profile_tip">请确保配置文件别名存在并唯一</string>
<string name="sub_setting_pre_profile">前置代理配置别名</string>
<string name="sub_setting_next_profile">落地代理配置別名</string>
<string name="sub_setting_pre_profile_tip">请确保配置别名存在并唯一</string>
<string name="title_sub_update">更新当前组订阅</string>
<string name="title_ping_all_server">测试当前组配置 Tcping</string>
<string name="title_real_ping_all_server">测试当前组配置真连接</string>
<string name="title_create_intelligent_selection_all_server">生成当前组智能选择配置</string>
<string name="title_user_asset_setting">资源文件</string>
<string name="title_sort_by_test_results">按测试结果排序</string>
<string name="title_filter_config">过滤配置文件</string>
<string name="title_filter_config">过滤配置</string>
<string name="filter_config_all">所有分组</string>
<string name="title_del_duplicate_config_count">删除 %d 个重复配置</string>
@@ -363,7 +366,7 @@
</string-array>
<string-array name="vpn_bypass_lan">
<item>跟随配置文件</item>
<item>跟随配置</item>
<item>绕过</item>
<item>不绕过</item>
</string-array>
@@ -380,5 +383,6 @@
<item>最低延迟</item>
<item>最稳定</item>
</string-array>
<string name="pre_resolving_domain">预解析域名中…</string>
</resources>

View File

@@ -183,6 +183,7 @@
<string name="title_pref_vpn_bypass_lan">VPN 是否繞過區域網</string>
<string name="title_pref_vpn_interface_address">VPN 介面位址</string>
<string name="title_pref_vpn_mtu">VPN MTU (預設 1500)</string>
<string name="summary_pref_domestic_dns">DNS</string>
<string name="title_pref_domestic_dns">境内 DNS (可选)</string>
@@ -248,6 +249,8 @@
<string name="title_pref_ui_mode_night">介面顯示模式</string>
<string name="title_pref_use_hev_tunnel">啟用新 TUN 功能</string>
<string name="summary_pref_use_hev_tunnel">選擇啟用後TUN 將使用 hev-socks5-tunnel否則使用 badvpn-tun2socks。</string>
<string name="title_pref_hev_tunnel_loglevel">HevTun 日誌級別</string>
<string name="title_pref_hev_tunnel_rw_timeout">HevTun 讀寫逾時 (ms, 預設 300000)</string>
<string name="title_logcat">Logcat</string>
<string name="logcat_copy">複製</string>
@@ -380,5 +383,6 @@
<item>Least Ping</item>
<item>Least Load</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -118,6 +118,13 @@
<item>Proxy only</item>
</string-array>
<string-array name="hev_tunnel_loglevel" translatable="false">
<item>none</item>
<item>error</item>
<item>warn</item>
<item>debug</item>
</string-array>
<string-array name="flows" translatable="false">
<item></item>
<item>xtls-rprx-vision</item>

View File

@@ -21,13 +21,13 @@
<string name="toast_services_failure">Start Services Failure</string>
<!--ServerActivity-->
<string name="title_server">Configuration file</string>
<string name="menu_item_add_config">Add config</string>
<string name="menu_item_save_config">Save config</string>
<string name="menu_item_del_config">Delete config</string>
<string name="menu_item_import_config_qrcode">Import config from QRcode</string>
<string name="menu_item_import_config_clipboard">Import config from Clipboard</string>
<string name="menu_item_import_config_local">Import config from locally</string>
<string name="title_server">Configuration</string>
<string name="menu_item_add_config">Add configuration</string>
<string name="menu_item_save_config">Save configuration</string>
<string name="menu_item_del_config">Delete configuration</string>
<string name="menu_item_import_config_qrcode">Import configuration from QRcode</string>
<string name="menu_item_import_config_clipboard">Import configuration from Clipboard</string>
<string name="menu_item_import_config_local">Import configuration from locally</string>
<string name="menu_item_import_config_manually_vmess">Type manually[VMess]</string>
<string name="menu_item_import_config_manually_vless">Type manually[VLESS]</string>
<string name="menu_item_import_config_manually_ss">Type manually[Shadowsocks]</string>
@@ -91,16 +91,16 @@
<string name="toast_none_data">There is nothing</string>
<string name="toast_incorrect_protocol">Incorrect protocol</string>
<string name="toast_decoding_failed">Decoding failed</string>
<string name="title_file_chooser">Select a Config File</string>
<string name="title_file_chooser">Select a configuration</string>
<string name="toast_require_file_manager">Please install a File Manager.</string>
<string name="server_customize_config">Customize Config</string>
<string name="toast_config_file_invalid">Invalid Config</string>
<string name="server_customize_config">Customize configuration</string>
<string name="toast_config_file_invalid">Invalid configuration</string>
<string name="server_lab_content">Content</string>
<string name="toast_none_data_clipboard">There is no data in the clipboard</string>
<string name="toast_invalid_url">Invalid URL</string>
<string name="toast_insecure_url_protocol">Please do not use the insecure HTTP protocol subscription address</string>
<string name="server_lab_need_inbound">Ensure inbounds port is consistent with the settings</string>
<string name="toast_malformed_josn">Config malformed</string>
<string name="toast_malformed_josn">Configuration malformed</string>
<string name="server_lab_request_host6">Host(SNI)(Optional)</string>
<string name="toast_action_not_allowed">Action not allowed</string>
<string name="server_obfs_password">Obfs password</string>
@@ -186,6 +186,9 @@
<string name="title_pref_vpn_interface_address">VPN Interface Address</string>
<string name="title_pref_vpn_mtu">VPN MTU (default 1500)</string>
<string name="title_pref_domestic_dns">Domestic DNS (Optional)</string>
<string name="summary_pref_domestic_dns">DNS</string>
@@ -208,8 +211,8 @@
<string name="title_pref_local_dns_port">Local DNS port</string>
<string name="summary_pref_local_dns_port">Local DNS port</string>
<string name="title_pref_confirm_remove">Delete configuration file confirmation</string>
<string name="summary_pref_confirm_remove">Whether to delete the configuration file requires a second confirmation by the user</string>
<string name="title_pref_confirm_remove">Delete configuration confirmation</string>
<string name="summary_pref_confirm_remove">Whether to delete the configuration requires a second confirmation by the user</string>
<string name="title_pref_start_scan_immediate">Start scanning immediately</string>
<string name="summary_pref_start_scan_immediate">Open the camera to scan immediately at startup, otherwise you can choose to scan the code or select a photo in the toolbar</string>
@@ -251,6 +254,8 @@
<string name="title_pref_ui_mode_night">UI mode settings</string>
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
<string name="title_pref_hev_tunnel_loglevel">Hev Tun Log Level</string>
<string name="title_pref_hev_tunnel_rw_timeout">Hev Tun Read/Write Timeout (ms, default 300000)</string>
<string name="title_logcat">Logcat</string>
<string name="logcat_copy">Copy</string>
@@ -276,7 +281,7 @@
<string name="title_create_intelligent_selection_all_server">Creating Intelligent Selection Current Group Configuration</string>
<string name="title_user_asset_setting">Asset files</string>
<string name="title_sort_by_test_results">Sorting by test results</string>
<string name="title_filter_config">Filter configuration file</string>
<string name="title_filter_config">Filter configuration</string>
<string name="filter_config_all">All groups</string>
<string name="title_del_duplicate_config_count">Delete %d duplicate configurations</string>
<string name="title_del_config_count">Delete %d configurations</string>
@@ -373,7 +378,7 @@
</string-array>
<string-array name="vpn_bypass_lan">
<item>Follow config</item>
<item>Follow configuration</item>
<item>Bypass</item>
<item>Not Bypass</item>
</string-array>
@@ -390,5 +395,6 @@
<item>Least Ping</item>
<item>Least Load</item>
</string-array>
<string name="pre_resolving_domain">Pre-resolving domain…</string>
</resources>

View File

@@ -25,10 +25,10 @@
android:summary="@string/summary_pref_prefer_ipv6"
android:title="@string/title_pref_prefer_ipv6" />
<CheckBoxPreference
android:key="pref_per_app_proxy"
android:summary="@string/summary_pref_per_app_proxy"
android:title="@string/title_pref_per_app_proxy" />
<!-- <CheckBoxPreference-->
<!-- android:key="pref_per_app_proxy"-->
<!-- android:summary="@string/summary_pref_per_app_proxy"-->
<!-- android:title="@string/title_pref_per_app_proxy" />-->
<CheckBoxPreference
android:key="pref_local_dns_enabled"
@@ -71,6 +71,32 @@
android:key="pref_vpn_interface_address_config_index"
android:summary="%s"
android:title="@string/title_pref_vpn_interface_address" />
<EditTextPreference
android:inputType="number"
android:key="pref_vpn_mtu"
android:summary="1500"
android:title="@string/title_pref_vpn_mtu" />
<CheckBoxPreference
android:defaultValue="true"
android:key="pref_use_hev_tunnel"
android:summary="@string/summary_pref_use_hev_tunnel"
android:title="@string/title_pref_use_hev_tunnel" />
<ListPreference
android:defaultValue="none"
android:entries="@array/hev_tunnel_loglevel"
android:entryValues="@array/hev_tunnel_loglevel"
android:key="pref_hev_tunnel_loglevel"
android:summary="%s"
android:title="@string/title_pref_hev_tunnel_loglevel" />
<EditTextPreference
android:inputType="number"
android:key="pref_hev_tunnel_rw_timeout"
android:summary="300000"
android:title="@string/title_pref_hev_tunnel_rw_timeout" />
</PreferenceCategory>
<PreferenceCategory android:title="@string/title_ui_settings">
@@ -256,11 +282,6 @@
android:summary="%s"
android:title="@string/title_mode" />
<CheckBoxPreference
android:key="pref_use_hev_tunnel"
android:summary="@string/summary_pref_use_hev_tunnel"
android:title="@string/title_pref_use_hev_tunnel" />
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -1,17 +1,17 @@
[versions]
agp = "8.12.0"
agp = "8.12.3"
desugarJdkLibs = "2.1.5"
gradleLicensePlugin = "0.9.8"
kotlin = "2.1.21"
kotlin = "2.2.20"
coreKtx = "1.16.0"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
junitVersion = "1.3.0"
espressoCore = "3.7.0"
appcompat = "1.7.1"
material = "1.12.0"
material = "1.13.0"
activity = "1.10.1"
constraintlayout = "2.2.1"
mmkvStatic = "1.3.12"
mmkvStatic = "1.3.14"
gson = "2.12.1"
quickieFoss = "1.14.0"
kotlinxCoroutinesAndroid = "1.10.2"
@@ -20,8 +20,8 @@ swiperefreshlayout = "1.1.0"
toasty = "1.5.2"
editorkit = "2.9.0"
core = "3.5.3"
workRuntimeKtx = "2.10.2"
lifecycleViewmodelKtx = "2.9.2"
workRuntimeKtx = "2.10.5"
lifecycleViewmodelKtx = "2.9.4"
multidex = "2.0.1"
mockitoMockitoInline = "5.2.0"
flexbox = "3.0.0"

View File

@@ -1,6 +1,6 @@
#Thu Nov 14 12:42:51 BDT 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -30,3 +30,29 @@ $NDK_HOME/ndk-build \
cp -r $TMPDIR/libs $__dir/
popd
rm -rf $TMPDIR
#build hev-socks5-tunnel
HEVTUN_TMP=$(mktemp -d)
trap 'rm -rf "$HEVTUN_TMP"' EXIT
mkdir -p "$HEVTUN_TMP/jni"
pushd "$HEVTUN_TMP"
echo 'include $(call all-subdir-makefiles)' > jni/Android.mk
ln -s "$__dir/hev-socks5-tunnel" jni/hev-socks5-tunnel
"$NDK_HOME/ndk-build" \
NDK_PROJECT_PATH=. \
APP_BUILD_SCRIPT=jni/Android.mk \
"APP_ABI=armeabi-v7a arm64-v8a x86 x86_64" \
APP_PLATFORM=android-21 \
NDK_LIBS_OUT="$HEVTUN_TMP/libs" \
NDK_OUT="$HEVTUN_TMP/obj" \
"APP_CFLAGS=-O3 -DPKGNAME=com/v2ray/ang/service" \
"APP_LDFLAGS=-WI,--build-id=none -WI,--hash-style=gnu" \
cp -r "$HEVTUN_TMP/libs/"* "$__dir/libs/"
popd
rm -rf "$HEVTUN_TMP"

1
hev-socks5-tunnel Submodule

Submodule hev-socks5-tunnel added at 0239bd443f