diff --git a/app/src/main/java/com/hippo/ehviewer/Settings.java b/app/src/main/java/com/hippo/ehviewer/Settings.java index ad3248514..1f62052f3 100755 --- a/app/src/main/java/com/hippo/ehviewer/Settings.java +++ b/app/src/main/java/com/hippo/ehviewer/Settings.java @@ -85,6 +85,7 @@ public class Settings { public static final int DEFAULT_READ_CACHE_SIZE = 320; public static final String KEY_BUILT_IN_HOSTS = "built_in_hosts_2"; public static final String KEY_DOMAIN_FRONTING = "domain_fronting"; + public static final String KEY_BYPASS_VPN = "bypass_vpn"; public static final String KEY_LIST_THUMB_SIZE = "list_tile_size"; private static final String KEY_HIDE_HV_EVENTS = "hide_hv_events"; private static final boolean DEFAULT_HIDE_HV_EVENTS = true; @@ -179,6 +180,7 @@ public class Settings { private static final boolean DEFAULT_SAVE_CRASH_LOG = true; private static final boolean DEFAULT_BUILT_IN_HOSTS = false; private static final boolean DEFAULT_FRONTING = false; + private static final boolean DEFAULT_BYPASS_VPN = true; private static final String KEY_PROXY_TYPE = "proxy_type"; private static final int DEFAULT_PROXY_TYPE = EhProxySelector.TYPE_SYSTEM; private static final String KEY_PROXY_IP = "proxy_ip"; @@ -673,6 +675,10 @@ public class Settings { putBoolean(KEY_DOMAIN_FRONTING, value); } + public static boolean getBypassVPN() { + return getBoolean(KEY_BYPASS_VPN, DEFAULT_BYPASS_VPN); + } + public static int getProxyType() { return getInt(KEY_PROXY_TYPE, DEFAULT_PROXY_TYPE); } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt index a7b2569ac..d6d7c9053 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.kt @@ -24,15 +24,20 @@ import android.content.pm.verify.domain.DomainVerificationManager import android.content.pm.verify.domain.DomainVerificationUserState import android.graphics.Bitmap import android.net.ConnectivityManager +import android.net.Network +import android.net.NetworkCapabilities +import android.net.NetworkRequest import android.net.Uri import android.os.Build import android.os.Bundle import android.text.TextUtils +import android.util.Log import android.view.View import android.widget.Toast import androidx.activity.OnBackPressedCallback import androidx.annotation.RequiresApi import androidx.annotation.StringRes +import androidx.core.content.getSystemService import androidx.core.view.GravityCompat import androidx.customview.widget.Openable import androidx.drawerlayout.widget.DrawerLayout @@ -83,6 +88,8 @@ import java.io.OutputStream class MainActivity : EhActivity() { private lateinit var binding: ActivityMainBinding private lateinit var navController: NavController + private lateinit var connectivityManager: ConnectivityManager + private val availableNetworks: MutableList = mutableListOf() private fun saveImageToTempFile(file: UniFile?): File? { file ?: return null @@ -217,6 +224,10 @@ class MainActivity : EhActivity() { } override fun onCreate(savedInstanceState: Bundle?) { + connectivityManager = getSystemService()!! + if (Settings.getDF() && Settings.getBypassVPN()) { + bypassVPN() + } if (EhUtils.needSignedIn()) startActivity(Intent(this, LoginActivity::class.java)) super.onCreate(savedInstanceState) @@ -276,6 +287,19 @@ class MainActivity : EhActivity() { } } + private fun bypassVPN() { + val network = connectivityManager.activeNetwork + val capabilities = connectivityManager.getNetworkCapabilities(network) + capabilities?.let { + if (it.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) { + val builder = NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) + connectivityManager.registerNetworkCallback(builder.build(), mNetworkCallback) + } + } + } + @RequiresApi(Build.VERSION_CODES.S) @Throws(PackageManager.NameNotFoundException::class) private fun checkAppLinkVerify() { @@ -334,8 +358,7 @@ class MainActivity : EhActivity() { } private fun checkMeteredNetwork() { - val cm = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager - if (cm.isActiveNetworkMetered) { + if (connectivityManager.isActiveNetworkMetered) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Snackbar.make( binding.drawView, @@ -503,4 +526,25 @@ class MainActivity : EhActivity() { override fun onDrawerClosed(drawerView: View) {} override fun onDrawerStateChanged(newState: Int) {} } + + private val mNetworkCallback = object : ConnectivityManager.NetworkCallback() { + private val TAG = "mNetworkCallback" + + override fun onAvailable(network: Network) { + Log.d(TAG, "onAvailable: $network") + connectivityManager.bindProcessToNetwork(network) + availableNetworks.add(network) + } + + override fun onLost(network: Network) { + Log.d(TAG, "onLost: $network") + val activeNetwork = availableNetworks.last() + availableNetworks.remove(network) + if (network == activeNetwork) { + connectivityManager.bindProcessToNetwork( + availableNetworks.takeIf { it.isNotEmpty() }?.last() + ) + } + } + } } \ No newline at end of file diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 9e9249a5f..7c9f9363e 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -392,6 +392,10 @@ 应用提供的主机到IP的映射\n可被自定义 hosts.txt 覆盖 自定义 hosts.txt 将主机名称映射到相应的IP地址\n可覆盖内置 hosts.txt + 域名前置(重启应用后生效) + 绕过 SNI 封锁\n启用时会禁用代理设置 + 绕过VPN + 启用域名前置时尝试绕过VPN 导出数据 保存数据至外置存储器,例如下载列表,快速搜索列表 已导出数据至 %s @@ -499,8 +503,6 @@ 从剪贴板导入 未在剪贴板中发现 Cookies。 从搜索记录中删除“%s”? - 域名前置(重启应用后生效) - 绕过 SNI 封锁\n启用时会禁用代理 添加标签 添加新标签,用逗号「,」分割 %s (上传者) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 60afa0324..437f9ca76 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -436,6 +436,8 @@ Apply the built-in host-to-IP mapping provided by the app.\nIt can be overridden by custom hosts.txt. Domain fronting Bypass SNI blocking. + Bypass VPN + Try to bypass VPN when domain fronting is enabled Custom hosts.txt Map hostnames to IP addresses.\nIt can override built-in hosts.txt. Export data diff --git a/app/src/main/res/xml/advanced_settings.xml b/app/src/main/res/xml/advanced_settings.xml index 4c7592a8d..6170b9b48 100644 --- a/app/src/main/res/xml/advanced_settings.xml +++ b/app/src/main/res/xml/advanced_settings.xml @@ -43,8 +43,8 @@ android:title="@string/settings_advanced_read_cache_size" app:entries="@array/read_cache_size_entries" app:entryValues="@array/read_cache_size_entry_values" - app:useSimpleSummaryProvider="true" - app:iconSpaceReserved="false" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + app:iconSpaceReserved="false" + app:useSimpleSummaryProvider="true" /> + +