diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt index 85ca77a3..b84a4e02 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/V2RayTestService.kt @@ -3,12 +3,12 @@ package com.v2ray.ang.service import android.app.Service import android.content.Intent import android.os.IBinder -import com.google.gson.Gson import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_CANCEL import com.v2ray.ang.AppConfig.MSG_MEASURE_CONFIG_SUCCESS import com.v2ray.ang.dto.ConfigResult import com.v2ray.ang.extension.serializable +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.SpeedtestUtil import com.v2ray.ang.util.Utils @@ -33,8 +33,8 @@ class V2RayTestService : Service() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { when (intent?.getIntExtra("key", 0)) { MSG_MEASURE_CONFIG -> { - val content = intent.serializable("content") - val config = Gson().fromJson(content, ConfigResult::class.java) + val content = intent.serializable("content") ?: "" + val config = JsonUtil.fromJson(content, ConfigResult::class.java) realTestScope.launch { val result = SpeedtestUtil.realPing(config.content) MessageUtil.sendMsg2UI(this@V2RayTestService, MSG_MEASURE_CONFIG_SUCCESS, Pair(config.guid, result)) diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt index 0789934d..f6c12a96 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/RoutingSettingActivity.kt @@ -10,13 +10,14 @@ import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.LinearLayoutManager -import com.google.gson.Gson + import com.v2ray.ang.AppConfig import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityRoutingSettingBinding import com.v2ray.ang.dto.RulesetItem import com.v2ray.ang.extension.toast import com.v2ray.ang.helper.SimpleItemTouchHelperCallback +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.MmkvManager.settingsStorage import com.v2ray.ang.util.SettingsManager @@ -141,7 +142,7 @@ class RoutingSettingActivity : BaseActivity() { if (rulesetList.isNullOrEmpty()) { toast(R.string.toast_failure) } else { - Utils.setClipboard(this, Gson().toJson(rulesetList)) + Utils.setClipboard(this, JsonUtil.toJson(rulesetList)) toast(R.string.toast_success) } true diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt index 4dba5343..d6891270 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/ServerCustomConfigActivity.kt @@ -8,13 +8,14 @@ import android.widget.Toast import androidx.appcompat.app.AlertDialog import com.blacksquircle.ui.editorkit.utils.EditorTheme import com.blacksquircle.ui.language.json.JsonLanguage -import com.google.gson.Gson + import com.v2ray.ang.R import com.v2ray.ang.databinding.ActivityServerCustomConfigBinding import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.ServerConfig import com.v2ray.ang.dto.V2rayConfig import com.v2ray.ang.extension.toast +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.Utils import me.drakeet.support.toast.ToastCompat @@ -78,7 +79,7 @@ class ServerCustomConfigActivity : BaseActivity() { } val v2rayConfig = try { - Gson().fromJson(binding.editor.text.toString(), V2rayConfig::class.java) + JsonUtil.fromJson(binding.editor.text.toString(), V2rayConfig::class.java) } catch (e: Exception) { e.printStackTrace() ToastCompat.makeText(this, "${getString(R.string.toast_malformed_josn)} ${e.cause?.message}", Toast.LENGTH_LONG).show() diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt index 68ef328e..b4e1b7c4 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/AngConfigManager.kt @@ -4,7 +4,7 @@ import android.content.Context import android.graphics.Bitmap import android.text.TextUtils import android.util.Log -import com.google.gson.Gson + import com.google.gson.GsonBuilder import com.google.gson.JsonPrimitive import com.google.gson.JsonSerializationContext @@ -278,34 +278,21 @@ object AngConfigManager { && server.contains("routing") ) { try { - //val gson = GsonBuilder().setPrettyPrinting().create() - val gson = GsonBuilder() - .setPrettyPrinting() - .disableHtmlEscaping() - .registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start - object : TypeToken() {}.type, - JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? -> - JsonPrimitive( - src?.toInt() - ) - } - ) - .create() val serverList: Array = - Gson().fromJson(server, Array::class.java) + JsonUtil.fromJson(server, Array::class.java) if (serverList.isNotEmpty()) { var count = 0 for (srv in serverList.reversed()) { val config = ServerConfig.create(EConfigType.CUSTOM) config.fullConfig = - Gson().fromJson(Gson().toJson(srv), V2rayConfig::class.java) + JsonUtil.fromJson(JsonUtil.toJson(srv), V2rayConfig::class.java) config.remarks = config.fullConfig?.remarks ?: ("%04d-".format(count + 1) + System.currentTimeMillis() .toString()) config.subscriptionId = subid val key = MmkvManager.encodeServerConfig("", config) - MmkvManager.encodeServerRaw(key, gson.toJson(srv)) + MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(srv)) count += 1 } return count @@ -318,7 +305,7 @@ object AngConfigManager { // For compatibility val config = ServerConfig.create(EConfigType.CUSTOM) config.subscriptionId = subid - config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java) + config.fullConfig = JsonUtil.fromJson(server, V2rayConfig::class.java) config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString() val key = MmkvManager.encodeServerConfig("", config) MmkvManager.encodeServerRaw(key, server) diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/JsonUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/JsonUtil.kt new file mode 100644 index 00000000..0c1c950a --- /dev/null +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/JsonUtil.kt @@ -0,0 +1,37 @@ +package com.v2ray.ang.util + +import com.google.gson.Gson +import com.google.gson.GsonBuilder +import com.google.gson.JsonPrimitive +import com.google.gson.JsonSerializationContext +import com.google.gson.JsonSerializer +import com.google.gson.reflect.TypeToken +import java.lang.reflect.Type + +object JsonUtil { + private var gson = Gson() + + fun toJson(src: Any?): String { + return gson.toJson(src) + } + + fun fromJson(json: String, cls: Class): T { + return gson.fromJson(json, cls) + } + + fun toJsonPretty(src: Any?): String { + val gsonPre = GsonBuilder() + .setPrettyPrinting() + .disableHtmlEscaping() + .registerTypeAdapter( // custom serialiser is needed here since JSON by default parse number as Double, core will fail to start + object : TypeToken() {}.type, + JsonSerializer { src: Double?, _: Type?, _: JsonSerializationContext? -> + JsonPrimitive( + src?.toInt() + ) + } + ) + .create() + return gsonPre.toJson(src) + } +} \ No newline at end of file diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt index 2a04f89b..4787ffee 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/MmkvManager.kt @@ -1,6 +1,6 @@ package com.v2ray.ang.util -import com.google.gson.Gson + import com.tencent.mmkv.MMKV import com.v2ray.ang.AppConfig.PREF_IS_BOOTED import com.v2ray.ang.AppConfig.PREF_ROUTING_RULESET @@ -49,7 +49,7 @@ object MmkvManager { } fun encodeServerList(serverList: MutableList) { - mainStorage.encode(KEY_ANG_CONFIGS, Gson().toJson(serverList)) + mainStorage.encode(KEY_ANG_CONFIGS, JsonUtil.toJson(serverList)) } fun decodeServerList(): MutableList { @@ -57,7 +57,7 @@ object MmkvManager { return if (json.isNullOrBlank()) { mutableListOf() } else { - Gson().fromJson(json, Array::class.java).toMutableList() + JsonUtil.fromJson(json, Array::class.java).toMutableList() } } @@ -69,7 +69,7 @@ object MmkvManager { if (json.isNullOrBlank()) { return null } - return Gson().fromJson(json, ServerConfig::class.java) + return JsonUtil.fromJson(json, ServerConfig::class.java) } fun decodeProfileConfig(guid: String): ProfileItem? { @@ -80,12 +80,12 @@ object MmkvManager { if (json.isNullOrBlank()) { return null } - return Gson().fromJson(json, ProfileItem::class.java) + return JsonUtil.fromJson(json, ProfileItem::class.java) } fun encodeServerConfig(guid: String, config: ServerConfig): String { val key = guid.ifBlank { Utils.getUuid() } - serverStorage.encode(key, Gson().toJson(config)) + serverStorage.encode(key, JsonUtil.toJson(config)) val serverList = decodeServerList() if (!serverList.contains(key)) { serverList.add(0, key) @@ -101,7 +101,7 @@ object MmkvManager { server = config.getProxyOutbound()?.getServerAddress(), serverPort = config.getProxyOutbound()?.getServerPort(), ) - profileStorage.encode(key, Gson().toJson(profile)) + profileStorage.encode(key, JsonUtil.toJson(profile)) return key } @@ -141,7 +141,7 @@ object MmkvManager { if (json.isNullOrBlank()) { return null } - return Gson().fromJson(json, ServerAffiliationInfo::class.java) + return JsonUtil.fromJson(json, ServerAffiliationInfo::class.java) } fun encodeServerTestDelayMillis(guid: String, testResult: Long) { @@ -150,14 +150,14 @@ object MmkvManager { } val aff = decodeServerAffiliationInfo(guid) ?: ServerAffiliationInfo() aff.testDelayMillis = testResult - serverAffStorage.encode(guid, Gson().toJson(aff)) + serverAffStorage.encode(guid, JsonUtil.toJson(aff)) } fun clearAllTestDelayResults(keys: List?) { keys?.forEach { key -> decodeServerAffiliationInfo(key)?.let { aff -> aff.testDelayMillis = 0 - serverAffStorage.encode(key, Gson().toJson(aff)) + serverAffStorage.encode(key, JsonUtil.toJson(aff)) } } } @@ -217,7 +217,7 @@ object MmkvManager { decodeSubsList().forEach { key -> val json = subStorage.decodeString(key) if (!json.isNullOrBlank()) { - subscriptions.add(Pair(key, Gson().fromJson(json, SubscriptionItem::class.java))) + subscriptions.add(Pair(key, JsonUtil.fromJson(json, SubscriptionItem::class.java))) } } return subscriptions @@ -234,7 +234,7 @@ object MmkvManager { fun encodeSubscription(guid: String, subItem: SubscriptionItem) { val key = guid.ifBlank { Utils.getUuid() } - subStorage.encode(key, Gson().toJson(subItem)) + subStorage.encode(key, JsonUtil.toJson(subItem)) val subsList = decodeSubsList() if (!subsList.contains(key)) { @@ -245,11 +245,11 @@ object MmkvManager { fun decodeSubscription(subscriptionId: String): SubscriptionItem? { val json = subStorage.decodeString(subscriptionId) ?: return null - return Gson().fromJson(json, SubscriptionItem::class.java) + return JsonUtil.fromJson(json, SubscriptionItem::class.java) } fun encodeSubsList(subsList: MutableList) { - mainStorage.encode(KEY_SUB_IDS, Gson().toJson(subsList)) + mainStorage.encode(KEY_SUB_IDS, JsonUtil.toJson(subsList)) } fun decodeSubsList(): MutableList { @@ -257,7 +257,7 @@ object MmkvManager { return if (json.isNullOrBlank()) { mutableListOf() } else { - Gson().fromJson(json, Array::class.java).toMutableList() + JsonUtil.fromJson(json, Array::class.java).toMutableList() } } @@ -270,7 +270,7 @@ object MmkvManager { assetStorage.allKeys()?.forEach { key -> val json = assetStorage.decodeString(key) if (!json.isNullOrBlank()) { - assetUrlItems.add(Pair(key, Gson().fromJson(json, AssetUrlItem::class.java))) + assetUrlItems.add(Pair(key, JsonUtil.fromJson(json, AssetUrlItem::class.java))) } } return assetUrlItems.sortedBy { (_, value) -> value.addedTime } @@ -282,12 +282,12 @@ object MmkvManager { fun encodeAsset(assetid: String, assetItem: AssetUrlItem) { val key = assetid.ifBlank { Utils.getUuid() } - assetStorage.encode(key, Gson().toJson(assetItem)) + assetStorage.encode(key, JsonUtil.toJson(assetItem)) } fun decodeAsset(assetid: String): AssetUrlItem? { val json = assetStorage.decodeString(assetid) ?: return null - return Gson().fromJson(json, AssetUrlItem::class.java) + return JsonUtil.fromJson(json, AssetUrlItem::class.java) } //endregion @@ -297,14 +297,14 @@ object MmkvManager { fun decodeRoutingRulesets(): MutableList? { val ruleset = settingsStorage.decodeString(PREF_ROUTING_RULESET) if (ruleset.isNullOrEmpty()) return null - return Gson().fromJson(ruleset, Array::class.java).toMutableList() + return JsonUtil.fromJson(ruleset, Array::class.java).toMutableList() } fun encodeRoutingRulesets(rulesetList: MutableList?) { if (rulesetList.isNullOrEmpty()) settingsStorage.encode(PREF_ROUTING_RULESET, "") else - settingsStorage.encode(PREF_ROUTING_RULESET, Gson().toJson(rulesetList)) + settingsStorage.encode(PREF_ROUTING_RULESET, JsonUtil.toJson(rulesetList)) } //endregion diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/PluginUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/PluginUtil.kt index d649e861..bb585ca1 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/PluginUtil.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/PluginUtil.kt @@ -3,7 +3,7 @@ package com.v2ray.ang.util import android.content.Context import android.os.SystemClock import android.util.Log -import com.google.gson.Gson + import com.v2ray.ang.AppConfig.ANG_PACKAGE import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.ServerConfig @@ -38,8 +38,8 @@ object PluginUtil { Log.d(packageName, "runPlugin ${configFile.absolutePath}") configFile.parentFile?.mkdirs() - configFile.writeText(Gson().toJson(hy2Config)) - Log.d(packageName, Gson().toJson(hy2Config)) + configFile.writeText(JsonUtil.toJson(hy2Config)) + Log.d(packageName, JsonUtil.toJson(hy2Config)) runHy2(context, configFile) } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt index 6d49f783..53e13138 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/SettingsManager.kt @@ -2,7 +2,7 @@ package com.v2ray.ang.util import android.content.Context import android.text.TextUtils -import com.google.gson.Gson + import com.v2ray.ang.AppConfig import com.v2ray.ang.dto.RulesetItem import com.v2ray.ang.dto.ServerConfig @@ -35,7 +35,7 @@ object SettingsManager { return null } - return Gson().fromJson(assets, Array::class.java).toMutableList() + return JsonUtil.fromJson(assets, Array::class.java).toMutableList() } fun resetRoutingRulesets(context: Context, index: Int) { @@ -49,7 +49,7 @@ object SettingsManager { } try { - val rulesetList = Gson().fromJson(content, Array::class.java).toMutableList() + val rulesetList = JsonUtil.fromJson(content, Array::class.java).toMutableList() if (rulesetList.isNullOrEmpty()) { return false } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt index 9c5a26da..aa04e075 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt @@ -3,7 +3,7 @@ package com.v2ray.ang.util import android.content.Context import android.text.TextUtils import android.util.Log -import com.google.gson.Gson + import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig.ANG_PACKAGE import com.v2ray.ang.AppConfig.LOOPBACK @@ -67,7 +67,7 @@ object V2rayConfigUtil { if (TextUtils.isEmpty(assets)) { return result } - val v2rayConfig = Gson().fromJson(assets, V2rayConfig::class.java) ?: return result + val v2rayConfig = JsonUtil.fromJson(assets, V2rayConfig::class.java) ?: return result v2rayConfig.log.loglevel = settingsStorage?.decodeString(AppConfig.PREF_LOGLEVEL) ?: "warning" v2rayConfig.remarks = config.remarks @@ -206,7 +206,7 @@ object V2rayConfigUtil { return } - val rule = Gson().fromJson(Gson().toJson(item), RulesBean::class.java) ?: return + val rule = JsonUtil.fromJson(JsonUtil.toJson(item), RulesBean::class.java) ?: return v2rayConfig.routing.rules.add(rule) @@ -440,7 +440,7 @@ object V2rayConfigUtil { val requestString: String by lazy { """{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36","Mozilla/5.0 (iPhone; CPU iPhone OS 10_0_2 like Mac OS X) AppleWebKit/601.1 (KHTML, like Gecko) CriOS/53.0.2785.109 Mobile/14A456 Safari/601.1.46"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}""" } - outbound.streamSettings?.tcpSettings?.header?.request = Gson().fromJson( + outbound.streamSettings?.tcpSettings?.header?.request = JsonUtil.fromJson( requestString, V2rayConfig.OutboundBean.StreamSettingsBean.TcpSettingsBean.HeaderBean.RequestBean::class.java ) diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VmessFmt.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VmessFmt.kt index eca35e85..1efad50b 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VmessFmt.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/fmt/VmessFmt.kt @@ -2,13 +2,14 @@ package com.v2ray.ang.util.fmt import android.text.TextUtils import android.util.Log -import com.google.gson.Gson + import com.v2ray.ang.AppConfig import com.v2ray.ang.dto.EConfigType import com.v2ray.ang.dto.ServerConfig import com.v2ray.ang.dto.V2rayConfig import com.v2ray.ang.dto.VmessQRCode import com.v2ray.ang.extension.idnHost +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.MmkvManager.settingsStorage import com.v2ray.ang.util.Utils import java.net.URI @@ -29,7 +30,7 @@ object VmessFmt { Log.d(AppConfig.ANG_PACKAGE, "R.string.toast_decoding_failed") return null } - val vmessQRCode = Gson().fromJson(result, VmessQRCode::class.java) + val vmessQRCode = JsonUtil.fromJson(result, VmessQRCode::class.java) // Although VmessQRCode fields are non null, looks like Gson may still create null fields if (TextUtils.isEmpty(vmessQRCode.add) || TextUtils.isEmpty(vmessQRCode.port) @@ -100,7 +101,7 @@ object VmessFmt { vmessQRCode.host = transportDetails[1] vmessQRCode.path = transportDetails[2] } - val json = Gson().toJson(vmessQRCode) + val json = JsonUtil.toJson(vmessQRCode) return Utils.encode(json) } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt index f4d0f7c2..2a761156 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/MainViewModel.kt @@ -11,7 +11,7 @@ import android.util.Log import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope -import com.google.gson.Gson + import com.v2ray.ang.AngApplication import com.v2ray.ang.AppConfig import com.v2ray.ang.AppConfig.ANG_PACKAGE @@ -25,6 +25,7 @@ import com.v2ray.ang.extension.serializable import com.v2ray.ang.extension.toast import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.AngConfigManager.updateConfigViaSub +import com.v2ray.ang.util.JsonUtil import com.v2ray.ang.util.MessageUtil import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.SpeedtestUtil @@ -99,7 +100,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { try { val config = ServerConfig.create(EConfigType.CUSTOM) config.subscriptionId = subscriptionId - config.fullConfig = Gson().fromJson(server, V2rayConfig::class.java) + config.fullConfig = JsonUtil.fromJson(server, V2rayConfig::class.java) config.remarks = config.fullConfig?.remarks ?: System.currentTimeMillis().toString() val key = MmkvManager.encodeServerConfig("", config) MmkvManager.encodeServerRaw(key, server) @@ -217,7 +218,7 @@ class MainViewModel(application: Application) : AndroidViewModel(application) { MessageUtil.sendMsg2TestService( getApplication(), AppConfig.MSG_MEASURE_CONFIG, - Gson().toJson(config) + JsonUtil.toJson(config) ) } }