Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
866ceae75c | ||
|
|
349cac092f | ||
|
|
613a643528 | ||
|
|
3144817795 | ||
|
|
6cae2c1785 | ||
|
|
a71509d130 | ||
|
|
d4aa419284 | ||
|
|
b484de5fb7 | ||
|
|
13480b0077 | ||
|
|
1987880294 | ||
|
|
0ae459a70e | ||
|
|
02bc46634d | ||
|
|
cfdaa0c54b | ||
|
|
cbe6c1e3e0 | ||
|
|
3cd6f12b94 | ||
|
|
516235cd6a | ||
|
|
236923d0a0 | ||
|
|
a4816b8251 | ||
|
|
2c2bc86457 | ||
|
|
68a03a93b5 | ||
|
|
5127a30ae9 | ||
|
|
8b76a7a4f4 | ||
|
|
b6aec3fd63 | ||
|
|
18e0dc4546 | ||
|
|
129c1db995 |
@@ -13,6 +13,9 @@ A V2Ray client for Android, support [Xray core](https://github.com/XTLS/Xray-cor
|
|||||||
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
|
<img alt="Get it on Google Play" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png" width="165" height="64" />
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
### Telegram Channel
|
||||||
|
[github_2dust](https://t.me/github_2dust)
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
#### Geoip and Geosite
|
#### Geoip and Geosite
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion Integer.parseInt("$targetSdkVer")
|
targetSdkVersion Integer.parseInt("$targetSdkVer")
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
versionCode 470
|
versionCode 480
|
||||||
versionName "1.7.17"
|
versionName "1.7.23"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props["sign"]) {
|
if (props["sign"]) {
|
||||||
@@ -112,15 +112,15 @@ dependencies {
|
|||||||
implementation 'androidx.cardview:cardview:1.0.0'
|
implementation 'androidx.cardview:cardview:1.0.0'
|
||||||
implementation 'androidx.preference:preference-ktx:1.2.0'
|
implementation 'androidx.preference:preference-ktx:1.2.0'
|
||||||
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
implementation 'androidx.recyclerview:recyclerview:1.2.1'
|
||||||
implementation 'androidx.fragment:fragment-ktx:1.5.0'
|
implementation 'androidx.fragment:fragment-ktx:1.5.2'
|
||||||
implementation 'androidx.multidex:multidex:2.0.1'
|
implementation 'androidx.multidex:multidex:2.0.1'
|
||||||
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
implementation 'androidx.viewpager2:viewpager2:1.1.0-beta01'
|
||||||
|
|
||||||
// Androidx ktx
|
// Androidx ktx
|
||||||
implementation 'androidx.activity:activity-ktx:1.5.0'
|
implementation 'androidx.activity:activity-ktx:1.5.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0'
|
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.0'
|
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.5.1'
|
||||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
|
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.1'
|
||||||
|
|
||||||
//kotlin
|
//kotlin
|
||||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinVersion"
|
||||||
@@ -141,12 +141,11 @@ dependencies {
|
|||||||
implementation 'com.blacksquircle.ui:language-json:2.1.1'
|
implementation 'com.blacksquircle.ui:language-json:2.1.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
buildscript {
|
//buildscript {
|
||||||
repositories {
|
// repositories {
|
||||||
google()
|
// google()
|
||||||
mavenCentral()
|
// mavenCentral()
|
||||||
maven { url 'https://maven.google.com' }
|
// maven { url 'https://maven.google.com' }
|
||||||
maven { url 'https://jitpack.io' }
|
// maven { url 'https://jitpack.io' }
|
||||||
jcenter()
|
// }
|
||||||
}
|
//}
|
||||||
}
|
|
||||||
|
|||||||
@@ -259,11 +259,13 @@ data class V2rayConfig(
|
|||||||
return sni
|
return sni
|
||||||
}
|
}
|
||||||
|
|
||||||
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String) {
|
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?) {
|
||||||
security = streamSecurity
|
security = streamSecurity
|
||||||
val tlsSetting = TlsSettingsBean(
|
val tlsSetting = TlsSettingsBean(
|
||||||
allowInsecure = allowInsecure,
|
allowInsecure = allowInsecure,
|
||||||
serverName = sni
|
serverName = sni,
|
||||||
|
fingerprint = fingerprint,
|
||||||
|
alpn = if (alpns.isNullOrEmpty()) null else alpns.split(",").map { it.trim() }.filter { it.isNotEmpty() }
|
||||||
)
|
)
|
||||||
if (security == TLS) {
|
if (security == TLS) {
|
||||||
tlsSettings = tlsSetting
|
tlsSettings = tlsSetting
|
||||||
|
|||||||
@@ -12,4 +12,5 @@ data class VmessQRCode(var v: String = "",
|
|||||||
var host: String = "",
|
var host: String = "",
|
||||||
var path: String = "",
|
var path: String = "",
|
||||||
var tls: String = "",
|
var tls: String = "",
|
||||||
var sni: String = "")
|
var sni: String = "",
|
||||||
|
var alpn: String = "")
|
||||||
@@ -2,6 +2,7 @@ package com.v2ray.ang.ui
|
|||||||
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.text.TextUtils
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
@@ -153,7 +154,9 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
|
|||||||
val selected = mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)
|
val selected = mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)
|
||||||
if (guid != selected) {
|
if (guid != selected) {
|
||||||
mainStorage?.encode(MmkvManager.KEY_SELECTED_SERVER, guid)
|
mainStorage?.encode(MmkvManager.KEY_SELECTED_SERVER, guid)
|
||||||
|
if (!TextUtils.isEmpty(selected)) {
|
||||||
notifyItemChanged(mActivity.mainViewModel.getPosition(selected!!))
|
notifyItemChanged(mActivity.mainViewModel.getPosition(selected!!))
|
||||||
|
}
|
||||||
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
|
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
mActivity.showCircle()
|
mActivity.showCircle()
|
||||||
|
|||||||
@@ -67,7 +67,12 @@ class ServerActivity : BaseActivity() {
|
|||||||
private val allowinsecures: Array<out String> by lazy {
|
private val allowinsecures: Array<out String> by lazy {
|
||||||
resources.getStringArray(R.array.allowinsecures)
|
resources.getStringArray(R.array.allowinsecures)
|
||||||
}
|
}
|
||||||
|
private val uTlsItems: Array<out String> by lazy {
|
||||||
|
resources.getStringArray(R.array.streamsecurity_utls)
|
||||||
|
}
|
||||||
|
private val alpns: Array<out String> by lazy {
|
||||||
|
resources.getStringArray(R.array.streamsecurity_alpn)
|
||||||
|
}
|
||||||
// Kotlin synthetics was used, but since it is removed in 1.8. We switch to old manual approach.
|
// Kotlin synthetics was used, but since it is removed in 1.8. We switch to old manual approach.
|
||||||
// We don't use AndroidViewBinding because, it is better to share similar logics for different
|
// We don't use AndroidViewBinding because, it is better to share similar logics for different
|
||||||
// protocols. Use findViewById manually ensures the xml are de-coupled with the activity logic.
|
// protocols. Use findViewById manually ensures the xml are de-coupled with the activity logic.
|
||||||
@@ -82,11 +87,13 @@ class ServerActivity : BaseActivity() {
|
|||||||
private val sp_stream_security: Spinner? by lazy { findViewById(R.id.sp_stream_security) }
|
private val sp_stream_security: Spinner? by lazy { findViewById(R.id.sp_stream_security) }
|
||||||
private val sp_allow_insecure: Spinner? by lazy { findViewById(R.id.sp_allow_insecure) }
|
private val sp_allow_insecure: Spinner? by lazy { findViewById(R.id.sp_allow_insecure) }
|
||||||
private val et_sni: EditText? by lazy { findViewById(R.id.et_sni) }
|
private val et_sni: EditText? by lazy { findViewById(R.id.et_sni) }
|
||||||
|
private val sp_stream_fingerprint: Spinner? by lazy { findViewById(R.id.sp_stream_fingerprint) } //uTLS
|
||||||
private val sp_network: Spinner? by lazy { findViewById(R.id.sp_network) }
|
private val sp_network: Spinner? by lazy { findViewById(R.id.sp_network) }
|
||||||
private val sp_header_type: Spinner? by lazy { findViewById(R.id.sp_header_type) }
|
private val sp_header_type: Spinner? by lazy { findViewById(R.id.sp_header_type) }
|
||||||
private val sp_header_type_title: TextView? by lazy { findViewById(R.id.sp_header_type_title) }
|
private val sp_header_type_title: TextView? by lazy { findViewById(R.id.sp_header_type_title) }
|
||||||
private val et_request_host: EditText? by lazy { findViewById(R.id.et_request_host) }
|
private val et_request_host: EditText? by lazy { findViewById(R.id.et_request_host) }
|
||||||
private val et_path: EditText? by lazy { findViewById(R.id.et_path) }
|
private val et_path: EditText? by lazy { findViewById(R.id.et_path) }
|
||||||
|
private val sp_stream_alpn: Spinner? by lazy { findViewById(R.id.sp_stream_alpn) } //uTLS
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -170,6 +177,16 @@ class ServerActivity : BaseActivity() {
|
|||||||
sp_allow_insecure?.setSelection(allowinsecure)
|
sp_allow_insecure?.setSelection(allowinsecure)
|
||||||
}
|
}
|
||||||
et_sni?.text = Utils.getEditable(tlsSetting.serverName)
|
et_sni?.text = Utils.getEditable(tlsSetting.serverName)
|
||||||
|
|
||||||
|
tlsSetting.fingerprint?.let {
|
||||||
|
val utlsIndex = Utils.arrayFind(uTlsItems, tlsSetting.fingerprint)
|
||||||
|
sp_stream_fingerprint?.setSelection(utlsIndex)
|
||||||
|
}
|
||||||
|
tlsSetting.alpn?.let {
|
||||||
|
val alpnIndex = Utils.arrayFind(alpns, Utils.removeWhiteSpace(tlsSetting.alpn.joinToString())!!)
|
||||||
|
sp_stream_alpn?.setSelection(alpnIndex)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val network = Utils.arrayFind(networks, streamSetting.network)
|
val network = Utils.arrayFind(networks, streamSetting.network)
|
||||||
@@ -310,6 +327,8 @@ class ServerActivity : BaseActivity() {
|
|||||||
val sniField = et_sni?.text?.toString()?.trim() ?: return
|
val sniField = et_sni?.text?.toString()?.trim() ?: return
|
||||||
val allowInsecureField = sp_allow_insecure?.selectedItemPosition ?: return
|
val allowInsecureField = sp_allow_insecure?.selectedItemPosition ?: return
|
||||||
val streamSecurity = sp_stream_security?.selectedItemPosition ?: return
|
val streamSecurity = sp_stream_security?.selectedItemPosition ?: return
|
||||||
|
var utlsIndex = sp_stream_fingerprint?.selectedItemPosition ?: return
|
||||||
|
var alpnIndex = sp_stream_alpn?.selectedItemPosition ?: return
|
||||||
|
|
||||||
var sni = streamSetting.populateTransportSettings(
|
var sni = streamSetting.populateTransportSettings(
|
||||||
transport = networks[network],
|
transport = networks[network],
|
||||||
@@ -330,7 +349,8 @@ class ServerActivity : BaseActivity() {
|
|||||||
} else {
|
} else {
|
||||||
allowinsecures[allowInsecureField].toBoolean()
|
allowinsecures[allowInsecureField].toBoolean()
|
||||||
}
|
}
|
||||||
streamSetting.populateTlsSettings(streamSecuritys[streamSecurity], allowInsecure, sni)
|
|
||||||
|
streamSetting.populateTlsSettings(streamSecuritys[streamSecurity], allowInsecure, sni, uTlsItems[utlsIndex], alpns[alpnIndex])
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun transportTypes(network: String?): Array<out String> {
|
private fun transportTypes(network: String?): Array<out String> {
|
||||||
|
|||||||
@@ -141,10 +141,10 @@ class UserAssetActivity : BaseActivity() {
|
|||||||
val result = downloadGeo(it, 60000, httpPort)
|
val result = downloadGeo(it, 60000, httpPort)
|
||||||
launch(Dispatchers.Main) {
|
launch(Dispatchers.Main) {
|
||||||
if (result) {
|
if (result) {
|
||||||
toast(getString(R.string.toast_success) + it)
|
toast(getString(R.string.toast_success) + " " + it)
|
||||||
binding.recyclerView.adapter?.notifyDataSetChanged()
|
binding.recyclerView.adapter?.notifyDataSetChanged()
|
||||||
} else {
|
} else {
|
||||||
toast(getString(R.string.toast_failure) + it)
|
toast(getString(R.string.toast_failure) + " " + it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -143,8 +143,9 @@ object AngConfigManager {
|
|||||||
} else {
|
} else {
|
||||||
vmessBean.allowInsecure.toBoolean()
|
vmessBean.allowInsecure.toBoolean()
|
||||||
}
|
}
|
||||||
|
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||||
streamSetting.populateTlsSettings(vmessBean.streamSecurity, allowInsecure,
|
streamSetting.populateTlsSettings(vmessBean.streamSecurity, allowInsecure,
|
||||||
vmessBean.sni.ifBlank { sni })
|
vmessBean.sni.ifBlank { sni }, fingerprint, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
|
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
|
||||||
@@ -185,6 +186,9 @@ object AngConfigManager {
|
|||||||
config = ServerConfig.create(EConfigType.VMESS)
|
config = ServerConfig.create(EConfigType.VMESS)
|
||||||
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
||||||
|
|
||||||
|
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||||
|
|
||||||
|
|
||||||
if (!tryParseNewVmess(str, config, allowInsecure)) {
|
if (!tryParseNewVmess(str, config, allowInsecure)) {
|
||||||
if (str.indexOf("?") > 0) {
|
if (str.indexOf("?") > 0) {
|
||||||
if (!tryResolveVmess4Kitsunebi(str, config)) {
|
if (!tryResolveVmess4Kitsunebi(str, config)) {
|
||||||
@@ -216,8 +220,10 @@ object AngConfigManager {
|
|||||||
}
|
}
|
||||||
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
|
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
|
||||||
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
|
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
|
||||||
|
|
||||||
|
|
||||||
streamSetting.populateTlsSettings(vmessQRCode.tls, allowInsecure,
|
streamSetting.populateTlsSettings(vmessQRCode.tls, allowInsecure,
|
||||||
if (TextUtils.isEmpty(vmessQRCode.sni)) sni else vmessQRCode.sni)
|
if (TextUtils.isEmpty(vmessQRCode.sni)) sni else vmessQRCode.sni, fingerprint, vmessQRCode.alpn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (str.startsWith(EConfigType.SHADOWSOCKS.protocolScheme)) {
|
} else if (str.startsWith(EConfigType.SHADOWSOCKS.protocolScheme)) {
|
||||||
@@ -292,6 +298,7 @@ object AngConfigManager {
|
|||||||
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
|
|
||||||
var flow = ""
|
var flow = ""
|
||||||
|
var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint
|
||||||
if (uri.rawQuery != null) {
|
if (uri.rawQuery != null) {
|
||||||
val queryParam = uri.rawQuery.split("&")
|
val queryParam = uri.rawQuery.split("&")
|
||||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||||
@@ -299,10 +306,11 @@ object AngConfigManager {
|
|||||||
val sni = config.outboundBean?.streamSettings?.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
|
val sni = config.outboundBean?.streamSettings?.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
|
||||||
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
|
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
|
||||||
queryParam["mode"], queryParam["serviceName"])
|
queryParam["mode"], queryParam["serviceName"])
|
||||||
config.outboundBean?.streamSettings?.populateTlsSettings(queryParam["security"] ?: TLS, allowInsecure, queryParam["sni"] ?: sni!!)
|
config.outboundBean?.streamSettings?.populateTlsSettings(queryParam["security"] ?: TLS, allowInsecure, queryParam["sni"] ?: sni!!, fingerprint, queryParam["alpn"])
|
||||||
flow = queryParam["flow"] ?: ""
|
flow = queryParam["flow"] ?: ""
|
||||||
} else {
|
} else {
|
||||||
config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, "")
|
|
||||||
|
config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, "", fingerprint, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
config.outboundBean?.settings?.servers?.get(0)?.let { server ->
|
||||||
@@ -317,6 +325,8 @@ object AngConfigManager {
|
|||||||
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
.associate { it.split("=").let { (k, v) -> k to Utils.urlDecode(v) } }
|
||||||
config = ServerConfig.create(EConfigType.VLESS)
|
config = ServerConfig.create(EConfigType.VLESS)
|
||||||
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
val streamSetting = config.outboundBean?.streamSettings ?: return -1
|
||||||
|
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||||
|
|
||||||
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
config.remarks = Utils.urlDecode(uri.fragment ?: "")
|
||||||
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
|
||||||
vnext.address = uri.idnHost
|
vnext.address = uri.idnHost
|
||||||
@@ -329,7 +339,7 @@ object AngConfigManager {
|
|||||||
val sni = streamSetting.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
|
val sni = streamSetting.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
|
||||||
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
|
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
|
||||||
queryParam["mode"], queryParam["serviceName"])
|
queryParam["mode"], queryParam["serviceName"])
|
||||||
streamSetting.populateTlsSettings(queryParam["security"] ?: "", allowInsecure, queryParam["sni"] ?: sni)
|
streamSetting.populateTlsSettings(queryParam["security"] ?: "", allowInsecure, queryParam["sni"] ?: sni, fingerprint, queryParam["alpn"])
|
||||||
}
|
}
|
||||||
if (config == null){
|
if (config == null){
|
||||||
return R.string.toast_incorrect_protocol
|
return R.string.toast_incorrect_protocol
|
||||||
@@ -369,12 +379,12 @@ object AngConfigManager {
|
|||||||
vnext.users[0].security = DEFAULT_SECURITY
|
vnext.users[0].security = DEFAULT_SECURITY
|
||||||
vnext.users[0].alterId = alterId.toInt()
|
vnext.users[0].alterId = alterId.toInt()
|
||||||
}
|
}
|
||||||
|
var fingerprint = streamSetting.tlsSettings?.fingerprint
|
||||||
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
|
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
|
||||||
queryParam["host"]?.split("|")?.get(0) ?: "",
|
queryParam["host"]?.split("|")?.get(0) ?: "",
|
||||||
queryParam["path"]?.takeIf { it.trim() != "/" } ?: "", queryParam["seed"], queryParam["security"],
|
queryParam["path"]?.takeIf { it.trim() != "/" } ?: "", queryParam["seed"], queryParam["security"],
|
||||||
queryParam["key"], queryParam["mode"], queryParam["serviceName"])
|
queryParam["key"], queryParam["mode"], queryParam["serviceName"])
|
||||||
streamSetting.populateTlsSettings(if (tls) TLS else "", allowInsecure, sni)
|
streamSetting.populateTlsSettings(if (tls) TLS else "", allowInsecure, sni, fingerprint, null)
|
||||||
true
|
true
|
||||||
}.getOrElse { false }
|
}.getOrElse { false }
|
||||||
}
|
}
|
||||||
@@ -467,6 +477,7 @@ object AngConfigManager {
|
|||||||
vmessQRCode.net = streamSetting.network
|
vmessQRCode.net = streamSetting.network
|
||||||
vmessQRCode.tls = streamSetting.security
|
vmessQRCode.tls = streamSetting.security
|
||||||
vmessQRCode.sni = streamSetting.tlsSettings?.serverName.orEmpty()
|
vmessQRCode.sni = streamSetting.tlsSettings?.serverName.orEmpty()
|
||||||
|
vmessQRCode.alpn = Utils.removeWhiteSpace(streamSetting.tlsSettings?.alpn?.joinToString()).orEmpty()
|
||||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||||
vmessQRCode.type = transportDetails[0]
|
vmessQRCode.type = transportDetails[0]
|
||||||
vmessQRCode.host = transportDetails[1]
|
vmessQRCode.host = transportDetails[1]
|
||||||
@@ -521,6 +532,9 @@ object AngConfigManager {
|
|||||||
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
if (!TextUtils.isEmpty(tlsSetting.serverName)) {
|
||||||
dicQuery["sni"] = tlsSetting.serverName
|
dicQuery["sni"] = tlsSetting.serverName
|
||||||
}
|
}
|
||||||
|
if (!tlsSetting.alpn.isNullOrEmpty() && tlsSetting.alpn.isNotEmpty()) {
|
||||||
|
dicQuery["alpn"] = Utils.removeWhiteSpace(tlsSetting.alpn.joinToString()).orEmpty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
dicQuery["type"] = streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
dicQuery["type"] = streamSetting.network.ifEmpty { V2rayConfig.DEFAULT_NETWORK }
|
||||||
|
|
||||||
|
|||||||
@@ -409,6 +409,7 @@ object Utils {
|
|||||||
"zh-rCN" -> Locale("zh", "CN")
|
"zh-rCN" -> Locale("zh", "CN")
|
||||||
"zh-rTW" -> Locale("zh", "TW")
|
"zh-rTW" -> Locale("zh", "TW")
|
||||||
"vi" -> Locale("vi")
|
"vi" -> Locale("vi")
|
||||||
|
"ru" -> Locale("ru")
|
||||||
else -> getSysLocale()
|
else -> getSysLocale()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,5 +424,9 @@ object Utils {
|
|||||||
.replace(" ","%20")
|
.replace(" ","%20")
|
||||||
.replace("|","%7C")
|
.replace("|","%7C")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun removeWhiteSpace(str: String?): String? {
|
||||||
|
return str?.replace(" ", "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,18 +54,17 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
|||||||
|
|
||||||
fun reloadServerList() {
|
fun reloadServerList() {
|
||||||
serverList = MmkvManager.decodeServerList()
|
serverList = MmkvManager.decodeServerList()
|
||||||
viewModelScope.launch(Dispatchers.Default) {
|
|
||||||
updateCache()
|
updateCache()
|
||||||
launch(Dispatchers.Main) {
|
|
||||||
updateListAction.value = -1
|
updateListAction.value = -1
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun removeServer(guid: String) {
|
fun removeServer(guid: String) {
|
||||||
serverList.remove(guid)
|
serverList.remove(guid)
|
||||||
MmkvManager.removeServer(guid)
|
MmkvManager.removeServer(guid)
|
||||||
serversCache.removeAt(getPosition(guid))
|
val index = getPosition(guid)
|
||||||
|
if(index >= 0){
|
||||||
|
serversCache.removeAt(index)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun appendCustomConfigServer(server: String) {
|
fun appendCustomConfigServer(server: String) {
|
||||||
|
|||||||
@@ -202,64 +202,7 @@
|
|||||||
android:inputType="text" />
|
android:inputType="text" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/tls_layout" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_stream_security" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_stream_security"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/streamsecurityxs"
|
|
||||||
android:nextFocusDown="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_sni" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_sni"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:inputType="text" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_allow_insecure" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_allow_insecure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/allowinsecures"
|
|
||||||
android:nextFocusUp="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -223,63 +223,7 @@
|
|||||||
android:inputType="text" />
|
android:inputType="text" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/tls_layout" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_stream_security" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_stream_security"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/streamsecurityxs"
|
|
||||||
android:nextFocusDown="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_sni" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_sni"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:inputType="text" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_allow_insecure" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_allow_insecure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/allowinsecures"
|
|
||||||
android:nextFocusUp="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
@@ -222,64 +222,7 @@
|
|||||||
android:inputType="text" />
|
android:inputType="text" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<include layout="@layout/tls_layout" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_stream_security" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_stream_security"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/streamsecuritys"
|
|
||||||
android:nextFocusDown="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_sni" />
|
|
||||||
|
|
||||||
<EditText
|
|
||||||
android:id="@+id/et_sni"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:inputType="text" />
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="@dimen/layout_margin_top_height"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:text="@string/server_lab_allow_insecure" />
|
|
||||||
|
|
||||||
<Spinner
|
|
||||||
android:id="@+id/sp_allow_insecure"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="@dimen/edit_height"
|
|
||||||
android:entries="@array/allowinsecures"
|
|
||||||
android:nextFocusUp="@+id/et_sni" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
|||||||
108
V2rayNG/app/src/main/res/layout/tls_layout.xml
Normal file
108
V2rayNG/app/src/main/res/layout/tls_layout.xml
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="@dimen/activity_horizontal_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/l1"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/activity_horizontal_margin"
|
||||||
|
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_lab_stream_security" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sp_stream_security"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/edit_height"
|
||||||
|
android:entries="@array/streamsecurityxs"
|
||||||
|
android:nextFocusDown="@+id/et_sni" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/l2"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="@dimen/activity_horizontal_margin"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_lab_sni" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/et_sni"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/edit_height"
|
||||||
|
android:inputType="text"
|
||||||
|
android:nextFocusDown="@+id/sp_stream_fingerprint" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/l3"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="@dimen/activity_horizontal_margin">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_lab_stream_fingerprint" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sp_stream_fingerprint"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/edit_height"
|
||||||
|
android:entries="@array/streamsecurity_utls"
|
||||||
|
android:nextFocusDown="@+id/sp_stream_alpn" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/l4"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_marginBottom="@dimen/activity_horizontal_margin">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_lab_stream_alpn" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sp_stream_alpn"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/edit_height"
|
||||||
|
android:entries="@array/streamsecurity_alpn"
|
||||||
|
android:nextFocusDown="@+id/sp_allow_insecure" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/l5"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/server_lab_allow_insecure" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/sp_allow_insecure"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="@dimen/edit_height"
|
||||||
|
android:entries="@array/allowinsecures" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
228
V2rayNG/app/src/main/res/values-ru/strings.xml
Normal file
228
V2rayNG/app/src/main/res/values-ru/strings.xml
Normal file
@@ -0,0 +1,228 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name" translatable="false">v2rayNG</string>
|
||||||
|
<string name="app_widget_name">Переключить</string>
|
||||||
|
<string name="app_tile_name">Переключить</string>
|
||||||
|
<string name="app_tile_first_use">Первое использование этой функции, пожалуйста, используйте приложение, чтобы добавить сервер</string>
|
||||||
|
<string name="navigation_drawer_open">Открыть панель навигации</string>
|
||||||
|
<string name="navigation_drawer_close">Закрыть панель навигации</string>
|
||||||
|
<string name="migration_success">Успешный перенос данных!</string>
|
||||||
|
<string name="migration_fail">Перенос данных не выполнен!</string>
|
||||||
|
|
||||||
|
<!-- Notifications -->
|
||||||
|
<string name="notification_action_stop_v2ray">Остановить</string>
|
||||||
|
<string name="toast_permission_denied">Разрешение не получено</string>
|
||||||
|
<string name="notification_action_more">Ещё…</string>
|
||||||
|
<string name="toast_services_start">Запуск служб</string>
|
||||||
|
<string name="toast_services_stop">Остановка служб</string>
|
||||||
|
<string name="toast_services_success">Службы успешно запущены</string>
|
||||||
|
<string name="toast_services_failure">Сбой при запуске служб</string>
|
||||||
|
|
||||||
|
<!--ServerActivity-->
|
||||||
|
<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>
|
||||||
|
<string name="menu_item_import_config_qrcode">Импорт профиля из QR-кода</string>
|
||||||
|
<string name="menu_item_import_config_clipboard">Импорт профиля из буфера обмена</string>
|
||||||
|
<string name="menu_item_import_config_manually_vmess">Ручной ввод профиля Vmess</string>
|
||||||
|
<string name="menu_item_import_config_manually_vless">Ручной ввод профиля VLESS</string>
|
||||||
|
<string name="menu_item_import_config_manually_ss">Ручной ввод профиля Shadowsocks</string>
|
||||||
|
<string name="menu_item_import_config_manually_socks">Ручной ввод профиля Socks</string>
|
||||||
|
<string name="menu_item_import_config_manually_trojan">Ручной ввод профиля Trojan</string>
|
||||||
|
<string name="menu_item_import_config_custom">Пользовательский профиль</string>
|
||||||
|
<string name="menu_item_import_config_custom_clipboard">Импорт из буфера обмена</string>
|
||||||
|
<string name="menu_item_import_config_custom_local">Импорт с устройства</string>
|
||||||
|
<string name="menu_item_import_config_custom_url">Импорт из URL</string>
|
||||||
|
<string name="menu_item_import_config_custom_url_scan">Импорт сканированием URL</string>
|
||||||
|
<string name="del_config_comfirm">Подтверждаете удаление?</string>
|
||||||
|
<string name="server_lab_remarks">Описание</string>
|
||||||
|
<string name="server_lab_address">Адрес</string>
|
||||||
|
<string name="server_lab_port">Порт</string>
|
||||||
|
<string name="server_lab_id">ID</string>
|
||||||
|
<string name="server_lab_alterid">Альтернативный ID</string>
|
||||||
|
<string name="server_lab_security">Безопасность</string>
|
||||||
|
<string name="server_lab_network">Сеть</string>
|
||||||
|
<string name="server_lab_more_function">Другие параметры</string>
|
||||||
|
<string name="server_lab_head_type">Тип заголовка</string>
|
||||||
|
<string name="server_lab_mode_type">Режим gRPC</string>
|
||||||
|
<string name="server_lab_request_host">Запрос узла (WS/H2) / Шифрование QUIC</string>
|
||||||
|
<string name="server_lab_path">Путь (WS/H2) / Ключ QUIC / Сид KCP / Сервис gRPC</string>
|
||||||
|
<string name="server_lab_stream_security">TLS</string>
|
||||||
|
<string name="server_lab_stream_fingerprint">uTLS</string>
|
||||||
|
<string name="server_lab_allow_insecure">Разрешать небезопасные</string>
|
||||||
|
<string name="server_lab_sni">SNI</string>
|
||||||
|
<string name="server_lab_address3">Адрес</string>
|
||||||
|
<string name="server_lab_port3">Порт</string>
|
||||||
|
<string name="server_lab_id3">Пароль</string>
|
||||||
|
<string name="server_lab_security3">Безопасность</string>
|
||||||
|
<string name="server_lab_id4">Пароль (необязательно)</string>
|
||||||
|
<string name="server_lab_security4">Пользователь (необязательно)</string>
|
||||||
|
<string name="server_lab_encryption">Шифрование</string>
|
||||||
|
<string name="server_lab_flow">Поток</string>
|
||||||
|
<string name="toast_success">Успешно</string>
|
||||||
|
<string name="toast_failure">Ошибка</string>
|
||||||
|
<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="toast_require_file_manager">Установите файловый менеджер</string>
|
||||||
|
<string name="server_customize_config">Изменить профиль</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">Неправильный URL</string>
|
||||||
|
<string name="server_lab_need_inbound">Убедитесь, что входящий порт соответствует настройкам</string>
|
||||||
|
<string name="toast_malformed_josn">Профиль повреждён</string>
|
||||||
|
<string name="server_lab_request_host6">Узел (SNI) (необязательно)</string>
|
||||||
|
<string name="toast_asset_copy_failed">Невозможно скопировать файл, используйте файловый менеджер</string>
|
||||||
|
<string name="menu_item_add_file">Добавить файлы</string>
|
||||||
|
<string name="menu_item_download_file">Загрузить файлы</string>
|
||||||
|
|
||||||
|
<!-- PerAppProxyActivity -->
|
||||||
|
<string name="msg_dialog_progress">Загрузка…</string>
|
||||||
|
<string name="menu_item_search">Поиск</string>
|
||||||
|
<string name="menu_item_select_all">Выбрать все</string>
|
||||||
|
<string name="msg_enter_keywords">Введите ключевые слова</string>
|
||||||
|
<string name="switch_bypass_apps_mode">Режим обхода</string>
|
||||||
|
<string name="menu_item_select_proxy_app">Автовыбор проксируемых приложений</string>
|
||||||
|
<string name="msg_downloading_content">Загрузка данных</string>
|
||||||
|
<string name="menu_item_export_proxy_app">Экспорт в буфер обмена</string>
|
||||||
|
<string name="menu_item_import_proxy_app">Импорт из буфера обмена</string>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Preferences -->
|
||||||
|
<string name="title_settings">Настройки</string>
|
||||||
|
<string name="title_advanced">Расширенные настройки</string>
|
||||||
|
<string name="title_vpn_settings">Настройки VPN</string>
|
||||||
|
<string name="title_pref_per_app_proxy">Прокси для выбранных приложений</string>
|
||||||
|
<string name="summary_pref_per_app_proxy">Основной: выделенное приложение соединяется через прокси, не выделенное — напрямую; \n\nРежим обхода: выделенное приложение соединяется напрямую, не выделенное — через прокси.\n\nЕсть возможность автоматического выбора проксируемых приложений в меню.</string>
|
||||||
|
|
||||||
|
<string name="title_pref_mux_enabled">Использовать мультиплексирование</string>
|
||||||
|
<string name="summary_pref_mux_enabled">Включение может ускорить работу и переключение сети</string>
|
||||||
|
|
||||||
|
<string name="title_pref_speed_enabled">Отображение скорости</string>
|
||||||
|
<string name="summary_pref_speed_enabled">Показывать текущую скорость в уведомлении.\n\nЗначок будет меняться в зависимости от использования.</string>
|
||||||
|
|
||||||
|
<string name="title_pref_sniffing_enabled">Анализ пакетов</string>
|
||||||
|
<string name="summary_pref_sniffing_enabled">Использовать анализ пакетов (по умолчанию включено)</string>
|
||||||
|
|
||||||
|
<string name="title_pref_local_dns_enabled">Использовать локальную DNS</string>
|
||||||
|
<string name="summary_pref_local_dns_enabled">Обслуживание выполняется DNS-модулем ядра (в настройках маршрутизации рекомендуется выбрать режим «Все, кроме LAN и Китая»)</string>
|
||||||
|
|
||||||
|
<string name="title_pref_fake_dns_enabled">Использовать поддельную DNS</string>
|
||||||
|
<string name="summary_pref_fake_dns_enabled">Локальная DNS возвращает поддельный IP-адрес (быстрее, но может не работать с некоторыми приложениями)</string>
|
||||||
|
|
||||||
|
<string name="title_pref_prefer_ipv6">Предпочитать IPv6</string>
|
||||||
|
<string name="summary_pref_prefer_ipv6">Предпочитать IPv6-адреса и маршрутизацию</string>
|
||||||
|
|
||||||
|
<string name="title_pref_routing">Маршрутизация</string>
|
||||||
|
<string name="title_pref_routing_domain_strategy">Доменная стратегия</string>
|
||||||
|
<string name="title_pref_routing_mode">Режим маршрутизации</string>
|
||||||
|
<string name="title_pref_routing_custom">Пользовательские правила</string>
|
||||||
|
|
||||||
|
<string name="title_pref_remote_dns">Удалённая DNS (необязательно)</string>
|
||||||
|
<string name="summary_pref_remote_dns">DNS</string>
|
||||||
|
|
||||||
|
<string name="title_pref_vpn_dns">VPN DNS (только IPv4/v6)</string>
|
||||||
|
|
||||||
|
<string name="title_pref_domestic_dns">Внутренняя DNS (необязательно)</string>
|
||||||
|
<string name="summary_pref_domestic_dns">DNS</string>
|
||||||
|
|
||||||
|
<string name="title_pref_proxy_sharing_enabled">Разрешать подключения из LAN</string>
|
||||||
|
<string name="summary_pref_proxy_sharing_enabled">Другие устройства могут подключаться к прокси по вашему IP-адресу через протокол SOCKS/HTTP. Используйте только в надёжной сети, чтобы избежать несанкционированного подключения.</string>
|
||||||
|
<string name="toast_warning_pref_proxysharing_short">Доступ из LAN разрешён, убедитесь, что вы находитесь в надёжной сети</string>
|
||||||
|
|
||||||
|
<string name="title_pref_allow_insecure">Разрешать небезопасные</string>
|
||||||
|
<string name="summary_pref_allow_insecure">Для TLS по умолчанию разрешены небезопасные соединения</string>
|
||||||
|
|
||||||
|
<string name="title_pref_socks_port">Порт SOCKS5-прокси</string>
|
||||||
|
<string name="summary_pref_socks_port">Порт SOCKS5-прокси</string>
|
||||||
|
|
||||||
|
<string name="title_pref_http_port">Порт HTTP-прокси</string>
|
||||||
|
<string name="summary_pref_http_port">Порт HTTP-прокси</string>
|
||||||
|
|
||||||
|
<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_feedback">Обратная связь</string>
|
||||||
|
<string name="summary_pref_feedback">Предложить улучшение или сообщить об ошибке на GitHub</string>
|
||||||
|
<string name="summary_pref_tg_group">Присоединиться к группе в Telegram</string>
|
||||||
|
<string name="toast_tg_app_not_found">Приложение Telegram не найдено</string>
|
||||||
|
|
||||||
|
<string name="title_pref_promotion">Содействие</string>
|
||||||
|
<string name="summary_pref_promotion">Содействие, нажмите для получения подробной информации (пожертвование может быть удалено)</string>
|
||||||
|
|
||||||
|
<string name="title_core_loglevel">Подробность ведения журнала</string>
|
||||||
|
<string name="title_mode">Режим</string>
|
||||||
|
<string name="title_mode_help">Нажмите для получения дополнительной информации</string>
|
||||||
|
<string name="title_language">Язык</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_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">URL (необязательно)</string>
|
||||||
|
<string name="sub_setting_enable">использовать обновление</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_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="tasker_start_service">Запуск службы</string>
|
||||||
|
<string name="tasker_setting_confirm">Подтвердить</string>
|
||||||
|
|
||||||
|
<string name="routing_settings_title">Настройки маршрутизации</string>
|
||||||
|
<string name="routing_settings_tips">Введите требуемые IP/URL через запятую. Не забудьте сохранить изменения.</string>
|
||||||
|
<string name="routing_settings_save">Сохранить</string>
|
||||||
|
<string name="routing_settings_delete">Очистить</string>
|
||||||
|
<string name="routing_settings_scan_replace">Сканировать и заменить</string>
|
||||||
|
<string name="routing_settings_scan_append">Сканировать и добавить</string>
|
||||||
|
<string name="routing_settings_default_rules"> Правила по умолчанию</string>
|
||||||
|
|
||||||
|
<string name="connection_test_pending">Проверить подключение</string>
|
||||||
|
<string name="connection_test_testing">Проверка…</string>
|
||||||
|
<string name="connection_test_available">Успешно: рукопожатие HTTP заняло %d мс</string>
|
||||||
|
<string name="connection_test_error">Сбой проверки интернет-соединения: %s</string>
|
||||||
|
<string name="connection_test_fail">Интернет недоступен</string>
|
||||||
|
<string name="connection_test_error_status_code">Код ошибки: #%d</string>
|
||||||
|
<string name="connection_connected">Подключено, нажмите для проверки</string>
|
||||||
|
<string name="connection_not_connected">Не подключено</string>
|
||||||
|
|
||||||
|
<string-array name="share_method">
|
||||||
|
<item>QR-код</item>
|
||||||
|
<item>Экспорт в буфер обмена</item>
|
||||||
|
<item>Экспорт всего профиля в буфер обмена</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="routing_tag">
|
||||||
|
<item>Проксируемые</item>
|
||||||
|
<item>Прямые</item>
|
||||||
|
<item>Блокируемые</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="routing_mode">
|
||||||
|
<item>Все через прокси</item>
|
||||||
|
<item>Все, кроме LAN через прокси</item>
|
||||||
|
<item>Все, кроме Китая через прокси</item>
|
||||||
|
<item>Все, кроме LAN и Китая через прокси</item>
|
||||||
|
<item>Все напрямую</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="mode_entries">
|
||||||
|
<item>VPN</item>
|
||||||
|
<item>Только прокси</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
</resources>
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
<string name="menu_item_import_config_manually_trojan">手動鍵入 [Trojan]</string>
|
<string name="menu_item_import_config_manually_trojan">手動鍵入 [Trojan]</string>
|
||||||
<string name="menu_item_import_config_custom">自訂組態</string>
|
<string name="menu_item_import_config_custom">自訂組態</string>
|
||||||
<string name="menu_item_import_config_custom_clipboard">從剪貼簿匯入自訂組態</string>
|
<string name="menu_item_import_config_custom_clipboard">從剪貼簿匯入自訂組態</string>
|
||||||
<string name="menu_item_import_config_custom_local">從 URL 匯入自訂組態</string>
|
<string name="menu_item_import_config_custom_local">從本地匯入自訂組態</string>
|
||||||
<string name="menu_item_import_config_custom_url">從 URL 匯入自訂組態</string>
|
<string name="menu_item_import_config_custom_url">從 URL 匯入自訂組態</string>
|
||||||
<string name="menu_item_import_config_custom_url_scan">掃描 URL 匯入自訂組態</string>
|
<string name="menu_item_import_config_custom_url_scan">掃描 URL 匯入自訂組態</string>
|
||||||
<string name="del_config_comfirm">確定刪除?</string>
|
<string name="del_config_comfirm">確定刪除?</string>
|
||||||
|
|||||||
@@ -60,6 +60,21 @@
|
|||||||
<item>xtls</item>
|
<item>xtls</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="streamsecurity_utls" translatable="false">
|
||||||
|
<item></item>
|
||||||
|
<item>chrome</item>
|
||||||
|
<item>firefox</item>
|
||||||
|
<item>safari</item>
|
||||||
|
<item>randomized</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="streamsecurity_alpn" translatable="false">
|
||||||
|
<item></item>
|
||||||
|
<item>h2</item>
|
||||||
|
<item>http/1.1</item>
|
||||||
|
<item>h2,http/1.1</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="allowinsecures" translatable="false">
|
<string-array name="allowinsecures" translatable="false">
|
||||||
<item></item>
|
<item></item>
|
||||||
<item>true</item>
|
<item>true</item>
|
||||||
@@ -146,6 +161,7 @@
|
|||||||
<item>中文简体</item>
|
<item>中文简体</item>
|
||||||
<item>中文繁體</item>
|
<item>中文繁體</item>
|
||||||
<item>Tiếng Việt</item>
|
<item>Tiếng Việt</item>
|
||||||
|
<item>Русский</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
|
||||||
@@ -155,5 +171,6 @@
|
|||||||
<item>zh-rCN</item>
|
<item>zh-rCN</item>
|
||||||
<item>zh-rTW</item>
|
<item>zh-rTW</item>
|
||||||
<item>vi</item>
|
<item>vi</item>
|
||||||
|
<item>ru</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -49,6 +49,8 @@
|
|||||||
<string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC security</string>
|
<string name="server_lab_request_host">request host(host/ws host/h2 host)/QUIC security</string>
|
||||||
<string name="server_lab_path">path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName</string>
|
<string name="server_lab_path">path(ws path/h2 path)/QUIC key/kcp seed/gRPC serviceName</string>
|
||||||
<string name="server_lab_stream_security">tls</string>
|
<string name="server_lab_stream_security">tls</string>
|
||||||
|
<string name="server_lab_stream_fingerprint" translatable="false">uTLS</string>
|
||||||
|
<string name="server_lab_stream_alpn" translatable="false">alpn</string>
|
||||||
<string name="server_lab_allow_insecure">allowInsecure</string>
|
<string name="server_lab_allow_insecure">allowInsecure</string>
|
||||||
<string name="server_lab_sni">SNI</string>
|
<string name="server_lab_sni">SNI</string>
|
||||||
<string name="server_lab_address3">address</string>
|
<string name="server_lab_address3">address</string>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ buildscript {
|
|||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven { url 'https://maven.google.com' }
|
maven { url 'https://maven.google.com' }
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
jcenter()
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||||
|
|||||||
Reference in New Issue
Block a user