diff --git a/V2rayNG/app/build.gradle b/V2rayNG/app/build.gradle index 00cc729b..733784a0 100644 --- a/V2rayNG/app/build.gradle +++ b/V2rayNG/app/build.gradle @@ -17,8 +17,8 @@ android { minSdkVersion 21 targetSdkVersion Integer.parseInt("$targetSdkVer") multiDexEnabled true - versionCode 523 - versionName "1.8.9" + versionCode 526 + versionName "1.8.10" } buildTypes { diff --git a/V2rayNG/app/src/main/AndroidManifest.xml b/V2rayNG/app/src/main/AndroidManifest.xml index bdec513e..24d7d2bd 100644 --- a/V2rayNG/app/src/main/AndroidManifest.xml +++ b/V2rayNG/app/src/main/AndroidManifest.xml @@ -50,7 +50,7 @@ - + diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt index 8a3be9e0..2012818a 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/AppConfig.kt @@ -94,7 +94,7 @@ object AppConfig { // subscription settings const val SUBSCRIPTION_AUTO_UPDATE = "pref_auto_update_subscription" const val SUBSCRIPTION_AUTO_UPDATE_INTERVAL = "pref_auto_update_interval" - const val DEFAULT_UPDATE_INTERVAL = "1440" // 24 hours - const val UPDATE_TASK_NAME = "subscription-updater" + const val SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL = "1440" // 24 hours + const val SUBSCRIPTION_UPDATE_TASK_NAME = "subscription_updater" } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt index 4eeaaa7e..acbe0040 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/service/SubscriptionUpdater.kt @@ -1,29 +1,24 @@ package com.v2ray.ang.service -import android.Manifest import android.annotation.SuppressLint import android.app.NotificationChannel import android.app.NotificationManager import android.content.Context -import android.content.pm.PackageManager import android.os.Build import android.util.Log -import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.work.CoroutineWorker import androidx.work.WorkerParameters import com.v2ray.ang.AppConfig import com.v2ray.ang.R -import com.v2ray.ang.extension.toast import com.v2ray.ang.util.AngConfigManager import com.v2ray.ang.util.MmkvManager import com.v2ray.ang.util.Utils -import kotlinx.coroutines.delay object SubscriptionUpdater { - const val notificationChannel = "update-subscription-channel" + const val notificationChannel = "subscription_update_channel" class UpdateTask(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) { @@ -31,23 +26,20 @@ object SubscriptionUpdater { private val notificationManager = NotificationManagerCompat.from(applicationContext) private val notification = NotificationCompat.Builder(applicationContext, notificationChannel) - .setWhen(0) .setTicker("Update") - .setContentTitle("Subscription Update") + .setContentTitle(context.getString(R.string.title_pref_auto_update_subscription)) .setSmallIcon(R.drawable.ic_stat_name) .setCategory(NotificationCompat.CATEGORY_SERVICE) - .setPriority(NotificationCompat.PRIORITY_MIN) + .setPriority(NotificationCompat.PRIORITY_DEFAULT) @SuppressLint("MissingPermission") override suspend fun doWork(): Result { - Log.d(AppConfig.ANG_PACKAGE, "start updating subscriptions") - + Log.d(AppConfig.ANG_PACKAGE, "subscription automatic update starting") val subs = MmkvManager.decodeSubscriptions().filter { it.second.autoUpdate } for (i in subs) { - val subscription = i.second if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { @@ -61,7 +53,10 @@ object SubscriptionUpdater { notificationManager.createNotificationChannel(channel) } notificationManager.notify(3, notification.build()) - Log.d(AppConfig.ANG_PACKAGE, "update: ${subscription.remarks} subscription") + Log.d( + AppConfig.ANG_PACKAGE, + "subscription automatic update: ---${subscription.remarks}" + ) val configs = Utils.getUrlContentWithCustomUserAgent(subscription.url) importBatchConfig(configs, i.first) notification.setContentText("Updating ${subscription.remarks}") @@ -72,10 +67,9 @@ object SubscriptionUpdater { } fun importBatchConfig(server: String?, subid: String = "") { + val append = subid.isEmpty() - val append = subid.isNullOrEmpty() - - var count = AngConfigManager.importBatchConfig(server, subid, append) + val count = AngConfigManager.importBatchConfig(server, subid, append) if (count <= 0) { AngConfigManager.importBatchConfig(Utils.decode(server!!), subid, append) } diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt index 86e648fe..9891568c 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/MainRecyclerAdapter.kt @@ -96,7 +96,8 @@ class MainRecyclerAdapter(val activity: MainActivity) : RecyclerView.Adapter diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt index e2420ce3..c93fae00 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/ui/SettingsActivity.kt @@ -14,13 +14,10 @@ import androidx.work.multiprocess.RemoteWorkManager import com.v2ray.ang.AngApplication import com.v2ray.ang.AppConfig import com.v2ray.ang.R -import com.v2ray.ang.dto.AngConfig import com.v2ray.ang.service.SubscriptionUpdater import com.v2ray.ang.util.Utils import com.v2ray.ang.viewmodel.SettingsViewModel -import java.sql.Time import java.util.concurrent.TimeUnit -import kotlin.time.toDuration class SettingsActivity : BaseActivity() { private val settingsViewModel: SettingsViewModel by viewModels() @@ -81,9 +78,9 @@ class SettingsActivity : BaseActivity() { autoUpdateInterval?.setOnPreferenceChangeListener { _, any -> val nval = any as String autoUpdateInterval?.summary = - if (TextUtils.isEmpty(nval) or (nval.toLong() < 15)) AppConfig.DEFAULT_UPDATE_INTERVAL else nval + if (TextUtils.isEmpty(nval) or (nval.toLong() < 1)) AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL else nval configureUpdateTask(nval.toLong()) - false + true } // licenses.onClick { @@ -180,7 +177,8 @@ class SettingsActivity : BaseActivity() { httpPort?.summary = defaultSharedPreferences.getString(AppConfig.PREF_HTTP_PORT, AppConfig.PORT_HTTP) updateMux(defaultSharedPreferences.getBoolean(AppConfig.PREF_MUX_ENABLED, false)) muxXudpConcurrency?.summary = defaultSharedPreferences.getString(AppConfig.PREF_MUX_XUDP_CONCURRENCY, "8") - autoUpdateInterval?.summary = defaultSharedPreferences.getString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.DEFAULT_UPDATE_INTERVAL) + autoUpdateInterval?.summary = defaultSharedPreferences.getString(AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL,AppConfig.SUBSCRIPTION_DEFAULT_UPDATE_INTERVAL) + autoUpdateInterval?.isEnabled = defaultSharedPreferences.getBoolean(AppConfig.SUBSCRIPTION_AUTO_UPDATE, false) if (TextUtils.isEmpty(remoteDnsString)) { remoteDnsString = AppConfig.DNS_AGENT @@ -233,9 +231,9 @@ class SettingsActivity : BaseActivity() { private fun configureUpdateTask(interval: Long) { val rw = RemoteWorkManager.getInstance(AngApplication.application) - rw.cancelUniqueWork(AppConfig.UPDATE_TASK_NAME) + rw.cancelUniqueWork(AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME) rw.enqueueUniquePeriodicWork( - AppConfig.UPDATE_TASK_NAME, + AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME, ExistingPeriodicWorkPolicy.UPDATE, PeriodicWorkRequest.Builder( SubscriptionUpdater.UpdateTask::class.java, @@ -245,17 +243,14 @@ class SettingsActivity : BaseActivity() { .apply { setInitialDelay(interval, TimeUnit.MINUTES) } - .setConstraints( - Constraints( - NetworkType.CONNECTED, - ) - ).build() + .build() ) } private fun cancelUpdateTask() { val rw = RemoteWorkManager.getInstance(AngApplication.application) - rw.cancelUniqueWork(AppConfig.UPDATE_TASK_NAME) + rw.cancelUniqueWork(AppConfig.SUBSCRIPTION_UPDATE_TASK_NAME) + } private fun updateMux(enabled: Boolean) { val defaultSharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity()) diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt index b8cf2f54..4e0df222 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/util/V2rayConfigUtil.kt @@ -401,17 +401,35 @@ object V2rayConfigUtil { private fun updateOutboundWithGlobalSettings(outbound: V2rayConfig.OutboundBean): Boolean { try { - if (settingsStorage?.decodeBool(AppConfig.PREF_MUX_ENABLED) == true) { + var muxEnabled = settingsStorage?.decodeBool(AppConfig.PREF_MUX_ENABLED, false) + + val protocol = outbound.protocol + if (protocol.equals(EConfigType.SHADOWSOCKS.name, true) + || protocol.equals(EConfigType.SOCKS.name, true) + || protocol.equals(EConfigType.TROJAN.name, true) + ) { + muxEnabled = false + } else if (protocol.equals(EConfigType.VLESS.name, true) + && outbound.settings?.vnext?.get(0)?.users?.get(0)?.flow?.isNotEmpty() == true + ) { + muxEnabled = false + } + + if (muxEnabled == true) { outbound.mux?.enabled = true outbound.mux?.concurrency = 8 - outbound.mux?.xudpConcurrency = settingsStorage?.decodeInt(AppConfig.PREF_MUX_XUDP_CONCURRENCY) ?: 8 - outbound.mux?.xudpProxyUDP443 = settingsStorage?.decodeString(AppConfig.PREF_MUX_XUDP_QUIC) ?: "reject" + outbound.mux?.xudpConcurrency = + settingsStorage?.decodeInt(AppConfig.PREF_MUX_XUDP_CONCURRENCY) ?: 8 + outbound.mux?.xudpProxyUDP443 = + settingsStorage?.decodeString(AppConfig.PREF_MUX_XUDP_QUIC) ?: "reject" } else { outbound.mux?.enabled = false + outbound.mux?.concurrency = -1 } if (outbound.streamSettings?.network == DEFAULT_NETWORK - && outbound.streamSettings?.tcpSettings?.header?.type == HTTP) { + && outbound.streamSettings?.tcpSettings?.header?.type == HTTP + ) { val path = outbound.streamSettings?.tcpSettings?.header?.request?.path val host = outbound.streamSettings?.tcpSettings?.header?.request?.headers?.Host diff --git a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt index 0d34c0bb..4fa407e8 100644 --- a/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt +++ b/V2rayNG/app/src/main/kotlin/com/v2ray/ang/viewmodel/SettingsViewModel.kt @@ -40,6 +40,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_V2RAY_ROUTING_AGENT, AppConfig.PREF_V2RAY_ROUTING_BLOCKED, AppConfig.PREF_V2RAY_ROUTING_DIRECT, + AppConfig.SUBSCRIPTION_AUTO_UPDATE_INTERVAL, AppConfig.PREF_MUX_XUDP_QUIC, -> { settingsStorage?.encode(key, sharedPreferences.getString(key, "")) } @@ -53,6 +54,7 @@ class SettingsViewModel(application: Application) : AndroidViewModel(application AppConfig.PREF_BYPASS_APPS, AppConfig.PREF_CONFIRM_REMOVE, AppConfig.PREF_START_SCAN_IMMEDIATE, + AppConfig.SUBSCRIPTION_AUTO_UPDATE, AppConfig.PREF_MUX_ENABLED, -> { settingsStorage?.encode(key, sharedPreferences.getBoolean(key, false)) } diff --git a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml index d61169cf..1bf37ac7 100644 --- a/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml +++ b/V2rayNG/app/src/main/res/layout/activity_sub_edit.xml @@ -69,6 +69,28 @@ + + + + + + + + + - - - - - - - - diff --git a/V2rayNG/app/src/main/res/layout/item_recycler_main.xml b/V2rayNG/app/src/main/res/layout/item_recycler_main.xml index 2dc83fb9..b2fbd63d 100644 --- a/V2rayNG/app/src/main/res/layout/item_recycler_main.xml +++ b/V2rayNG/app/src/main/res/layout/item_recycler_main.xml @@ -41,7 +41,12 @@ android:orientation="vertical" android:paddingStart="9dp"> - + + - + + android:textAppearance="@style/TextAppearance.AppCompat.Small" + android:textSize="12sp"/> diff --git a/V2rayNG/app/src/main/res/values-ru/strings.xml b/V2rayNG/app/src/main/res/values-ru/strings.xml index efc771cf..4989238b 100644 --- a/V2rayNG/app/src/main/res/values-ru/strings.xml +++ b/V2rayNG/app/src/main/res/values-ru/strings.xml @@ -32,7 +32,7 @@ Ручной ввод профиля Trojan Пользовательский профиль Импорт из буфера обмена - Импорт с устройства + Импорт из файла Импорт из URL Импорт сканированием URL Подтверждаете удаление? @@ -103,12 +103,12 @@ Основной: выделенное приложение соединяется через прокси, не выделенное — напрямую; \n\nРежим обхода: выделенное приложение соединяется напрямую, не выделенное — через прокси.\n\nЕсть возможность автоматического выбора проксируемых приложений в меню. Использовать мультиплексирование - Быстрее, но это может привести к нестабильному соединению\nМультиплексор TCP-трафика с 8 соединениями по умолчанию, ниже можно настроить обработку UDP и QUIC. + Быстрее, но это может привести к нестабильному соединению.\nМультиплексирование TCP-трафика с 8 соединениями по умолчанию, ниже можно настроить обработку UDP и QUIC. XUDP-соединения (диапазон от -1 до 1024) - Обработка QUIC в мультиплексорном туннеле + Обработка QUIC в мультиплексном туннеле отклонять - допустимый + разрешать пропускать @@ -170,6 +170,10 @@ Содействие Содействие, нажмите для получения подробной информации (пожертвование может быть удалено) + Автоматическое обновление подписок + Автоматическое обновление подписок в фоновом режиме с указанным интервалом. В зависимости от устройства эта функция может работать не всегда. + Интервал автообновления (мин.) + Подробность ведения журнала Режим Нажмите для получения дополнительной информации @@ -182,12 +186,13 @@ Перезапуск службы Удалить все профили Удалить дубликаты профилей - Удалить сбойные профили (после проверки) + Удалить нерабочие профили (после проверки) Экспорт всех профилей в буфер обмена Группы примечания URL (необязательно) - использовать обновление + Использовать обновление + Использовать автоматическое обновление Обновить подписку Проверка доступности профилей Время отклика профилей @@ -206,7 +211,7 @@ Очистить Сканировать и заменить Сканировать и добавить - Правила по умолчанию + Правила по умолчанию Проверить подключение Проверка… @@ -217,6 +222,9 @@ Подключено, нажмите для проверки Не подключено + Подписка импортирована + Невозможно импортировать подписку + QR-код Экспорт в буфер обмена @@ -246,7 +254,5 @@ VPN Только прокси - Подписка импортирована - Подписка не импортирована diff --git a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml index 346ea0b6..45879449 100644 --- a/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rCN/strings.xml @@ -97,7 +97,7 @@ 常规:勾选的App被代理,未勾选的直连;\n绕行模式:勾选的App直连,未勾选的被代理.\n不明白者在菜单中选择自动选中需代理应用 启用 Mux 多路复用 - 减低延时 但可能会断流\nTCP 默认复用 8 个子链接,UDP 及 QUIC 流量处理方式下方可选 + 减低延时,但可能会断流,建议不要启用。\nTCP 默认复用 8 个子链接,UDP 及 QUIC 流量处理方式下方可选。 XUDP 复用子链接数(可填 -1 至 1024) QUIC 流量处理方式 @@ -164,6 +164,10 @@ 推广 一些推广,点击查看详情(捐赠可去除) + 自动更新订阅 + 在后台按一定时间间隔自动更新您的订阅。受设备影响,此功能不一定总是有效 + 订阅自动更新间隔(分钟) + 日志级别 模式 点此查看更多帮助 @@ -182,6 +186,7 @@ 备注 可选地址(url) 启用更新 + 启用自动更新 更新订阅 测试全部配置Tcping 测试全部配置真连接 diff --git a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml index d2ff9e90..2fbd228a 100644 --- a/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml +++ b/V2rayNG/app/src/main/res/values-zh-rTW/strings.xml @@ -164,6 +164,10 @@ 推廣 一些推廣,輕觸以檢視 (捐贈可去除) + 自動更新訂閱 + 在後台以一定時間間隔自動更新您的訂閱。受設備影響,此功能不一定總是有效 + 訂閱自動更新間隔(分鐘) + 記錄層級 模式 輕觸以檢視說明 @@ -182,6 +186,7 @@ 備註 Optional URL 啟用更新 + 啟用自動更新 更新訂閱 偵測所有組態 Tcping 偵測所有組態真延遲 diff --git a/V2rayNG/app/src/main/res/values/strings.xml b/V2rayNG/app/src/main/res/values/strings.xml index 6214b267..a27d1398 100644 --- a/V2rayNG/app/src/main/res/values/strings.xml +++ b/V2rayNG/app/src/main/res/values/strings.xml @@ -172,6 +172,10 @@ Promotion Promotion,click for details(Donation can be removed) + Automatic update subscriptions + Update your subscriptions automatically with an interval in background. Depending on the device, this feature may not always work + Subscription Auto Update Interval (Minutes) + Log Level Mode Click me for more help @@ -189,8 +193,8 @@ Subscription group setting remarks Optional URL - enable update - Auto update + Enable update + Enable automatic update Update subscription Tcping all configuration Real delay all configuration diff --git a/V2rayNG/app/src/main/res/xml/pref_settings.xml b/V2rayNG/app/src/main/res/xml/pref_settings.xml index a14314d5..21c1751d 100644 --- a/V2rayNG/app/src/main/res/xml/pref_settings.xml +++ b/V2rayNG/app/src/main/res/xml/pref_settings.xml @@ -2,10 +2,10 @@ + android:defaultValue="true" + android:key="pref_sniffing_enabled" + android:summary="@string/summary_pref_sniffing_enabled" + android:title="@string/title_pref_sniffing_enabled" /> + android:key="pref_local_dns_enabled" + android:summary="@string/summary_pref_local_dns_enabled" + android:title="@string/title_pref_local_dns_enabled" /> + android:key="pref_fake_dns_enabled" + android:summary="@string/summary_pref_fake_dns_enabled" + android:title="@string/title_pref_fake_dns_enabled" /> + android:key="pref_local_dns_port" + android:summary="10853" + android:inputType="number" + android:title="@string/title_pref_local_dns_port" /> + android:key="pref_vpn_dns" + android:summary="@string/summary_pref_remote_dns" + android:title="@string/title_pref_vpn_dns" /> @@ -78,6 +78,18 @@ + + + + + + android:key="pref_domestic_dns" + android:summary="@string/summary_pref_domestic_dns" + android:title="@string/title_pref_domestic_dns" /> - - - - - - - - - - - - - - - - - - + android:title="@string/title_mode" /> - - + \ No newline at end of file