Compare commits

...

38 Commits

Author SHA1 Message Date
2dust
f610e1d20a Merge pull request #1879 from MUedsa/idn_to_accii
only domain idn to ascii
2022-12-30 18:16:37 +08:00
MUEDSA
9f4127a588 only domain idn to ascii 2022-12-30 17:08:36 +08:00
2dust
a211bc24cb up 1.7.31 2022-12-30 12:47:09 +08:00
2dust
6f47aa33e8 Convert idn domain 2022-12-30 12:46:51 +08:00
2dust
90636bb294 Merge pull request #1800 from zjudongze/master
restart tun2socks process if exited abnormally
2022-12-30 10:35:00 +08:00
2dust
ff98ff02c5 up 1.7.30 2022-12-13 19:49:59 +08:00
2dust
dc36986255 up 1.7.28 2022-12-05 20:36:29 +08:00
2dust
5651e002c4 Merge pull request #1822 from yuhan6665/xtls-rv
Add Wireguard outbound (custom config)
2022-12-05 20:00:40 +08:00
yuhan6665
4e7849d1cb Add Wireguard outbound (custom config) 2022-12-04 18:15:17 -05:00
2dust
9e3dba8dbe up 1.7.27 2022-11-28 20:18:17 +08:00
derek.dong
3a1daf1888 restart tun2socks process if exited abnormally 2022-11-23 16:25:38 +08:00
2dust
79ba41354e Merge pull request #1784 from DanielBlackBeard/master
fix Persian language dictation
2022-11-19 11:33:25 +08:00
dany pm
85e866d462 fix Persian language dictation 2022-11-18 17:28:01 +03:30
2dust
2fb5d05040 up 1.7.26 2022-11-14 21:04:29 +08:00
2dust
221b251bbf up 1.7.25 2022-11-07 19:47:42 +08:00
2dust
1a90e77d56 fix language 2022-11-07 19:47:28 +08:00
2dust
0ca1c697c7 Merge pull request #1732 from Goudarz/GJ-Edition
Add Persian translation
2022-11-01 09:02:00 +08:00
Goudarz Jafari
3e9a6b5d5c Persian translation 2022-10-31 18:43:31 +03:30
Goudarz Jafari
77a1d77753 Add Persian translation 2022-10-31 18:43:08 +03:30
2dust
8732ef399c up 1.7.24 2022-10-29 20:57:17 +08:00
2dust
f2720ac00b Merge pull request #1717 from yuhan6665/xtls-rv
Add xtls rprx vision
2022-10-29 19:32:36 +08:00
yuhan6665
1794ae4759 Add xtls rprx vision 2022-10-29 01:29:03 -04:00
2dust
866ceae75c up 1.7.23 2022-10-22 12:13:59 +08:00
2dust
349cac092f bug fix 2022-10-21 10:16:30 +08:00
2dust
613a643528 up 1.7.22 2022-10-20 16:38:27 +08:00
2dust
3144817795 add tls alpn 2022-10-20 16:37:41 +08:00
2dust
6cae2c1785 fix Russian translation 2022-10-20 15:03:59 +08:00
2dust
a71509d130 Merge pull request #1693 from solokot/master
Russian translation
2022-10-16 19:58:13 +08:00
solokot
d4aa419284 Add Russian translation 2022-10-16 09:51:42 +03:00
solokot
b484de5fb7 Russian translation 2022-10-16 09:50:51 +03:00
2dust
13480b0077 up1.7.21 2022-10-14 20:33:10 +08:00
2dust
1987880294 Merge pull request #1689 from BI7PRK/master
Add uTLS option
2022-10-14 20:01:32 +08:00
xskill
0ae459a70e Add uTLS option 2022-10-13 15:07:10 +08:00
2dust
02bc46634d Update README.md 2022-10-10 20:24:52 +08:00
2dust
cfdaa0c54b Update build.gradle 2022-09-19 20:42:01 +08:00
2dust
cbe6c1e3e0 Update build.gradle 2022-09-19 20:25:48 +08:00
2dust
3cd6f12b94 Merge pull request #1639 from zhaoguomanong/master
fix NullPointerException
2022-09-10 19:51:19 +08:00
zhaoguomanong
516235cd6a fix NullPointerException
复现方法:
添加两个订阅A, B -> 选择A中任意节点并启动 -> 删除A订阅, 选中B订阅中任意节点启动 -> crash

09-09 10:53:50.355 18739 18739 D AndroidRuntime: Shutting down VM
09-09 10:53:50.356 18739 18739 E AndroidRuntime: FATAL EXCEPTION: main
09-09 10:53:50.356 18739 18739 E AndroidRuntime: Process: com.v2ray.ang, PID: 18739
09-09 10:53:50.356 18739 18739 E AndroidRuntime: java.lang.NullPointerException
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at com.v2ray.ang.ui.MainRecyclerAdapter.onBindViewHolder$lambda-6(MainRecyclerAdapter.kt:156)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at com.v2ray.ang.ui.MainRecyclerAdapter.$r8$lambda$VmDbsAxtrWNiVtS0BmO3UDui2o4(Unknown Source:0)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at com.v2ray.ang.ui.MainRecyclerAdapter$$ExternalSyntheticLambda2.onClick(Unknown Source:4)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.view.View.performClick(View.java:6597)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.view.View.performClickInternal(View.java:6574)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.view.View.access$3100(View.java:778)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.view.View$PerformClick.run(View.java:25906)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.os.Handler.handleCallback(Handler.java:873)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.os.Handler.dispatchMessage(Handler.java:99)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.os.Looper.loop(Looper.java:193)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at android.app.ActivityThread.main(ActivityThread.java:6718)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at java.lang.reflect.Method.invoke(Native Method)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:491)
09-09 10:53:50.356 18739 18739 E AndroidRuntime: 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)

Signed-off-by: zhaoguomanong <zhaoguomanong@gmail.com>
2022-09-09 13:12:15 +08:00
21 changed files with 704 additions and 211 deletions

View File

@@ -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" />
</a>
### Telegram Channel
[github_2dust](https://t.me/github_2dust)
### Usage
#### Geoip and Geosite

View File

@@ -18,8 +18,8 @@ android {
minSdkVersion 21
targetSdkVersion Integer.parseInt("$targetSdkVer")
multiDexEnabled true
versionCode 473
versionName "1.7.19"
versionCode 492
versionName "1.7.31"
}
if (props["sign"]) {

View File

@@ -6,7 +6,8 @@ enum class EConfigType(val value: Int, val protocolScheme: String) {
SHADOWSOCKS(3, "ss://"),
SOCKS(4, "socks://"),
VLESS(5, "vless://"),
TROJAN(6, "trojan://");
TROJAN(6, "trojan://"),
WIREGUARD(7, "wireguard://");
companion object {
fun fromInt(value: Int) = values().firstOrNull { it.value == value }

View File

@@ -26,7 +26,7 @@ data class ServerConfig(
vnext = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean(
users = listOf(V2rayConfig.OutboundBean.OutSettingsBean.VnextBean.UsersBean())))),
streamSettings = V2rayConfig.OutboundBean.StreamSettingsBean()))
EConfigType.CUSTOM ->
EConfigType.CUSTOM, EConfigType.WIREGUARD ->
return ServerConfig(configType = configType)
EConfigType.SHADOWSOCKS, EConfigType.SOCKS, EConfigType.TROJAN ->
return ServerConfig(

View File

@@ -27,7 +27,6 @@ data class V2rayConfig(
const val DEFAULT_SECURITY = "auto"
const val DEFAULT_LEVEL = 8
const val DEFAULT_NETWORK = "tcp"
const val DEFAULT_FLOW = "xtls-rprx-splice"
const val TLS = "tls"
const val XTLS = "xtls"
@@ -75,14 +74,18 @@ data class V2rayConfig(
var response: Response? = null,
/*DNS*/
val network: String? = null,
val address: String? = null,
val address: Any? = null,
val port: Int? = null,
/*Freedom*/
var domainStrategy: String? = null,
val redirect: String? = null,
val userLevel: Int? = null,
/*Loopback*/
val inboundTag: String? = null) {
val inboundTag: String? = null,
/*Wireguard*/
val secretKey: String? = null,
val peers: List<WireGuardBean>? = null,
) {
data class VnextBean(var address: String = "",
var port: Int = DEFAULT_PORT,
@@ -114,6 +117,9 @@ data class V2rayConfig(
}
data class Response(var type: String)
data class WireGuardBean(var publicKey: String = "",
var endpoint: String = "")
}
data class StreamSettingsBean(var network: String = DEFAULT_NETWORK,
@@ -259,11 +265,13 @@ data class V2rayConfig(
return sni
}
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String) {
fun populateTlsSettings(streamSecurity: String, allowInsecure: Boolean, sni: String, fingerprint: String?, alpns: String?) {
security = streamSecurity
val tlsSetting = TlsSettingsBean(
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) {
tlsSettings = tlsSetting
@@ -285,6 +293,8 @@ data class V2rayConfig(
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) {
return settings?.servers?.get(0)?.address
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringBeforeLast(":")
}
return null
}
@@ -297,6 +307,8 @@ data class V2rayConfig(
|| protocol.equals(EConfigType.SOCKS.name, true)
|| protocol.equals(EConfigType.TROJAN.name, true)) {
return settings?.servers?.get(0)?.port
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.peers?.get(0)?.endpoint?.substringAfterLast(":")?.toInt()
}
return null
}
@@ -310,6 +322,8 @@ data class V2rayConfig(
return settings?.servers?.get(0)?.password
} else if (protocol.equals(EConfigType.SOCKS.name, true)) {
return settings?.servers?.get(0)?.users?.get(0)?.pass
} else if (protocol.equals(EConfigType.WIREGUARD.name, true)) {
return settings?.secretKey
}
return null
}
@@ -425,12 +439,10 @@ data class V2rayConfig(
fun getProxyOutbound(): OutboundBean? {
outbounds.forEach { outbound ->
if (outbound.protocol.equals(EConfigType.VMESS.name, true) ||
outbound.protocol.equals(EConfigType.VLESS.name, true) ||
outbound.protocol.equals(EConfigType.SHADOWSOCKS.name, true) ||
outbound.protocol.equals(EConfigType.SOCKS.name, true) ||
outbound.protocol.equals(EConfigType.TROJAN.name, true)) {
return outbound
EConfigType.values().forEach {
if (outbound.protocol.equals(it.name, true)) {
return outbound
}
}
}
return null

View File

@@ -12,4 +12,5 @@ data class VmessQRCode(var v: String = "",
var host: String = "",
var path: String = "",
var tls: String = "",
var sni: String = "")
var sni: String = "",
var alpn: String = "")

View File

@@ -36,6 +36,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
private val settingsStorage by lazy { MMKV.mmkvWithID(MmkvManager.ID_SETTING, MMKV.MULTI_PROCESS_MODE) }
private lateinit var mInterface: ParcelFileDescriptor
private var isRunning = false
//val fd: Int get() = mInterface.fd
private lateinit var process: Process
@@ -183,6 +184,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
// Create a new interface using the builder and save the parameters.
try {
mInterface = builder.establish()!!
isRunning = true
runTun2socks()
} catch (e: Exception) {
// non-nullable lateinit var
@@ -219,6 +221,15 @@ class V2RayVpnService : VpnService(), ServiceControl {
process = proBuilder
.directory(applicationContext.filesDir)
.start()
Thread(Runnable {
Log.d(packageName,"$TUN2SOCKS check")
process.waitFor()
Log.d(packageName,"$TUN2SOCKS exited")
if (isRunning) {
Log.d(packageName,"$TUN2SOCKS restart")
runTun2socks()
}
}).start()
Log.d(packageName, process.toString())
sendFd()
@@ -262,6 +273,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
// val emptyInfo = VpnNetworkInfo()
// val info = loadVpnNetworkInfo(configName, emptyInfo)!! + (lastNetworkInfo ?: emptyInfo)
// saveVpnNetworkInfo(configName, info)
isRunning = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
try {
connectivity.unregisterNetworkCallback(defaultNetworkCallback)

View File

@@ -488,7 +488,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
if (!it.second.enabled) {
return@forEach
}
val url = it.second.url
val url = Utils.idnToASCII(it.second.url)
if (!Utils.isValidUrl(url)) {
return@forEach
}

View File

@@ -2,6 +2,7 @@ package com.v2ray.ang.ui
import android.content.Intent
import android.graphics.Color
import android.text.TextUtils
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
@@ -153,7 +154,9 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter<Mai
val selected = mainStorage?.decodeString(MmkvManager.KEY_SELECTED_SERVER)
if (guid != selected) {
mainStorage?.encode(MmkvManager.KEY_SELECTED_SERVER, guid)
notifyItemChanged(mActivity.mainViewModel.getPosition(selected!!))
if (!TextUtils.isEmpty(selected)) {
notifyItemChanged(mActivity.mainViewModel.getPosition(selected!!))
}
notifyItemChanged(mActivity.mainViewModel.getPosition(guid))
if (isRunning) {
mActivity.showCircle()

View File

@@ -14,9 +14,7 @@ import com.v2ray.ang.R
import com.v2ray.ang.dto.EConfigType
import com.v2ray.ang.dto.ServerConfig
import com.v2ray.ang.dto.V2rayConfig
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_FLOW
import com.v2ray.ang.dto.V2rayConfig.Companion.DEFAULT_PORT
import com.v2ray.ang.dto.V2rayConfig.Companion.XTLS
import com.v2ray.ang.extension.toast
import com.v2ray.ang.util.MmkvManager
import com.v2ray.ang.util.MmkvManager.ID_MAIN
@@ -67,7 +65,12 @@ class ServerActivity : BaseActivity() {
private val allowinsecures: Array<out String> by lazy {
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.
// 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.
@@ -82,11 +85,13 @@ class ServerActivity : BaseActivity() {
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 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_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 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 sp_stream_alpn: Spinner? by lazy { findViewById(R.id.sp_stream_alpn) } //uTLS
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -170,6 +175,16 @@ class ServerActivity : BaseActivity() {
sp_allow_insecure?.setSelection(allowinsecure)
}
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)
@@ -268,11 +283,7 @@ class ServerActivity : BaseActivity() {
vnext.users[0].security = securitys[sp_security?.selectedItemPosition ?: 0]
} else if (config.configType == EConfigType.VLESS) {
vnext.users[0].encryption = et_security?.text.toString().trim()
if (streamSecuritys[sp_stream_security?.selectedItemPosition ?: 0] == XTLS) {
vnext.users[0].flow = flows[sp_flow?.selectedItemPosition ?: 0].ifBlank { DEFAULT_FLOW }
} else {
vnext.users[0].flow = ""
}
vnext.users[0].flow = flows[sp_flow?.selectedItemPosition ?: 0]
}
}
@@ -294,8 +305,8 @@ class ServerActivity : BaseActivity() {
} else if (config.configType == EConfigType.TROJAN) {
server.password = et_id.text.toString().trim()
server.flow =
if (streamSecuritys[sp_stream_security?.selectedItemPosition ?: 0] == XTLS) {
flows[sp_flow?.selectedItemPosition ?: 0].ifBlank { DEFAULT_FLOW }
if (streamSecuritys[sp_stream_security?.selectedItemPosition ?: 0] == V2rayConfig.XTLS) {
flows[sp_flow?.selectedItemPosition ?: 0]
} else {
""
}
@@ -310,6 +321,8 @@ class ServerActivity : BaseActivity() {
val sniField = et_sni?.text?.toString()?.trim() ?: return
val allowInsecureField = sp_allow_insecure?.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(
transport = networks[network],
@@ -330,7 +343,8 @@ class ServerActivity : BaseActivity() {
} else {
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> {

View File

@@ -143,8 +143,9 @@ object AngConfigManager {
} else {
vmessBean.allowInsecure.toBoolean()
}
var fingerprint = streamSetting.tlsSettings?.fingerprint
streamSetting.populateTlsSettings(vmessBean.streamSecurity, allowInsecure,
vmessBean.sni.ifBlank { sni })
vmessBean.sni.ifBlank { sni }, fingerprint, null)
}
}
val key = MmkvManager.encodeServerConfig(vmessBean.guid, config)
@@ -185,6 +186,9 @@ object AngConfigManager {
config = ServerConfig.create(EConfigType.VMESS)
val streamSetting = config.outboundBean?.streamSettings ?: return -1
var fingerprint = streamSetting.tlsSettings?.fingerprint
if (!tryParseNewVmess(str, config, allowInsecure)) {
if (str.indexOf("?") > 0) {
if (!tryResolveVmess4Kitsunebi(str, config)) {
@@ -216,8 +220,10 @@ object AngConfigManager {
}
val sni = streamSetting.populateTransportSettings(vmessQRCode.net, vmessQRCode.type, vmessQRCode.host,
vmessQRCode.path, vmessQRCode.path, vmessQRCode.host, vmessQRCode.path, vmessQRCode.type, vmessQRCode.path)
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)) {
@@ -292,6 +298,7 @@ object AngConfigManager {
config.remarks = Utils.urlDecode(uri.fragment ?: "")
var flow = ""
var fingerprint = config.outboundBean?.streamSettings?.tlsSettings?.fingerprint
if (uri.rawQuery != null) {
val queryParam = uri.rawQuery.split("&")
.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"],
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
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"] ?: ""
} else {
config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, "")
config.outboundBean?.streamSettings?.populateTlsSettings(TLS, allowInsecure, "", fingerprint, null)
}
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) } }
config = ServerConfig.create(EConfigType.VLESS)
val streamSetting = config.outboundBean?.streamSettings ?: return -1
var fingerprint = streamSetting.tlsSettings?.fingerprint
config.remarks = Utils.urlDecode(uri.fragment ?: "")
config.outboundBean?.settings?.vnext?.get(0)?.let { vnext ->
vnext.address = uri.idnHost
@@ -329,7 +339,7 @@ object AngConfigManager {
val sni = streamSetting.populateTransportSettings(queryParam["type"] ?: "tcp", queryParam["headerType"],
queryParam["host"], queryParam["path"], queryParam["seed"], queryParam["quicSecurity"], queryParam["key"],
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){
return R.string.toast_incorrect_protocol
@@ -369,12 +379,12 @@ object AngConfigManager {
vnext.users[0].security = DEFAULT_SECURITY
vnext.users[0].alterId = alterId.toInt()
}
var fingerprint = streamSetting.tlsSettings?.fingerprint
val sni = streamSetting.populateTransportSettings(protocol, queryParam["type"],
queryParam["host"]?.split("|")?.get(0) ?: "",
queryParam["path"]?.takeIf { it.trim() != "/" } ?: "", queryParam["seed"], queryParam["security"],
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
}.getOrElse { false }
}
@@ -467,6 +477,7 @@ object AngConfigManager {
vmessQRCode.net = streamSetting.network
vmessQRCode.tls = streamSetting.security
vmessQRCode.sni = streamSetting.tlsSettings?.serverName.orEmpty()
vmessQRCode.alpn = Utils.removeWhiteSpace(streamSetting.tlsSettings?.alpn?.joinToString()).orEmpty()
outbound.getTransportSettingDetails()?.let { transportDetails ->
vmessQRCode.type = transportDetails[0]
vmessQRCode.host = transportDetails[1]
@@ -475,7 +486,7 @@ object AngConfigManager {
val json = Gson().toJson(vmessQRCode)
Utils.encode(json)
}
EConfigType.CUSTOM -> ""
EConfigType.CUSTOM, EConfigType.WIREGUARD -> ""
EConfigType.SHADOWSOCKS -> {
val remark = "#" + Utils.urlEncode(config.remarks)
val pw = Utils.encode("${outbound.getSecurityEncryption()}:${outbound.getPassword()}")
@@ -521,6 +532,9 @@ object AngConfigManager {
if (!TextUtils.isEmpty(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 }

View File

@@ -409,6 +409,8 @@ object Utils {
"zh-rCN" -> Locale("zh", "CN")
"zh-rTW" -> Locale("zh", "TW")
"vi" -> Locale("vi")
"ru" -> Locale("ru")
"fa" -> Locale("fa")
else -> getSysLocale()
}
@@ -423,5 +425,15 @@ object Utils {
.replace(" ","%20")
.replace("|","%7C")
}
fun removeWhiteSpace(str: String?): String? {
return str?.replace(" ", "")
}
fun idnToASCII(str: String): String {
val url = URL(str)
return URL(url.protocol, IDN.toASCII(url.host, IDN.ALLOW_UNASSIGNED), url.port, url.file)
.toExternalForm()
}
}

View File

@@ -61,7 +61,10 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
fun removeServer(guid: String) {
serverList.remove(guid)
MmkvManager.removeServer(guid)
serversCache.removeAt(getPosition(guid))
val index = getPosition(guid)
if(index >= 0){
serversCache.removeAt(index)
}
}
fun appendCustomConfigServer(server: String) {

View File

@@ -202,64 +202,7 @@
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_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>
<include layout="@layout/tls_layout" />
<LinearLayout
android:layout_width="match_parent"

View File

@@ -223,63 +223,7 @@
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_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>
<include layout="@layout/tls_layout" />
<LinearLayout
android:layout_width="match_parent"

View File

@@ -222,64 +222,7 @@
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_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>
<include layout="@layout/tls_layout" />
<LinearLayout
android:layout_width="match_parent"

View 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>

View File

@@ -0,0 +1,229 @@
<?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">پیکربندی را از QRcode وارد کنید</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">پیکربندی سفارشی را از طریق نشانی اینترنتی وارد کنید</string>
<string name="menu_item_import_config_custom_url_scan">نشانی اینترنتی اسکن پیکربندی سفارشی را وارد کنید</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">شناسه</string>
<string name="server_lab_alterid">alterId</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">نوع head</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" 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_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">نشانی اینترنتی معتبر نیست</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">حالت Bypass</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حالت bypass: برنامه بررسی شده مستقیما متصل است، پراکسی بررسی نشده است. \nگزینهای برای انتخاب خودکار پروکسی برنامه در منو است</string>
<string name="title_pref_mux_enabled">فعال کردن Mux</string>
<string name="summary_pref_mux_enabled">فعال کردن شاید سرعت بخشیدن به شبکه و تغییر شبکه شاید فلش، بهبود کند</string>
<string name="title_pref_speed_enabled">فعال کردن نمایش سرعت</string>
<string name="summary_pref_speed_enabled">نمایش سرعت فعلی در قسمت آگاه‌سازی. \nآیکون آگاه‌سازی بر اساس استفاده تغییر می‌کند.</string>
<string name="title_pref_sniffing_enabled">فعال کردن Sniffing</string>
<string name="summary_pref_sniffing_enabled">دامنه sniff را از بسته امتحان کنید (پیش‌فرض روشن)</string>
<string name="title_pref_local_dns_enabled">فعال کردن DNS محلی</string>
<string name="summary_pref_local_dns_enabled">DNS پردازش شده توسط ماژول DNS هسته (توصیه می‌شود، در صورت نیاز به دور زدن LAN و نشانی mainland)</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">دستگاه‌های دیگر می‌توانند از طریق socks/http به پراکسی توسط نشانی آی‌پی شما متصل شوند، فقط در شبکه مورد اعتماد فعال می‌شوند تا از اتصال غیرمجاز جلوگیری کنند</string>
<string name="toast_warning_pref_proxysharing_short">اتصالات از طریق LAN را مجاز کنید، مطمئن شوید که در یک شبکه قابل اعتماد هستید</string>
<string name="title_pref_allow_insecure">allowInsecure</string>
<string name="summary_pref_allow_insecure">هنگامی که TLS، به طور پیش‌فرض allowInsecure</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">بهبودهای بازخورد یا اشکالات در گیت‌هاب</string>
<string name="summary_pref_tg_group">عضویت در گروه تلگرام</string>
<string name="toast_tg_app_not_found">برنامه تلگرام پیدا نشد</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">نشانی اینترنتی اختیاری</string>
<string name="sub_setting_enable">فعال کردن به‌روزرسانی</string>
<string name="title_sub_update">به‌روزرسانی اشتراک</string>
<string name="title_ping_all_server">Tcping همه پیکربندی</string>
<string name="title_real_ping_all_server">تاخیر واقعی همه پیکربندی</string>
<string name="title_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">با کاما (,) از هم جدا شوند، ذخیره کردن هم فراموش نک</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 %dms طول کشید</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>QRcode</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>دور زذن آدرس mainland و سپس پروکسی</item>
<item>دور زدن LAN و آدرس mainland و سپس پروکسی</item>
<item>مستقیم سراسری</item>
</string-array>
<string-array name="mode_entries">
<item>VPN</item>
<item>فقط پروکسی</item>
</string-array>
</resources>

View 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>

View File

@@ -60,6 +60,21 @@
<item>xtls</item>
</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">
<item></item>
<item>true</item>
@@ -101,6 +116,8 @@
<item>xtls-rprx-direct-udp443</item>
<item>xtls-rprx-splice</item>
<item>xtls-rprx-splice-udp443</item>
<item>xtls-rprx-vision</item>
<item>xtls-rprx-vision-udp443</item>
</string-array>
@@ -146,6 +163,8 @@
<item>中文简体</item>
<item>中文繁體</item>
<item>Tiếng Việt</item>
<item>Русский</item>
<item>فارسی</item>
</string-array>
@@ -155,5 +174,7 @@
<item>zh-rCN</item>
<item>zh-rTW</item>
<item>vi</item>
<item>ru</item>
<item>fa</item>
</string-array>
</resources>

View File

@@ -49,6 +49,8 @@
<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_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_sni">SNI</string>
<string name="server_lab_address3">address</string>