From 1f6f538aaac9c66c2f59e8f1b87c25a412be2722 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 11:41:07 +0800 Subject: [PATCH 01/23] Enable metered connection setting for VPN builder Revoke the default metered connections on Android Q and above. --- .../main/kotlin/com/simplexray/an/service/TProxyService.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt index 1b67c055..a021b0f6 100644 --- a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt +++ b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt @@ -295,6 +295,10 @@ class TProxyService : VpnService() { setBlocking(false) setMtu(prefs.tunnelMtu) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + setMetered(false) + } + if (prefs.bypassLan) { addRoute("10.0.0.0", 8) addRoute("172.16.0.0", 12) @@ -440,4 +444,4 @@ tunnel: return tproxyConf } } -} \ No newline at end of file +} From c339760d4429c428b975c7d1554a1236eacd7abc Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 12:24:47 +0800 Subject: [PATCH 02/23] Change build process to assembleDebug APK --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6fc23aea..cc3779b6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,7 +100,7 @@ jobs: run: chmod +x ./gradlew - name: Build Release APK - run: ./gradlew assembleRelease + run: ./gradlew assembleDebug - name: Find and Copy APKs run: | From 7547b0186b669a1279a6d36f68e1295571659607 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 12:37:30 +0800 Subject: [PATCH 03/23] Disable signingConfig for debug build Comment out signingConfig for debug build type. --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index 0ef06b98..f8eae0c6 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,7 +70,7 @@ android { } debug { minifyEnabled false - signingConfig signingConfigs.release + // signingConfig signingConfigs.release debuggable true } } From 57dccbfc639b119a9c77b227033ce8b1e64bbf40 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 12:48:14 +0800 Subject: [PATCH 04/23] Change APK copy path from release to debug --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cc3779b6..c4e88592 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -105,7 +105,7 @@ jobs: - name: Find and Copy APKs run: | mkdir -p apks - find app/build/outputs/apk/release -name "*.apk" -exec cp {} apks/ \; + find app/build/outputs/apk/debug -name "*.apk" -exec cp {} apks/ \; - name: Upload Artifacts uses: actions/upload-artifact@v4 From b957839f3ba9e32d736e5e8e78e2dce8190987e8 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 13:29:01 +0800 Subject: [PATCH 05/23] Enable signingConfig for debug build --- app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/build.gradle b/app/build.gradle index f8eae0c6..0ef06b98 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,7 +70,7 @@ android { } debug { minifyEnabled false - // signingConfig signingConfigs.release + signingConfig signingConfigs.release debuggable true } } From e2f8484f949150c41d64ec5319eb9750540ff3af Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Mon, 6 Apr 2026 13:30:06 +0800 Subject: [PATCH 06/23] Change build process to assemble release APK --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c4e88592..6fc23aea 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -100,12 +100,12 @@ jobs: run: chmod +x ./gradlew - name: Build Release APK - run: ./gradlew assembleDebug + run: ./gradlew assembleRelease - name: Find and Copy APKs run: | mkdir -p apks - find app/build/outputs/apk/debug -name "*.apk" -exec cp {} apks/ \; + find app/build/outputs/apk/release -name "*.apk" -exec cp {} apks/ \; - name: Upload Artifacts uses: actions/upload-artifact@v4 From 286c283585efd523dedda4bc2de6d71455fcffc4 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:33:27 +0800 Subject: [PATCH 07/23] Update Preferences.kt --- .../main/kotlin/com/simplexray/an/prefs/Preferences.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt b/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt index f0da40a2..3f3e9dcb 100644 --- a/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt +++ b/app/src/main/kotlin/com/simplexray/an/prefs/Preferences.kt @@ -187,6 +187,12 @@ class Preferences(context: Context) { setValueInProvider(DISABLE_VPN, value) } + var useXrayTun: Boolean + get() = getBooleanPref(USE_XRAY_TUN, false) + set(value) { + setValueInProvider(USE_XRAY_TUN, value) + } + val tunnelMtu: Int get() = 8500 @@ -333,6 +339,7 @@ class Preferences(context: Context) { const val CUSTOM_GEOSITE_IMPORTED: String = "CustomGeositeImported" const val CONFIG_FILES_ORDER: String = "ConfigFilesOrder" const val DISABLE_VPN: String = "DisableVpn" + const val USE_XRAY_TUN: String = "UseXrayTun" const val CONNECTIVITY_TEST_TARGET: String = "ConnectivityTestTarget" const val CONNECTIVITY_TEST_TIMEOUT: String = "ConnectivityTestTimeout" const val GEOIP_URL: String = "GeoipUrl" @@ -343,4 +350,4 @@ class Preferences(context: Context) { const val THEME: String = "Theme" private const val TAG = "Preferences" } -} \ No newline at end of file +} From c306572d47007be2f9dd88f66ec1950297a0dc36 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:34:45 +0800 Subject: [PATCH 08/23] Update SettingsState.kt --- .../main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt index 34f59587..97095bcb 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/SettingsState.kt @@ -14,6 +14,7 @@ data class SwitchStates( val httpProxyEnabled: Boolean, val bypassLanEnabled: Boolean, val disableVpn: Boolean, + val useXrayTun: Boolean, val themeMode: ThemeMode ) @@ -42,4 +43,4 @@ data class SettingsState( val files: FileStates, val connectivityTestTarget: InputFieldState, val connectivityTestTimeout: InputFieldState -) \ No newline at end of file +) From 5f5f18aa88cbe2baa093967932d523d5dcc38bdd Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:35:23 +0800 Subject: [PATCH 09/23] Update TProxyService.kt --- .../simplexray/an/service/TProxyService.kt | 54 +++++++++++-------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt index c90c6c5c..f87e75fc 100644 --- a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt +++ b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt @@ -129,7 +129,7 @@ class TProxyService : VpnService() { successIntent.setPackage(application.packageName) sendBroadcast(successIntent) - @Suppress("SameParameterValue") val channelName = "nosocks" + @Suppress("SameParameterValue") val channelName = "xray" initNotificationChannel(channelName) createNotification(channelName) @@ -248,7 +248,7 @@ class TProxyService : VpnService() { } private fun stopXray() { - Log.d(TAG, "stopXray called with keepExecutorAlive=" + false) + Log.d(TAG, "stopXray called") serviceScope.cancel() Log.d(TAG, "CoroutineScope cancelled.") @@ -269,30 +269,39 @@ class TProxyService : VpnService() { stopXray() return } - val tproxyFile = File(cacheDir, "tproxy.conf") - try { - tproxyFile.createNewFile() - FileOutputStream(tproxyFile, false).use { fos -> - val tproxyConf = getTproxyConf(prefs) - fos.write(tproxyConf.toByteArray()) + + // Use Xray native TUN or hev-tun2sock based on preference + if (prefs.useXrayTun) { + Log.d(TAG, "Using Xray native TUN inbound") + Log.d(TAG, "VPN service established. TUN FD: ${tunFd?.fd}") + } else { + Log.d(TAG, "Using hev-socks5-tunnel (legacy mode)") + val tproxyFile = File(cacheDir, "tproxy.conf") + try { + tproxyFile.createNewFile() + FileOutputStream(tproxyFile, false).use { fos -> + val tproxyConf = getTproxyConf(prefs) + fos.write(tproxyConf.toByteArray()) + } + } catch (e: IOException) { + Log.e(TAG, e.toString()) + stopXray() + return + } + tunFd?.fd?.let { fd -> + TProxyStartService(tproxyFile.absolutePath, fd) + Log.d(TAG, "hev-tun2sock service started") + } ?: run { + Log.e(TAG, "tunFd is null after establish()") + stopXray() + return } - } catch (e: IOException) { - Log.e(TAG, e.toString()) - stopXray() - return - } - tunFd?.fd?.let { fd -> - TProxyStartService(tproxyFile.absolutePath, fd) - } ?: run { - Log.e(TAG, "tunFd is null after establish()") - stopXray() - return } val successIntent = Intent(ACTION_START) successIntent.setPackage(application.packageName) sendBroadcast(successIntent) - @Suppress("SameParameterValue") val channelName = "socks5" + @Suppress("SameParameterValue") val channelName = "xray" initNotificationChannel(channelName) createNotification(channelName) } @@ -348,7 +357,10 @@ class TProxyService : VpnService() { tunFd = null } stopForeground(Service.STOP_FOREGROUND_REMOVE) - TProxyStopService() + val prefs = Preferences(this) + if (!prefs.useXrayTun) { + TProxyStopService() + } } exit() } From a3826d46aa9b7f23e08ac5604e8c0771e0697da1 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:37:59 +0800 Subject: [PATCH 10/23] Update MainViewModel.kt --- .../com/simplexray/an/viewmodel/MainViewModel.kt | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 70afe486..62fece20 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -180,7 +180,7 @@ class MainViewModel(application: Application) : } private fun updateSettingsState() { - _settingsState.value = _settingsState.value.copy( + _settingsState.value = SettingsState( socksPort = InputFieldState(prefs.socksPort.toString()), socksUser = InputFieldState(prefs.socksUsername), socksPass = InputFieldState(prefs.socksPassword), @@ -192,10 +192,12 @@ class MainViewModel(application: Application) : httpProxyEnabled = prefs.httpProxyEnabled, bypassLanEnabled = prefs.bypassLan, disableVpn = prefs.disableVpn, + useXrayTun = prefs.useXrayTun, // ADD THIS LINE themeMode = prefs.theme ), - info = _settingsState.value.info.copy( - appVersion = BuildConfig.VERSION_NAME, + info = InfoStates( + appVersion = versionName, + kernelVersion = Build.VERSION.RELEASE, geoipSummary = fileManager.getRuleFileSummary("geoip.dat"), geositeSummary = fileManager.getRuleFileSummary("geosite.dat"), geoipUrl = prefs.geoipUrl, @@ -471,6 +473,14 @@ class MainViewModel(application: Application) : } } + fun setUseXrayTun(enabled: Boolean) { + prefs.useXrayTun = enabled + _settingsState.value = _settingsState.value.copy( + switches = _settingsState.value.switches.copy(useXrayTun = enabled) + ) + Log.d(TAG, "Xray TUN mode: ${if (enabled) "native" else "hev-tun2sock"}") + } + fun updateDnsIpv4(ipv4Addr: String): Boolean { val matcher = IPV4_PATTERN.matcher(ipv4Addr) return if (matcher.matches()) { From ebe04fb7250f5e1f603678b19fd09007d714a810 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:39:49 +0800 Subject: [PATCH 11/23] Update SettingsScreen.kt --- .../com/simplexray/an/ui/screens/SettingsScreen.kt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt b/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt index 8437fdbe..235ca1f5 100644 --- a/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt +++ b/app/src/main/kotlin/com/simplexray/an/ui/screens/SettingsScreen.kt @@ -477,6 +477,20 @@ fun SettingsScreen( } ) + ListItem( + headlineContent = { Text(stringResource(R.string.tun_mode_title)) }, + supportingContent = { Text(stringResource(R.string.tun_mode_summary)) }, + trailingContent = { + Switch( + checked = settingsState.switches.useXrayTun, + onCheckedChange = { + mainViewModel.setUseXrayTun(it) + }, + enabled = !vpnDisabled + ) + } + ) + PreferenceCategoryTitle(stringResource(R.string.rule_files_category_title)) ListItem( From 8bf6786f7828a2b3cfd0a19b3b7a4ab5914b84cb Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:41:46 +0800 Subject: [PATCH 12/23] Update FileManager.kt --- .../main/kotlin/com/simplexray/an/data/source/FileManager.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt b/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt index 62b3150e..01efdf83 100644 --- a/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt +++ b/app/src/main/kotlin/com/simplexray/an/data/source/FileManager.kt @@ -181,6 +181,7 @@ class FileManager(private val application: Application, private val prefs: Prefe prefs.apps ?: emptySet() ) preferencesMap[Preferences.BYPASS_LAN] = prefs.bypassLan + preferencesMap[Preferences.USE_XRAY_TUN] = prefs.useXrayTun preferencesMap[Preferences.USE_TEMPLATE] = prefs.useTemplate preferencesMap[Preferences.HTTP_PROXY_ENABLED] = prefs.httpProxyEnabled preferencesMap[Preferences.CONFIG_FILES_ORDER] = prefs.configFilesOrder @@ -764,4 +765,4 @@ class FileManager(private val application: Application, private val prefs: Prefe companion object { const val TAG = "FileManager" } -} \ No newline at end of file +} From f8d29d5503ad2a4964ccacbcb45be97045bed252 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:43:01 +0800 Subject: [PATCH 13/23] Update strings.xml --- app/src/main/res/values/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2e459a48..0192cd23 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -126,4 +126,6 @@ Light Dark Auto - \ No newline at end of file + Native TUN Mode + Use Xray native TUN inbound or hev-tun2sock + From 7287c3b2fcc1858d6f533eb942cc1b8d4f14ffcb Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:43:32 +0800 Subject: [PATCH 14/23] Update strings.xml --- app/src/main/res/values-zh/strings.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index ff78e747..b567e4a0 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -121,4 +121,6 @@ 深色 自动 SOCKS 用户 - \ No newline at end of file + 原生TUN模式 + 使用Xray原生TUN入站或hev-tun2sock + From bcbde6bf1cfe782dd7fcffbd0b893a06475ff6a5 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:43:53 +0800 Subject: [PATCH 15/23] Update strings.xml --- app/src/main/res/values-id/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 019e2a67..b9c58510 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -121,4 +121,6 @@ Gelap Otomatis "Pengguna SOCKS " + Mode TUN Asli + Gunakan inbound TUN asli Xray (lebih cepat) atau hev-tun2sock (lebih kompatibel) From 479f6c1c3fb98066627e595b9c841dfc03ae8823 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:44:20 +0800 Subject: [PATCH 16/23] Update strings.xml --- app/src/main/res/values-ru-rRU/strings.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 64532f46..006c934f 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -121,4 +121,6 @@ Тёмная Автоматически Пользователь SOCKS + Нативный режим TUN + Используйте встроенный TUN входящий Xray или hev-tun2sock From 10a4750a6c4d9256dd5c4d082ed7e3b060ed96aa Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:44:49 +0800 Subject: [PATCH 17/23] Update strings.xml --- app/src/main/res/values-id/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index b9c58510..5e292689 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -122,5 +122,5 @@ Otomatis "Pengguna SOCKS " Mode TUN Asli - Gunakan inbound TUN asli Xray (lebih cepat) atau hev-tun2sock (lebih kompatibel) + Gunakan inbound TUN asli Xray atau hev-tun2sock From f1b984e265fb4ed27c332c86c8039a3c4e86c5c6 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 18:58:47 +0800 Subject: [PATCH 18/23] Update MainViewModel.kt --- .../main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 62fece20..0bc56403 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -473,7 +473,7 @@ class MainViewModel(application: Application) : } } - fun setUseXrayTun(enabled: Boolean) { + fun setUseXrayTun(enabled: Boolean = false) { prefs.useXrayTun = enabled _settingsState.value = _settingsState.value.copy( switches = _settingsState.value.switches.copy(useXrayTun = enabled) From f4f3575e4f82fa7c21cd035422d3b1189a763246 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 19:13:20 +0800 Subject: [PATCH 19/23] Update MainViewModel.kt --- app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 0bc56403..8d79b4f4 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -94,6 +94,7 @@ class MainViewModel(application: Application) : httpProxyEnabled = prefs.httpProxyEnabled, bypassLanEnabled = prefs.bypassLan, disableVpn = prefs.disableVpn, + useXrayTun = prefs.useXrayTun themeMode = prefs.theme ), info = InfoStates( From 18706670c18bb1c0f528369b9981bbdcf38d8574 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 19:16:13 +0800 Subject: [PATCH 20/23] Update MainViewModel.kt --- .../main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 8d79b4f4..0bc57f8f 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -197,8 +197,7 @@ class MainViewModel(application: Application) : themeMode = prefs.theme ), info = InfoStates( - appVersion = versionName, - kernelVersion = Build.VERSION.RELEASE, + appVersion = BuildConfig.VERSION_NAME, geoipSummary = fileManager.getRuleFileSummary("geoip.dat"), geositeSummary = fileManager.getRuleFileSummary("geosite.dat"), geoipUrl = prefs.geoipUrl, From 262f971a3f93f606ee8c2256c6dae7487dc4a422 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 19:23:16 +0800 Subject: [PATCH 21/23] Update MainViewModel.kt --- .../main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 0bc57f8f..4b6a2e6a 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -94,7 +94,7 @@ class MainViewModel(application: Application) : httpProxyEnabled = prefs.httpProxyEnabled, bypassLanEnabled = prefs.bypassLan, disableVpn = prefs.disableVpn, - useXrayTun = prefs.useXrayTun + useXrayTun = prefs.useXrayTun, themeMode = prefs.theme ), info = InfoStates( From 7a718182871e8f61316200b8eb956e6d08c98e03 Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 19:41:00 +0800 Subject: [PATCH 22/23] Update MainViewModel.kt --- .../main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt index 4b6a2e6a..0453bd02 100644 --- a/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt +++ b/app/src/main/kotlin/com/simplexray/an/viewmodel/MainViewModel.kt @@ -181,7 +181,7 @@ class MainViewModel(application: Application) : } private fun updateSettingsState() { - _settingsState.value = SettingsState( + _settingsState.value = _settingsState.value.copy( socksPort = InputFieldState(prefs.socksPort.toString()), socksUser = InputFieldState(prefs.socksUsername), socksPass = InputFieldState(prefs.socksPassword), @@ -196,7 +196,7 @@ class MainViewModel(application: Application) : useXrayTun = prefs.useXrayTun, // ADD THIS LINE themeMode = prefs.theme ), - info = InfoStates( + info = _settingsState.value.info.copy( appVersion = BuildConfig.VERSION_NAME, geoipSummary = fileManager.getRuleFileSummary("geoip.dat"), geositeSummary = fileManager.getRuleFileSummary("geosite.dat"), From 58ae2cf7ecaa12321c3c29a420c811055dd0002c Mon Sep 17 00:00:00 2001 From: dfliaoyue Date: Sun, 12 Apr 2026 20:06:28 +0800 Subject: [PATCH 23/23] Refactor TProxyService for TUN FD handling Refactor getProcessBuilder to accept Preferences and pass TUN FD when using native TUN mode. Update logging for better clarity. --- .../simplexray/an/service/TProxyService.kt | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt index f87e75fc..7c8abc8f 100644 --- a/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt +++ b/app/src/main/kotlin/com/simplexray/an/service/TProxyService.kt @@ -189,13 +189,17 @@ class TProxyService : VpnService() { prefs.apiAddress = "127.$octet2.$octet3.$octet4" Log.d(TAG, "Randomized API address: ${prefs.apiAddress}") - val processBuilder = getProcessBuilder(xrayPath) + val processBuilder = getProcessBuilder(xrayPath, prefs) currentProcess = processBuilder.start() this.xrayProcess = currentProcess Log.d(TAG, "Writing config to xray stdin from: $selectedConfigPath") - val injectedConfigContent = + val injectedConfigContent = if (prefs.useXrayTun && tunFd != null) { + // Inject TUN inbound into config when using native TUN ConfigUtils.injectStatsService(prefs, configContent) + } else { + ConfigUtils.injectStatsService(prefs, configContent) + } currentProcess.outputStream.use { os -> os.write(injectedConfigContent.toByteArray()) os.flush() @@ -236,12 +240,22 @@ class TProxyService : VpnService() { } } - private fun getProcessBuilder(xrayPath: String): ProcessBuilder { + private fun getProcessBuilder(xrayPath: String, prefs: Preferences): ProcessBuilder { val filesDir = applicationContext.filesDir val command: MutableList = mutableListOf(xrayPath) val processBuilder = ProcessBuilder(command) val environment = processBuilder.environment() environment["XRAY_LOCATION_ASSET"] = filesDir.path + + // Pass TUN FD to Xray when using native TUN mode + if (prefs.useXrayTun && tunFd != null) { + val tunFdValue = tunFd?.fd + if (tunFdValue != null) { + environment["XRAY_TUN_FD"] = tunFdValue.toString() + Log.d(TAG, "Passed TUN FD ($tunFdValue) to Xray process via environment variable") + } + } + processBuilder.directory(filesDir) processBuilder.redirectErrorStream(true) return processBuilder @@ -266,14 +280,17 @@ class TProxyService : VpnService() { val builder = getVpnBuilder(prefs) tunFd = builder.establish() if (tunFd == null) { + Log.e(TAG, "Failed to establish VPN") stopXray() return } + Log.d(TAG, "VPN service established. TUN FD: ${tunFd?.fd}") + // Use Xray native TUN or hev-tun2sock based on preference if (prefs.useXrayTun) { - Log.d(TAG, "Using Xray native TUN inbound") - Log.d(TAG, "VPN service established. TUN FD: ${tunFd?.fd}") + Log.d(TAG, "Using Xray native TUN inbound mode") + // TUN FD will be passed via environment variable in getProcessBuilder } else { Log.d(TAG, "Using hev-socks5-tunnel (legacy mode)") val tproxyFile = File(cacheDir, "tproxy.conf") @@ -284,13 +301,13 @@ class TProxyService : VpnService() { fos.write(tproxyConf.toByteArray()) } } catch (e: IOException) { - Log.e(TAG, e.toString()) + Log.e(TAG, "Error creating tproxy config: ${e.message}") stopXray() return } tunFd?.fd?.let { fd -> TProxyStartService(tproxyFile.absolutePath, fd) - Log.d(TAG, "hev-tun2sock service started") + Log.d(TAG, "hev-tun2sock service started with FD: $fd") } ?: run { Log.e(TAG, "tunFd is null after establish()") stopXray()