Raised minSdk to 24,Drop legacy Android support

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.
This commit is contained in:
2dust
2025-12-29 14:45:36 +08:00
parent 214ab76459
commit fd83f88ec2
15 changed files with 34 additions and 79 deletions
+2 -2
View File
@@ -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(';')
+2 -8
View File
@@ -10,10 +10,6 @@
android:smallScreens="true"
android:xlargeScreens="true" />
<uses-sdk
android:minSdkVersion="21"
tools:overrideLibrary="com.blacksquircle.ui.editorkit" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
@@ -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">
<activity
android:name=".ui.MainActivity"
@@ -216,8 +211,7 @@
android:icon="@drawable/ic_stat_name"
android:label="@string/app_tile_name"
android:permission="android.permission.BIND_QUICK_SETTINGS_TILE"
android:process=":RunSoLibV2RayDaemon"
tools:targetApi="24">
android:process=":RunSoLibV2RayDaemon">
<intent-filter>
<action android:name="android.service.quicksettings.action.QS_TILE" />
</intent-filter>
@@ -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
}
@@ -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()
@@ -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()
@@ -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) {
@@ -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)
}
/**
@@ -201,7 +201,7 @@ object V2rayConfigManager {
getInbounds(v2rayConfig)
v2rayConfig.outbounds.removeAt(0)
val outboundsList = mutableListOf<V2rayConfig.OutboundBean>()
val outboundsList = mutableListOf<OutboundBean>()
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
@@ -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) {
@@ -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() {
/**
@@ -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())
@@ -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())
@@ -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()))
}
@@ -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)
}
}
@@ -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.