From fd83f88ec2d452adda5416fc8fc29b6584c19647 Mon Sep 17 00:00:00 2001
From: 2dust <31833384+2dust@users.noreply.github.com>
Date: Mon, 29 Dec 2025 14:45:36 +0800
Subject: [PATCH] =?UTF-8?q?Raised=20minSdk=20to=2024=EF=BC=8CDrop=20legacy?=
=?UTF-8?q?=20Android=20support?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Raised minSdk to 24 and removed conditional code for pre-Nougat Android versions. Cleaned up context wrapping, notification, and service start logic to use modern APIs. Also removed unnecessary @RequiresApi annotations and legacy feature declarations from the manifest.
---
V2rayNG/app/build.gradle.kts | 4 ++--
V2rayNG/app/src/main/AndroidManifest.xml | 10 ++--------
.../java/com/v2ray/ang/dto/V2rayConfig.kt | 6 +++---
.../main/java/com/v2ray/ang/extension/_Ext.kt | 7 -------
.../v2ray/ang/handler/NotificationManager.kt | 13 ++-----------
.../com/v2ray/ang/handler/SpeedtestManager.kt | 14 +++++---------
.../v2ray/ang/handler/V2RayServiceManager.kt | 8 ++------
.../v2ray/ang/handler/V2rayConfigManager.kt | 16 ++++++++--------
.../com/v2ray/ang/receiver/WidgetProvider.kt | 6 +-----
.../com/v2ray/ang/service/QSTileService.kt | 1 -
.../ang/service/V2RayProxyOnlyService.kt | 1 -
.../com/v2ray/ang/service/V2RayVpnService.kt | 1 -
.../java/com/v2ray/ang/ui/BaseActivity.kt | 1 -
.../com/v2ray/ang/util/MyContextWrapper.kt | 19 ++++++++-----------
.../src/main/java/com/v2ray/ang/util/Utils.kt | 6 +-----
15 files changed, 34 insertions(+), 79 deletions(-)
diff --git a/V2rayNG/app/build.gradle.kts b/V2rayNG/app/build.gradle.kts
index e57bd9ee..bd14300d 100644
--- a/V2rayNG/app/build.gradle.kts
+++ b/V2rayNG/app/build.gradle.kts
@@ -10,10 +10,10 @@ android {
defaultConfig {
applicationId = "com.v2ray.ang"
- minSdk = 21
+ minSdk = 24
targetSdk = 36
versionCode = 684
- versionName = "1.10.32"
+ versionName = "1.10.33"
multiDexEnabled = true
val abiFilterList = (properties["ABI_FILTERS"] as? String)?.split(';')
diff --git a/V2rayNG/app/src/main/AndroidManifest.xml b/V2rayNG/app/src/main/AndroidManifest.xml
index bf7a7ede..76890065 100644
--- a/V2rayNG/app/src/main/AndroidManifest.xml
+++ b/V2rayNG/app/src/main/AndroidManifest.xml
@@ -10,10 +10,6 @@
android:smallScreens="true"
android:xlargeScreens="true" />
-
-
@@ -54,8 +50,7 @@
android:networkSecurityConfig="@xml/network_security_config"
android:supportsRtl="true"
android:theme="@style/AppThemeDayNight"
- android:usesCleartextTraffic="true"
- tools:targetApi="m">
+ android:usesCleartextTraffic="true">
+ android:process=":RunSoLibV2RayDaemon">
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt
index e2a42a19..2b3ddbfc 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/dto/V2rayConfig.kt
@@ -469,12 +469,12 @@ data class V2rayConfig(
return null
}
- fun ensureSockopt(): V2rayConfig.OutboundBean.StreamSettingsBean.SockoptBean {
- val stream = streamSettings ?: V2rayConfig.OutboundBean.StreamSettingsBean().also {
+ fun ensureSockopt(): StreamSettingsBean.SockoptBean {
+ val stream = streamSettings ?: StreamSettingsBean().also {
streamSettings = it
}
- val sockopt = stream.sockopt ?: V2rayConfig.OutboundBean.StreamSettingsBean.SockoptBean().also {
+ val sockopt = stream.sockopt ?: StreamSettingsBean.SockoptBean().also {
stream.sockopt = it
}
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt
index 6e5c6bb4..cc7e2f73 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/extension/_Ext.kt
@@ -116,13 +116,6 @@ fun Long.toTrafficString(): String {
return String.format("%.1f %s", size, units[unitIndex])
}
-val URLConnection.responseLength: Long
- get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- contentLengthLong
- } else {
- contentLength.toLong()
- }
-
val URI.idnHost: String
get() = host?.replace("[", "")?.replace("]", "").orEmpty()
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/NotificationManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/NotificationManager.kt
index e8737d7e..92141de5 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/NotificationManager.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/NotificationManager.kt
@@ -15,7 +15,6 @@ import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.dto.ProfileItem
import com.v2ray.ang.extension.toSpeedString
-import com.v2ray.ang.handler.V2RayServiceManager
import com.v2ray.ang.ui.MainActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -90,11 +89,7 @@ object NotificationManager {
*/
fun showNotification(currentConfig: ProfileItem?) {
val service = getService() ?: return
- val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
- } else {
- PendingIntent.FLAG_UPDATE_CURRENT
- }
+ val flags = PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
val startMainIntent = Intent(service, MainActivity::class.java)
val contentPendingIntent = PendingIntent.getActivity(service, NOTIFICATION_PENDING_INTENT_CONTENT, startMainIntent, flags)
@@ -147,11 +142,7 @@ object NotificationManager {
*/
fun cancelNotification() {
val service = getService() ?: return
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- service.stopForeground(Service.STOP_FOREGROUND_REMOVE)
- } else {
- service.stopForeground(true)
- }
+ service.stopForeground(Service.STOP_FOREGROUND_REMOVE)
mBuilder = null
speedNotificationJob?.cancel()
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt
index a79a7ecf..29bbaa6d 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/SpeedtestManager.kt
@@ -7,7 +7,6 @@ import android.util.Log
import com.v2ray.ang.AppConfig
import com.v2ray.ang.R
import com.v2ray.ang.dto.IPAPIInfo
-import com.v2ray.ang.extension.responseLength
import com.v2ray.ang.util.HttpUtil
import com.v2ray.ang.util.JsonUtil
import kotlinx.coroutines.currentCoroutineContext
@@ -143,14 +142,11 @@ object SpeedtestManager {
val code = conn.responseCode
elapsed = SystemClock.elapsedRealtime() - start
- if (code == 204 || code == 200 && conn.responseLength == 0L) {
- result = context.getString(R.string.connection_test_available, elapsed)
- } else {
- throw IOException(
- context.getString(
- R.string.connection_test_error_status_code,
- code
- )
+ result = when (code) {
+ 204 -> context.getString(R.string.connection_test_available, elapsed)
+ 200 if conn.contentLengthLong == 0L -> context.getString(R.string.connection_test_available, elapsed)
+ else -> throw IOException(
+ context.getString(R.string.connection_test_error_status_code, code)
)
}
} catch (e: IOException) {
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt
index 011338c2..edd03898 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2RayServiceManager.kt
@@ -106,7 +106,7 @@ object V2RayServiceManager {
// val result = V2rayConfigUtil.getV2rayConfig(context, guid)
// if (!result.status) return
- if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PROXY_SHARING) == true) {
+ if (MmkvManager.decodeSettingsBool(AppConfig.PREF_PROXY_SHARING)) {
context.toast(R.string.toast_warning_pref_proxysharing_short)
} else {
context.toast(R.string.toast_services_start)
@@ -116,11 +116,7 @@ object V2RayServiceManager {
} else {
Intent(context.applicationContext, V2RayProxyOnlyService::class.java)
}
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N_MR1) {
- context.startForegroundService(intent)
- } else {
- context.startService(intent)
- }
+ ContextCompat.startForegroundService(context, intent)
}
/**
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt
index ff012420..b87c8dfb 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/handler/V2rayConfigManager.kt
@@ -201,7 +201,7 @@ object V2rayConfigManager {
getInbounds(v2rayConfig)
v2rayConfig.outbounds.removeAt(0)
- val outboundsList = mutableListOf()
+ val outboundsList = mutableListOf()
var index = 0
for (config in validConfigs) {
index++
@@ -519,7 +519,7 @@ object V2rayConfigManager {
// DNS outbound
if (v2rayConfig.outbounds.none { e -> e.protocol == "dns" && e.tag == "dns-out" }) {
v2rayConfig.outbounds.add(
- V2rayConfig.OutboundBean(
+ OutboundBean(
protocol = "dns",
tag = "dns-out",
settings = null,
@@ -774,7 +774,7 @@ object V2rayConfigManager {
* @param outbound The outbound connection to update
* @return true if the update was successful, false otherwise
*/
- private fun updateOutboundWithGlobalSettings(outbound: V2rayConfig.OutboundBean): Boolean {
+ private fun updateOutboundWithGlobalSettings(outbound: OutboundBean): Boolean {
try {
var muxEnabled = MmkvManager.decodeSettingsBool(AppConfig.PREF_MUX_ENABLED, false)
val protocol = outbound.protocol
@@ -937,7 +937,7 @@ object V2rayConfigManager {
}
val fragmentOutbound =
- V2rayConfig.OutboundBean(
+ OutboundBean(
protocol = AppConfig.PROTOCOL_FREEDOM,
tag = AppConfig.TAG_FRAGMENT,
mux = null
@@ -955,8 +955,8 @@ object V2rayConfigManager {
packets = "tlshello"
}
- fragmentOutbound.settings = OutboundBean.OutSettingsBean(
- fragment = OutboundBean.OutSettingsBean.FragmentBean(
+ fragmentOutbound.settings = OutSettingsBean(
+ fragment = OutSettingsBean.FragmentBean(
packets = packets,
length = MmkvManager.decodeSettingsString(AppConfig.PREF_FRAGMENT_LENGTH)
?: "50-100",
@@ -964,7 +964,7 @@ object V2rayConfigManager {
?: "10-20"
),
noises = listOf(
- OutboundBean.OutSettingsBean.NoiseBean(
+ OutSettingsBean.NoiseBean(
type = "rand",
packet = "10-20",
delay = "10-16",
@@ -1043,7 +1043,7 @@ object V2rayConfigManager {
* @param profileItem The profile item to convert
* @return OutboundBean configuration for the profile, or null if not supported
*/
- private fun convertProfile2Outbound(profileItem: ProfileItem): V2rayConfig.OutboundBean? {
+ private fun convertProfile2Outbound(profileItem: ProfileItem): OutboundBean? {
return when (profileItem.configType) {
EConfigType.VMESS -> VmessFmt.toOutbound(profileItem)
EConfigType.CUSTOM -> null
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt
index 2004c135..31737449 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/receiver/WidgetProvider.kt
@@ -42,11 +42,7 @@ class WidgetProvider : AppWidgetProvider() {
context,
R.id.layout_switch,
intent,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
- } else {
- PendingIntent.FLAG_UPDATE_CURRENT
- }
+ PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
remoteViews.setOnClickPendingIntent(R.id.layout_switch, pendingIntent)
if (isRunning) {
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt
index 725987fe..28ba8be3 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/QSTileService.kt
@@ -18,7 +18,6 @@ import com.v2ray.ang.util.MessageUtil
import com.v2ray.ang.util.Utils
import java.lang.ref.SoftReference
-@RequiresApi(Build.VERSION_CODES.N)
class QSTileService : TileService() {
/**
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayProxyOnlyService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayProxyOnlyService.kt
index 232549f7..602701bf 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayProxyOnlyService.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayProxyOnlyService.kt
@@ -84,7 +84,6 @@ class V2RayProxyOnlyService : Service(), ServiceControl {
* Attaches the base context to the service.
* @param newBase The new base context.
*/
- @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let {
MyContextWrapper.wrap(newBase, SettingsManager.getLocale())
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt
index 4afb6313..a85d2f79 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/service/V2RayVpnService.kt
@@ -113,7 +113,6 @@ class V2RayVpnService : VpnService(), ServiceControl {
return protect(socket)
}
- @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) {
val context = newBase?.let {
MyContextWrapper.wrap(newBase, SettingsManager.getLocale())
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BaseActivity.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BaseActivity.kt
index 0cd7f647..7283b098 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BaseActivity.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/ui/BaseActivity.kt
@@ -38,7 +38,6 @@ abstract class BaseActivity : AppCompatActivity() {
else -> super.onOptionsItemSelected(item)
}
- @RequiresApi(Build.VERSION_CODES.N)
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(MyContextWrapper.wrap(newBase ?: return, SettingsManager.getLocale()))
}
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/MyContextWrapper.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/MyContextWrapper.kt
index a769368f..16c618f0 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/MyContextWrapper.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/MyContextWrapper.kt
@@ -18,21 +18,18 @@ open class MyContextWrapper(base: Context?) : ContextWrapper(base) {
* @param newLocale The new locale to set.
* @return A ContextWrapper with the new locale.
*/
- @RequiresApi(Build.VERSION_CODES.N)
fun wrap(context: Context, newLocale: Locale?): ContextWrapper {
var mContext = context
val res: Resources = mContext.resources
val configuration: Configuration = res.configuration
- mContext = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- configuration.setLocale(newLocale)
- val localeList = LocaleList(newLocale)
- LocaleList.setDefault(localeList)
- configuration.setLocales(localeList)
- mContext.createConfigurationContext(configuration)
- } else {
- configuration.setLocale(newLocale)
- mContext.createConfigurationContext(configuration)
- }
+
+ val locale = newLocale ?: Locale.getDefault()
+ configuration.setLocale(locale)
+ val localeList = LocaleList(locale)
+ LocaleList.setDefault(localeList)
+ configuration.setLocales(localeList)
+
+ mContext = mContext.createConfigurationContext(configuration)
return ContextWrapper(mContext)
}
}
diff --git a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt
index 0864c09d..dfb28edf 100644
--- a/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt
+++ b/V2rayNG/app/src/main/java/com/v2ray/ang/util/Utils.kt
@@ -437,11 +437,7 @@ object Utils {
*
* @return The system locale.
*/
- fun getSysLocale(): Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- LocaleList.getDefault()[0]
- } else {
- Locale.getDefault()
- }
+ fun getSysLocale(): Locale = LocaleList.getDefault().get(0) ?: Locale.getDefault()
/**
* Fix illegal characters in a URL.