Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
884b444a41 | ||
|
|
e1ff2df36e | ||
|
|
61c0111778 | ||
|
|
bfc9a64e07 | ||
|
|
2ba92045cc | ||
|
|
aeca9f51c8 | ||
|
|
b107c0ac1d | ||
|
|
65a04b4784 | ||
|
|
eab9f50cfd | ||
|
|
b8bb83b524 | ||
|
|
93eb9fe3b9 | ||
|
|
5f167512f5 | ||
|
|
a727b81263 | ||
|
|
f27c9192d1 | ||
|
|
90153fa17f | ||
|
|
cdfaa01852 | ||
|
|
33d2c3b00d | ||
|
|
b7f992cdc0 | ||
|
|
0a6a24e309 | ||
|
|
153b4cffef | ||
|
|
f09a413232 | ||
|
|
cba58f6ae2 | ||
|
|
2bf4b91488 | ||
|
|
b60b7f4307 | ||
|
|
e4ca04a096 | ||
|
|
d0f7ecec44 |
@@ -11,8 +11,8 @@ android {
|
||||
applicationId = "com.v2ray.ang"
|
||||
minSdk = 21
|
||||
targetSdk = 35
|
||||
versionCode = 604
|
||||
versionName = "1.9.10"
|
||||
versionCode = 607
|
||||
versionName = "1.9.12"
|
||||
multiDexEnabled = true
|
||||
splits {
|
||||
abi {
|
||||
|
||||
17
V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/NetworkType.kt
Normal file
17
V2rayNG/app/src/main/kotlin/com/v2ray/ang/dto/NetworkType.kt
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.v2ray.ang.dto
|
||||
|
||||
enum class NetworkType(val type: String) {
|
||||
TCP("tcp"),
|
||||
KCP("kcp"),
|
||||
WS("ws"),
|
||||
HTTP_UPGRADE("httpupgrade"),
|
||||
SPLIT_HTTP("splithttp"),
|
||||
HTTP("http"),
|
||||
H2("h2"),
|
||||
QUIC("quic"),
|
||||
GRPC("grpc");
|
||||
|
||||
companion object {
|
||||
fun fromString(type: String?) = entries.find { it.type == type } ?: TCP
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.v2ray.ang.fmt
|
||||
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.dto.NetworkType
|
||||
import com.v2ray.ang.dto.ProfileItem
|
||||
import com.v2ray.ang.extension.isNotNullEmpty
|
||||
import com.v2ray.ang.util.Utils
|
||||
@@ -31,7 +32,6 @@ open class FmtBase {
|
||||
|
||||
fun getQueryDic(config: ProfileItem): HashMap<String, String> {
|
||||
val dicQuery = HashMap<String, String>()
|
||||
|
||||
dicQuery["security"] = config.security?.ifEmpty { "none" }.orEmpty()
|
||||
config.sni.let { if (it.isNotNullEmpty()) dicQuery["sni"] = it.orEmpty() }
|
||||
config.alpn.let { if (it.isNotNullEmpty()) dicQuery["alpn"] = it.orEmpty() }
|
||||
@@ -41,37 +41,38 @@ open class FmtBase {
|
||||
config.spiderX.let { if (it.isNotNullEmpty()) dicQuery["spx"] = it.orEmpty() }
|
||||
config.flow.let { if (it.isNotNullEmpty()) dicQuery["flow"] = it.orEmpty() }
|
||||
|
||||
dicQuery["type"] = config.network?.ifEmpty { AppConfig.DEFAULT_NETWORK }.orEmpty()
|
||||
val networkType = NetworkType.fromString(config.network)
|
||||
dicQuery["type"] = networkType.type
|
||||
|
||||
when (config.network) {
|
||||
"tcp" -> {
|
||||
when (networkType) {
|
||||
NetworkType.TCP -> {
|
||||
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
|
||||
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
|
||||
}
|
||||
|
||||
"kcp" -> {
|
||||
NetworkType.KCP -> {
|
||||
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
|
||||
config.seed.let { if (it.isNotNullEmpty()) dicQuery["seed"] = it.orEmpty() }
|
||||
}
|
||||
|
||||
"ws", "httpupgrade", "splithttp" -> {
|
||||
NetworkType.WS, NetworkType.HTTP_UPGRADE, NetworkType.SPLIT_HTTP -> {
|
||||
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
|
||||
config.path.let { if (it.isNotNullEmpty()) dicQuery["path"] = it.orEmpty() }
|
||||
}
|
||||
|
||||
"http", "h2" -> {
|
||||
NetworkType.HTTP, NetworkType.H2 -> {
|
||||
dicQuery["type"] = "http"
|
||||
config.host.let { if (it.isNotNullEmpty()) dicQuery["host"] = it.orEmpty() }
|
||||
config.path.let { if (it.isNotNullEmpty()) dicQuery["path"] = it.orEmpty() }
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
NetworkType.QUIC -> {
|
||||
dicQuery["headerType"] = config.headerType?.ifEmpty { "none" }.orEmpty()
|
||||
config.quicSecurity.let { if (it.isNotNullEmpty()) dicQuery["quicSecurity"] = it.orEmpty() }
|
||||
config.quicKey.let { if (it.isNotNullEmpty()) dicQuery["key"] = it.orEmpty() }
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
NetworkType.GRPC -> {
|
||||
config.mode.let { if (it.isNotNullEmpty()) dicQuery["mode"] = it.orEmpty() }
|
||||
config.authority.let { if (it.isNotNullEmpty()) dicQuery["authority"] = it.orEmpty() }
|
||||
config.serviceName.let { if (it.isNotNullEmpty()) dicQuery["serviceName"] = it.orEmpty() }
|
||||
|
||||
@@ -19,9 +19,9 @@ object ShadowsocksFmt : FmtBase() {
|
||||
config.serverPort = uri.port.toString()
|
||||
|
||||
val result = if (uri.userInfo.contains(":")) {
|
||||
uri.userInfo.split(":")
|
||||
uri.userInfo.split(":", limit = 2)
|
||||
} else {
|
||||
Utils.decode(uri.userInfo).split(":")
|
||||
Utils.decode(uri.userInfo).split(":", limit = 2)
|
||||
}
|
||||
if (result.count() == 2) {
|
||||
config.method = result.first()
|
||||
|
||||
@@ -21,7 +21,7 @@ object SocksFmt : FmtBase() {
|
||||
config.serverPort = uri.port.toString()
|
||||
|
||||
if (uri.userInfo?.isEmpty() == false) {
|
||||
val result = Utils.decode(uri.userInfo).split(":")
|
||||
val result = Utils.decode(uri.userInfo).split(":", limit = 2)
|
||||
if (result.count() == 2) {
|
||||
config.username = result.first()
|
||||
config.password = result.last()
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.text.TextUtils
|
||||
import android.util.Log
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.dto.EConfigType
|
||||
import com.v2ray.ang.dto.NetworkType
|
||||
import com.v2ray.ang.dto.ProfileItem
|
||||
import com.v2ray.ang.dto.V2rayConfig.OutboundBean
|
||||
import com.v2ray.ang.dto.VmessQRCode
|
||||
@@ -52,22 +53,24 @@ object VmessFmt : FmtBase() {
|
||||
config.host = vmessQRCode.host
|
||||
config.path = vmessQRCode.path
|
||||
|
||||
when (config.network) {
|
||||
"kcp" -> {
|
||||
when (NetworkType.fromString(config.network)) {
|
||||
NetworkType.KCP -> {
|
||||
config.seed = vmessQRCode.path
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
NetworkType.QUIC -> {
|
||||
config.quicSecurity = vmessQRCode.host
|
||||
config.quicKey = vmessQRCode.path
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
NetworkType.GRPC -> {
|
||||
config.mode = vmessQRCode.type
|
||||
config.serviceName = vmessQRCode.path
|
||||
config.authority = vmessQRCode.host
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
config.security = vmessQRCode.tls
|
||||
config.insecure = allowInsecure
|
||||
config.sni = vmessQRCode.sni
|
||||
@@ -90,22 +93,24 @@ object VmessFmt : FmtBase() {
|
||||
|
||||
vmessQRCode.net = config.network.orEmpty()
|
||||
vmessQRCode.type = config.headerType.orEmpty()
|
||||
when (config.network) {
|
||||
"kcp" -> {
|
||||
when (NetworkType.fromString(config.network)) {
|
||||
NetworkType.KCP -> {
|
||||
vmessQRCode.path = config.seed.orEmpty()
|
||||
}
|
||||
|
||||
"quic" -> {
|
||||
NetworkType.QUIC -> {
|
||||
vmessQRCode.host = config.quicSecurity.orEmpty()
|
||||
vmessQRCode.path = config.quicKey.orEmpty()
|
||||
}
|
||||
|
||||
"grpc" -> {
|
||||
NetworkType.GRPC -> {
|
||||
vmessQRCode.type = config.mode.orEmpty()
|
||||
vmessQRCode.path = config.serviceName.orEmpty()
|
||||
vmessQRCode.host = config.authority.orEmpty()
|
||||
}
|
||||
else -> {}
|
||||
}
|
||||
|
||||
config.host.let { if (it.isNotNullEmpty()) vmessQRCode.host = it.orEmpty() }
|
||||
config.path.let { if (it.isNotNullEmpty()) vmessQRCode.path = it.orEmpty() }
|
||||
|
||||
@@ -119,7 +124,7 @@ object VmessFmt : FmtBase() {
|
||||
}
|
||||
|
||||
fun parseVmessStd(str: String): ProfileItem? {
|
||||
var allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
|
||||
val allowInsecure = MmkvManager.decodeSettingsBool(AppConfig.PREF_ALLOW_INSECURE, false)
|
||||
val config = ProfileItem.create(EConfigType.VMESS)
|
||||
|
||||
val uri = URI(Utils.fixIllegalUrl(str))
|
||||
@@ -132,7 +137,7 @@ object VmessFmt : FmtBase() {
|
||||
config.password = uri.userInfo
|
||||
config.method = AppConfig.DEFAULT_SECURITY
|
||||
|
||||
config.network = queryParam["type"] ?: "tcp"
|
||||
config.network = NetworkType.fromString(queryParam["type"]).name
|
||||
config.headerType = queryParam["headerType"]
|
||||
config.host = queryParam["host"]
|
||||
config.path = queryParam["path"]
|
||||
|
||||
@@ -277,7 +277,7 @@ object AngConfigManager {
|
||||
if (serverList.isNotEmpty()) {
|
||||
var count = 0
|
||||
for (srv in serverList.reversed()) {
|
||||
val config = CustomFmt.parse(server) ?: continue
|
||||
val config = CustomFmt.parse(JsonUtil.toJson(srv)) ?: continue
|
||||
config.subscriptionId = subid
|
||||
val key = MmkvManager.encodeServerConfig("", config)
|
||||
MmkvManager.encodeServerRaw(key, JsonUtil.toJsonPretty(srv))
|
||||
|
||||
@@ -19,7 +19,7 @@ object MigrateManager {
|
||||
if (serverStorage.count().toInt() == 0) {
|
||||
return false
|
||||
}
|
||||
var serverList = serverStorage.allKeys() ?: return false
|
||||
val serverList = serverStorage.allKeys() ?: return false
|
||||
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-" + serverList.count())
|
||||
|
||||
for (guid in serverList) {
|
||||
@@ -36,7 +36,7 @@ object MigrateManager {
|
||||
|
||||
//check and remove old
|
||||
decodeServerConfig(guid) ?: continue
|
||||
serverStorage.remove(guid)
|
||||
//serverStorage.remove(guid)
|
||||
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-" + config.remarks)
|
||||
}
|
||||
Log.d(ANG_PACKAGE, "migrateServerConfig2Profile-end")
|
||||
@@ -70,10 +70,10 @@ object MigrateManager {
|
||||
config.serverPort = outbound.getServerPort().toString()
|
||||
config.method = outbound.getSecurityEncryption()
|
||||
config.password = outbound.getPassword()
|
||||
config.flow = outbound?.settings?.vnext?.get(0)?.users[0]?.flow ?: outbound?.settings?.servers?.get(0)?.flow
|
||||
config.flow = outbound?.settings?.vnext?.get(0)?.users?.get(0)?.flow ?: outbound?.settings?.servers?.get(0)?.flow
|
||||
|
||||
config.network = outbound?.streamSettings?.network ?: "tcp"
|
||||
outbound.getTransportSettingDetails()?.let { transportDetails ->
|
||||
config.network = "tcp"
|
||||
config.headerType = transportDetails[0].orEmpty()
|
||||
config.host = transportDetails[1].orEmpty()
|
||||
config.path = transportDetails[2].orEmpty()
|
||||
|
||||
@@ -336,7 +336,7 @@ object MmkvManager {
|
||||
}
|
||||
|
||||
fun decodeSettingsBool(key: String): Boolean {
|
||||
return settingsStorage.decodeBool(key)
|
||||
return settingsStorage.decodeBool(key,false)
|
||||
}
|
||||
|
||||
fun decodeSettingsBool(key: String, defaultValue: Boolean): Boolean {
|
||||
|
||||
@@ -334,9 +334,7 @@ object V2rayConfigManager {
|
||||
servers.add(
|
||||
V2rayConfig.DnsBean.ServersBean(
|
||||
address = remoteDns.first(),
|
||||
port = 53,
|
||||
domains = proxyDomain,
|
||||
expectIPs = null
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -350,7 +348,6 @@ object V2rayConfigManager {
|
||||
servers.add(
|
||||
V2rayConfig.DnsBean.ServersBean(
|
||||
address = domesticDns.first(),
|
||||
port = 53,
|
||||
domains = directDomain,
|
||||
expectIPs = if (isCnRoutingMode) geoipCn else null,
|
||||
skipFallback = true
|
||||
@@ -458,7 +455,7 @@ object V2rayConfigManager {
|
||||
val host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host
|
||||
|
||||
val requestString: String by lazy {
|
||||
"""{"version":"1.1","method":"GET","headers":{"User-Agent":"Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.122 Mobile Safari/537.36"Safari/537.36,"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
|
||||
"""{"version":"1.1","method":"GET","headers":{"User-Agent":["Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.122 Mobile Safari/537.36"],"Accept-Encoding":["gzip, deflate"],"Connection":["keep-alive"],"Pragma":"no-cache"}}"""
|
||||
}
|
||||
outbound.streamSettings?.tcpSettings?.header?.request = JsonUtil.fromJson(
|
||||
requestString,
|
||||
|
||||
@@ -8,11 +8,11 @@ import com.v2ray.ang.service.V2RayServiceManager
|
||||
|
||||
class BootReceiver : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context?, intent: Intent?) {
|
||||
if (Intent.ACTION_BOOT_COMPLETED == intent?.action && MmkvManager.decodeStartOnBoot()) {
|
||||
if (MmkvManager.getSelectServer().isNullOrEmpty()) {
|
||||
return
|
||||
}
|
||||
V2RayServiceManager.startV2Ray(context!!)
|
||||
}
|
||||
//Check if context is not null and action is the one we want
|
||||
if (context == null || intent?.action != Intent.ACTION_BOOT_COMPLETED) return
|
||||
//Check if flag is true and a server is selected
|
||||
if (!MmkvManager.decodeStartOnBoot() || MmkvManager.getSelectServer().isNullOrEmpty()) return
|
||||
//Start v2ray
|
||||
V2RayServiceManager.startV2Ray(context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,9 @@ class TaskerReceiver : BroadcastReceiver() {
|
||||
try {
|
||||
val bundle = intent?.getBundleExtra(AppConfig.TASKER_EXTRA_BUNDLE)
|
||||
val switch = bundle?.getBoolean(AppConfig.TASKER_EXTRA_BUNDLE_SWITCH, false)
|
||||
val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID, "")
|
||||
val guid = bundle?.getString(AppConfig.TASKER_EXTRA_BUNDLE_GUID).orEmpty()
|
||||
|
||||
if (switch == null || guid == null || TextUtils.isEmpty(guid)) {
|
||||
if (switch == null || TextUtils.isEmpty(guid)) {
|
||||
return
|
||||
} else if (switch) {
|
||||
if (guid == AppConfig.TASKER_DEFAULT_GUID) {
|
||||
|
||||
@@ -8,11 +8,10 @@ import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class ProcessService {
|
||||
private val TAG = ANG_PACKAGE
|
||||
private var process: Process? = null
|
||||
|
||||
fun runProcess(context: Context, cmd: MutableList<String>) {
|
||||
Log.d(TAG, cmd.toString())
|
||||
Log.d(ANG_PACKAGE, cmd.toString())
|
||||
|
||||
try {
|
||||
val proBuilder = ProcessBuilder(cmd)
|
||||
@@ -23,23 +22,23 @@ class ProcessService {
|
||||
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
Thread.sleep(50L)
|
||||
Log.d(TAG, "runProcess check")
|
||||
Log.d(ANG_PACKAGE, "runProcess check")
|
||||
process?.waitFor()
|
||||
Log.d(TAG, "runProcess exited")
|
||||
Log.d(ANG_PACKAGE, "runProcess exited")
|
||||
}
|
||||
Log.d(TAG, process.toString())
|
||||
Log.d(ANG_PACKAGE, process.toString())
|
||||
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, e.toString())
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
}
|
||||
}
|
||||
|
||||
fun stopProcess() {
|
||||
try {
|
||||
Log.d(TAG, "runProcess destroy")
|
||||
Log.d(ANG_PACKAGE, "runProcess destroy")
|
||||
process?.destroy()
|
||||
} catch (e: Exception) {
|
||||
Log.d(TAG, e.toString())
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.service.quicksettings.TileService
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.R
|
||||
import com.v2ray.ang.extension.v2RayApplication
|
||||
import com.v2ray.ang.util.MessageUtil
|
||||
import com.v2ray.ang.util.Utils
|
||||
import java.lang.ref.SoftReference
|
||||
@@ -32,14 +34,20 @@ class QSTileService : TileService() {
|
||||
qsTile?.updateTile()
|
||||
}
|
||||
|
||||
/**
|
||||
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
|
||||
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
|
||||
*/
|
||||
|
||||
override fun onStartListening() {
|
||||
super.onStartListening()
|
||||
setState(Tile.STATE_INACTIVE)
|
||||
mMsgReceive = ReceiveMessageHandler(this)
|
||||
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY), RECEIVER_EXPORTED)
|
||||
ContextCompat.registerReceiver(applicationContext,mMsgReceive,mFilter,ContextCompat.RECEIVER_EXPORTED)
|
||||
} else {
|
||||
registerReceiver(mMsgReceive, IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY))
|
||||
ContextCompat.registerReceiver(applicationContext,mMsgReceive,mFilter,ContextCompat.RECEIVER_NOT_EXPORTED)
|
||||
}
|
||||
|
||||
MessageUtil.sendMsg2Service(this, AppConfig.MSG_REGISTER_CLIENT, "")
|
||||
|
||||
@@ -13,6 +13,7 @@ import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.AppConfig.TAG_DIRECT
|
||||
@@ -65,7 +66,7 @@ object V2RayServiceManager {
|
||||
if (v2rayPoint.isRunning) return
|
||||
val guid = MmkvManager.getSelectServer() ?: return
|
||||
val config = MmkvManager.decodeServerConfig(guid) ?: return
|
||||
if (!Utils.isValidUrl(config.server) && !Utils.isValidUrl(config.server)) return
|
||||
if (!Utils.isValidUrl(config.server) && !Utils.isIpAddress(config.server)) return
|
||||
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
|
||||
// if (!result.status) return
|
||||
|
||||
@@ -126,6 +127,11 @@ object V2RayServiceManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
|
||||
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
|
||||
*/
|
||||
|
||||
fun startV2rayPoint() {
|
||||
val service = serviceControl?.get()?.getService() ?: return
|
||||
val guid = MmkvManager.getSelectServer() ?: return
|
||||
@@ -143,9 +149,15 @@ object V2RayServiceManager {
|
||||
mFilter.addAction(Intent.ACTION_SCREEN_OFF)
|
||||
mFilter.addAction(Intent.ACTION_USER_PRESENT)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
service.registerReceiver(mMsgReceive, mFilter, Context.RECEIVER_EXPORTED)
|
||||
ContextCompat.registerReceiver(
|
||||
service, mMsgReceive, mFilter,
|
||||
ContextCompat.RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
service.registerReceiver(mMsgReceive, mFilter)
|
||||
ContextCompat.registerReceiver(
|
||||
service, mMsgReceive, mFilter,
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
@@ -156,7 +168,7 @@ object V2RayServiceManager {
|
||||
currentConfig = config
|
||||
|
||||
try {
|
||||
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true)
|
||||
v2rayPoint.runLoop(MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6))
|
||||
} catch (e: Exception) {
|
||||
Log.d(ANG_PACKAGE, e.toString())
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.os.StrictMode
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.v2ray.ang.AppConfig
|
||||
import com.v2ray.ang.AppConfig.ANG_PACKAGE
|
||||
import com.v2ray.ang.AppConfig.LOOPBACK
|
||||
import com.v2ray.ang.BuildConfig
|
||||
import com.v2ray.ang.R
|
||||
@@ -153,9 +154,9 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
builder.setSession(V2RayServiceManager.currentConfig?.remarks.orEmpty())
|
||||
|
||||
val selfPackageName = BuildConfig.APPLICATION_ID
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY) == true) {
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PER_APP_PROXY)) {
|
||||
val apps = MmkvManager.decodeSettingsStringSet(AppConfig.PREF_PER_APP_PROXY_SET)
|
||||
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS) == true
|
||||
val bypassApps = MmkvManager.decodeSettingsBool(AppConfig.PREF_BYPASS_APPS)
|
||||
//process self package
|
||||
if (bypassApps) apps?.add(selfPackageName) else apps?.remove(selfPackageName)
|
||||
apps?.forEach {
|
||||
@@ -165,6 +166,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
else
|
||||
builder.addAllowedApplication(it)
|
||||
} catch (e: PackageManager.NameNotFoundException) {
|
||||
Log.d(ANG_PACKAGE, "setup error : --${e.localizedMessage}")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -215,11 +217,11 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
"--loglevel", "notice"
|
||||
)
|
||||
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6) == true) {
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PREFER_IPV6)) {
|
||||
cmd.add("--netif-ip6addr")
|
||||
cmd.add(PRIVATE_VLAN6_ROUTER)
|
||||
}
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED) == true) {
|
||||
if (MmkvManager.decodeSettingsBool(AppConfig.PREF_LOCAL_DNS_ENABLED)) {
|
||||
val localDnsPort = Utils.parseInt(MmkvManager.decodeSettingsString(AppConfig.PREF_LOCAL_DNS_PORT), AppConfig.PORT_LOCAL_DNS.toInt())
|
||||
cmd.add("--dnsgw")
|
||||
cmd.add("$LOOPBACK:${localDnsPort}")
|
||||
@@ -232,7 +234,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
process = proBuilder
|
||||
.directory(applicationContext.filesDir)
|
||||
.start()
|
||||
Thread(Runnable {
|
||||
Thread {
|
||||
Log.d(packageName, "$TUN2SOCKS check")
|
||||
process.waitFor()
|
||||
Log.d(packageName, "$TUN2SOCKS exited")
|
||||
@@ -240,7 +242,7 @@ class V2RayVpnService : VpnService(), ServiceControl {
|
||||
Log.d(packageName, "$TUN2SOCKS restart")
|
||||
runTun2socks()
|
||||
}
|
||||
}).start()
|
||||
}.start()
|
||||
Log.d(packageName, process.toString())
|
||||
|
||||
sendFd()
|
||||
|
||||
@@ -133,7 +133,7 @@ class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedList
|
||||
.request(Manifest.permission.POST_NOTIFICATIONS)
|
||||
.subscribe {
|
||||
if (!it)
|
||||
toast(R.string.toast_permission_denied)
|
||||
toast(R.string.toast_permission_denied_notification)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,8 +159,11 @@ object Utils {
|
||||
/**
|
||||
* is ip address
|
||||
*/
|
||||
fun isIpAddress(value: String): Boolean {
|
||||
fun isIpAddress(value: String?): Boolean {
|
||||
try {
|
||||
if (value.isNullOrEmpty()) {
|
||||
return false
|
||||
}
|
||||
var addr = value
|
||||
if (addr.isEmpty() || addr.isBlank()) {
|
||||
return false
|
||||
|
||||
@@ -31,7 +31,7 @@ object ZipUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filesToCompress.isEmpty) {
|
||||
if (filesToCompress.isEmpty()) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.content.IntentFilter
|
||||
import android.content.res.AssetManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.lifecycle.AndroidViewModel
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.viewModelScope
|
||||
@@ -44,18 +45,24 @@ class MainViewModel(application: Application) : AndroidViewModel(application) {
|
||||
val updateTestResultAction by lazy { MutableLiveData<String>() }
|
||||
private val tcpingTestScope by lazy { CoroutineScope(Dispatchers.IO) }
|
||||
|
||||
/**
|
||||
* Refer to the official documentation for [registerReceiver](https://developer.android.com/reference/androidx/core/content/ContextCompat#registerReceiver(android.content.Context,android.content.BroadcastReceiver,android.content.IntentFilter,int):
|
||||
* `registerReceiver(Context, BroadcastReceiver, IntentFilter, int)`.
|
||||
*/
|
||||
|
||||
fun startListenBroadcast() {
|
||||
isRunning.value = false
|
||||
val mFilter = IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getApplication<AngApplication>().registerReceiver(
|
||||
mMsgReceiver,
|
||||
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY),
|
||||
Context.RECEIVER_EXPORTED
|
||||
ContextCompat.registerReceiver(
|
||||
getApplication(), mMsgReceiver, mFilter,
|
||||
ContextCompat.RECEIVER_EXPORTED
|
||||
)
|
||||
} else {
|
||||
getApplication<AngApplication>().registerReceiver(
|
||||
mMsgReceiver,
|
||||
IntentFilter(AppConfig.BROADCAST_ACTION_ACTIVITY)
|
||||
ContextCompat.registerReceiver(
|
||||
getApplication(), mMsgReceiver, mFilter,
|
||||
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||
)
|
||||
}
|
||||
MessageUtil.sendMsg2Service(getApplication(), AppConfig.MSG_REGISTER_CLIENT, "")
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">إيقاف</string>
|
||||
<string name="toast_permission_denied">تعذر الحصول على الإذن</string>
|
||||
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
|
||||
<string name="notification_action_more">انقر للمزيد</string>
|
||||
<string name="toast_services_start">بدء الخدمات</string>
|
||||
<string name="toast_services_stop">إيقاف الخدمات</string>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">বন্ধ করুন</string>
|
||||
<string name="toast_permission_denied">অনুমতি পাওয়া যাচ্ছে না</string>
|
||||
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
|
||||
<string name="notification_action_more">আরও দেখতে ক্লিক করুন</string>
|
||||
<string name="toast_services_start">সার্ভিস শুরু করুন</string>
|
||||
<string name="toast_services_stop">সার্ভিস বন্ধ করুন</string>
|
||||
|
||||
@@ -10,8 +10,9 @@
|
||||
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">توقف</string>
|
||||
<string name="toast_permission_denied">قادر به دریافت مجوز نیست</string>
|
||||
<string name="notification_action_more">برای اطلاعات بیشتر کلیک کنید</string>
|
||||
<string name="toast_permission_denied">دریافت مجوز امکان پذیر نیست</string>
|
||||
<string name="toast_permission_denied_notification">دریافت مجوز اعلان امکان پذیر نیست</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>
|
||||
@@ -159,7 +160,7 @@
|
||||
<string name="summary_pref_local_dns_enabled">درخواست های DNS به هسته وارد شده و توسط ماژول DNS پردازش می شوند (توصیه می شود در صورت نیاز به مسیریابی برای دور زدن آدرس های LAN و سرزمین اصلی فعال شود)</string>
|
||||
|
||||
<string name="title_pref_fake_dns_enabled">فعال کردن DNS جعلی</string>
|
||||
<string name="summary_pref_fake_dns_enabled">DNS محلی آدرس های آیپی فیک را بر می گرداند (سریع تر می باشد اما ممکن است برای برخی از برنامه ها کار نکند)</string>
|
||||
<string name="summary_pref_fake_dns_enabled">دی ان اس محلی آدرس های آیپی جعلی را بر می گرداند (سریع تر می باشد و تاخیر را کاهش می دهد اما ممکن است برای برخی از برنامه ها کار نکند)</string>
|
||||
|
||||
<string name="title_pref_prefer_ipv6">ترجیح دادن IPv6</string>
|
||||
<string name="summary_pref_prefer_ipv6">ترجیح دادن نشانی و مسیر های IPv6</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">Остановить</string>
|
||||
<string name="toast_permission_denied">Разрешение не получено</string>
|
||||
<string name="toast_permission_denied_notification">Разрешение на отображение уведомлений не получено</string>
|
||||
<string name="notification_action_more">Ещё…</string>
|
||||
<string name="toast_services_start">Запуск служб</string>
|
||||
<string name="toast_services_stop">Остановка служб</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">Ngắt kết nối v2rayNG</string>
|
||||
<string name="toast_permission_denied">Vui lòng cấp quyền cần thiết cho v2rayNG! Bạn đã từ chối các quyền cần thiết như Camera hay Bộ nhớ?</string>
|
||||
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
|
||||
<string name="notification_action_more">Nhấn để biết thêm...</string>
|
||||
<string name="toast_services_start">Đang khởi động v2rayNG...</string>
|
||||
<string name="toast_services_stop">Đã dừng v2rayNG!</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">停止</string>
|
||||
<string name="toast_permission_denied">无法取得权限</string>
|
||||
<string name="toast_permission_denied_notification">无法取得通知权限</string>
|
||||
<string name="notification_action_more">点击了解更多</string>
|
||||
<string name="toast_services_start">启动服务中</string>
|
||||
<string name="toast_services_stop">关闭中</string>
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">停止</string>
|
||||
<string name="toast_permission_denied">無法取得此權限</string>
|
||||
<string name="toast_permission_denied_notification">無法取得此通知權限</string>
|
||||
<string name="notification_action_more">瞭解更多</string>
|
||||
<string name="toast_services_start">啟動服務</string>
|
||||
<string name="toast_services_stop">停止服務</string>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<!-- Notifications -->
|
||||
<string name="notification_action_stop_v2ray">Stop</string>
|
||||
<string name="toast_permission_denied">Unable to obtain the permission</string>
|
||||
<string name="toast_permission_denied_notification">Unable to obtain the notification permission</string>
|
||||
<string name="notification_action_more">click for more</string>
|
||||
<string name="toast_services_start">Start Services</string>
|
||||
<string name="toast_services_stop">Stop Services</string>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
activityKtx = "1.9.3"
|
||||
appcompat = "1.7.0"
|
||||
cardview = "1.0.0"
|
||||
constraintlayout = "2.1.4"
|
||||
constraintlayout = "2.2.0"
|
||||
core = "3.5.3"
|
||||
editorkit = "2.9.0"
|
||||
flexbox = "3.0.0"
|
||||
@@ -12,7 +12,7 @@ junit = "4.13.2"
|
||||
kotlinReflect = "2.0.21"
|
||||
kotlinxCoroutinesCore = "1.9.0"
|
||||
legacySupportV4 = "1.0.0"
|
||||
lifecycleViewmodelKtx = "2.8.6"
|
||||
lifecycleViewmodelKtx = "2.8.7"
|
||||
material = "1.12.0"
|
||||
mmkvStatic = "1.3.9"
|
||||
multidex = "2.0.1"
|
||||
@@ -25,7 +25,7 @@ rxpermissions = "0.12"
|
||||
toastcompat = "1.1.0"
|
||||
viewpager2 = "1.1.0"
|
||||
workRuntimeKtx = "2.9.1"
|
||||
androidGradlePlugin = "8.7.1"
|
||||
androidGradlePlugin = "8.7.2"
|
||||
androidKotlinPlugin = "2.0.21"
|
||||
mockitoMockitoInline = "4.0.0"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#Sun Jul 28 13:40:50 CST 2024
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
distributionUrl=https://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
Reference in New Issue
Block a user