fix: per-app proxy - исправлен формат чтения списка приложений из SharedPreferences

- Удалён устаревший формат с Base64 + ObjectInputStream
- Теперь используется стандартный getStringSet() для чтения List<String>
- Совместимо с Flutter SharedPreferences plugin
- Убраны неиспользуемые импорты (Base64, ByteArrayInputStream, ObjectInputStream)
This commit is contained in:
Hiddify User
2026-01-13 15:53:02 +03:00
parent 5411a30519
commit f54603d129

View File

@@ -0,0 +1,115 @@
package com.umbrix.app
import android.content.Context
import com.umbrix.app.bg.ProxyService
import com.umbrix.app.bg.VPNService
import com.umbrix.app.constant.PerAppProxyMode
import com.umbrix.app.constant.ServiceMode
import com.umbrix.app.constant.SettingsKey
import org.json.JSONObject
import java.io.File
object Settings {
private val preferences by lazy {
val context = Application.application.applicationContext
context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
}
var perAppProxyMode: String
get() = preferences.getString(SettingsKey.PER_APP_PROXY_MODE, PerAppProxyMode.OFF)!!
set(value) = preferences.edit().putString(SettingsKey.PER_APP_PROXY_MODE, value).apply()
val perAppProxyEnabled: Boolean
get() = perAppProxyMode != PerAppProxyMode.OFF
val perAppProxyList: List<String>
get() {
val key = if (perAppProxyMode == PerAppProxyMode.INCLUDE) {
SettingsKey.PER_APP_PROXY_INCLUDE_LIST
} else {
SettingsKey.PER_APP_PROXY_EXCLUDE_LIST
}
// Flutter SharedPreferences plugin сохраняет List<String> как StringSet
// Читаем напрямую без дополнительной сериализации
return preferences.getStringSet(key, emptySet())?.toList() ?: emptyList()
}
var activeConfigPath: String
get() = preferences.getString(SettingsKey.ACTIVE_CONFIG_PATH, "")!!
set(value) = preferences.edit().putString(SettingsKey.ACTIVE_CONFIG_PATH, value).apply()
var activeProfileName: String
get() = preferences.getString(SettingsKey.ACTIVE_PROFILE_NAME, "")!!
set(value) = preferences.edit().putString(SettingsKey.ACTIVE_PROFILE_NAME, value).apply()
var serviceMode: String
get() = preferences.getString(SettingsKey.SERVICE_MODE, ServiceMode.VPN)!!
set(value) = preferences.edit().putString(SettingsKey.SERVICE_MODE, value).apply()
var configOptions: String
get() = preferences.getString(SettingsKey.CONFIG_OPTIONS, "")!!
set(value) = preferences.edit().putString(SettingsKey.CONFIG_OPTIONS, value).apply()
var debugMode: Boolean
get() = preferences.getBoolean(SettingsKey.DEBUG_MODE, false)
set(value) = preferences.edit().putBoolean(SettingsKey.DEBUG_MODE, value).apply()
var disableMemoryLimit: Boolean
get() = preferences.getBoolean(SettingsKey.DISABLE_MEMORY_LIMIT, false)
set(value) =
preferences.edit().putBoolean(SettingsKey.DISABLE_MEMORY_LIMIT, value).apply()
var dynamicNotification: Boolean
get() = preferences.getBoolean(SettingsKey.DYNAMIC_NOTIFICATION, true)
set(value) =
preferences.edit().putBoolean(SettingsKey.DYNAMIC_NOTIFICATION, value).apply()
var systemProxyEnabled: Boolean
get() = preferences.getBoolean(SettingsKey.SYSTEM_PROXY_ENABLED, true)
set(value) =
preferences.edit().putBoolean(SettingsKey.SYSTEM_PROXY_ENABLED, value).apply()
var startedByUser: Boolean
get() = preferences.getBoolean(SettingsKey.STARTED_BY_USER, false)
set(value) = preferences.edit().putBoolean(SettingsKey.STARTED_BY_USER, value).apply()
fun serviceClass(): Class<*> {
return when (serviceMode) {
ServiceMode.VPN -> VPNService::class.java
else -> ProxyService::class.java
}
}
private var currentServiceMode : String? = null
suspend fun rebuildServiceMode(): Boolean {
var newMode = ServiceMode.NORMAL
try {
if (serviceMode == ServiceMode.VPN) {
newMode = ServiceMode.VPN
}
} catch (_: Exception) {
}
if (currentServiceMode == newMode) {
return false
}
currentServiceMode = newMode
return true
}
private suspend fun needVPNService(): Boolean {
val filePath = activeConfigPath
if (filePath.isBlank()) return false
val content = JSONObject(File(filePath).readText())
val inbounds = content.getJSONArray("inbounds")
for (index in 0 until inbounds.length()) {
val inbound = inbounds.getJSONObject(index)
if (inbound.getString("type") == "tun") {
return true
}
}
return false
}
}