Merge remote-tracking branch 'origin/master'

This commit is contained in:
kunfei
2023-06-15 12:34:07 +08:00
13 changed files with 204 additions and 44 deletions
@@ -31,6 +31,16 @@ interface BookSourceDao {
) )
fun flowSearch(searchKey: String): Flow<List<BookSourcePart>> fun flowSearch(searchKey: String): Flow<List<BookSourcePart>>
@Query(
"""select * from book_sources
where bookSourceName like '%' || :searchKey || '%'
or bookSourceGroup like '%' || :searchKey || '%'
or bookSourceUrl like '%' || :searchKey || '%'
or bookSourceComment like '%' || :searchKey || '%'
order by customOrder asc"""
)
fun search(searchKey: String): List<BookSource>
@Query( @Query(
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore, """select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
@@ -56,27 +66,45 @@ interface BookSourceDao {
) )
fun flowGroupSearch(searchKey: String): Flow<List<BookSourcePart>> fun flowGroupSearch(searchKey: String): Flow<List<BookSourcePart>>
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore, @Query(
"""select * from book_sources
where bookSourceGroup = :searchKey
or bookSourceGroup like :searchKey || ',%'
or bookSourceGroup like '%,' || :searchKey
or bookSourceGroup like '%,' || :searchKey || ',%'
order by customOrder asc"""
)
fun groupSearch(searchKey: String): List<BookSource>
@Query(
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
from book_sources where enabled = 1 order by customOrder asc""") from book_sources where enabled = 1 order by customOrder asc"""
)
fun flowEnabled(): Flow<List<BookSourcePart>> fun flowEnabled(): Flow<List<BookSourcePart>>
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore, @Query(
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
from book_sources where enabled = 0 order by customOrder asc""") from book_sources where enabled = 0 order by customOrder asc"""
)
fun flowDisabled(): Flow<List<BookSourcePart>> fun flowDisabled(): Flow<List<BookSourcePart>>
@Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc") @Query("select * from book_sources where enabledExplore = 1 and trim(exploreUrl) <> '' order by customOrder asc")
fun flowExplore(): Flow<List<BookSource>> fun flowExplore(): Flow<List<BookSource>>
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore, @Query(
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
from book_sources where loginUrl is not null and loginUrl != ''""") from book_sources where loginUrl is not null and loginUrl != ''"""
)
fun flowLogin(): Flow<List<BookSourcePart>> fun flowLogin(): Flow<List<BookSourcePart>>
@Query("""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore, @Query(
"""select bookSourceUrl, bookSourceName, bookSourceGroup, customOrder, enabled, enabledExplore,
trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl trim(loginUrl) <> '' hasLoginUrl, lastUpdateTime, respondTime, weight, trim(exploreUrl) <> '' hasExploreUrl
from book_sources where bookSourceGroup is null or bookSourceGroup = '' or bookSourceGroup like '%未分组%'""") from book_sources where bookSourceGroup is null or bookSourceGroup = '' or bookSourceGroup like '%未分组%'"""
)
fun flowNoGroup(): Flow<List<BookSourcePart>> fun flowNoGroup(): Flow<List<BookSourcePart>>
@Query( @Query(
@@ -147,6 +175,15 @@ interface BookSourceDao {
@get:Query("select * from book_sources where enabled = 1 order by customOrder") @get:Query("select * from book_sources where enabled = 1 order by customOrder")
val allEnabled: List<BookSource> val allEnabled: List<BookSource>
@get:Query("select * from book_sources where enabled = 0 order by customOrder")
val allDisabled: List<BookSource>
@get:Query("select * from book_sources where bookSourceGroup is null or bookSourceGroup = '' or bookSourceGroup like '%未分组%'")
val allNoGroup: List<BookSource>
@get:Query("select * from book_sources where loginUrl is not null and loginUrl != ''")
val allLogin: List<BookSource>
@get:Query("select * from book_sources where enabled = 1 and bookSourceType = 0 order by customOrder") @get:Query("select * from book_sources where enabled = 1 and bookSourceType = 0 order by customOrder")
val allTextEnabled: List<BookSource> val allTextEnabled: List<BookSource>
@@ -108,7 +108,7 @@ class ContentProcessor private constructor(
if (matcher.find()) { if (matcher.find()) {
mContent = mContent.substring(matcher.end()) mContent = mContent.substring(matcher.end())
sameTitleRemoved = true sameTitleRemoved = true
} else if (useReplace) { } else if (useReplace && book.getUseReplaceRule()) {
title = Pattern.quote( title = Pattern.quote(
chapter.getDisplayTitle( chapter.getDisplayTitle(
contentReplaceRules, contentReplaceRules,
@@ -174,12 +174,13 @@ open class WebDav(
val baseUrl = NetworkUtils.getBaseUrl(urlStr) val baseUrl = NetworkUtils.getBaseUrl(urlStr)
for (element in elements) { for (element in elements) {
//依然是优化支持 caddy 自建的 WebDav ,其目录后缀都为“/”, 所以删除“/”的判定,不然无法获取该目录项 //依然是优化支持 caddy 自建的 WebDav ,其目录后缀都为“/”, 所以删除“/”的判定,不然无法获取该目录项
val href = URLDecoder.decode(element.findNS("href", ns)[0].text(), "UTF-8") val href = element.findNS("href", ns)[0].text().replace("+", "%20")
val hrefDecode = URLDecoder.decode(href, "UTF-8")
.removeSuffix("/") .removeSuffix("/")
val fileName = href.substringAfterLast("/") val fileName = hrefDecode.substringAfterLast("/")
val webDavFile: WebDav val webDavFile: WebDav
try { try {
val urlName = href.ifEmpty { val urlName = hrefDecode.ifEmpty {
url.file.replace("/", "") url.file.replace("/", "")
} }
val contentType = element val contentType = element
@@ -199,7 +200,7 @@ open class WebDav(
.toInstant(ZoneOffset.of("+8")).toEpochMilli() .toInstant(ZoneOffset.of("+8")).toEpochMilli()
} }
}.getOrNull() ?: 0 }.getOrNull() ?: 0
val fullURL = NetworkUtils.getAbsoluteURL(baseUrl, href) val fullURL = NetworkUtils.getAbsoluteURL(baseUrl, hrefDecode)
webDavFile = WebDavFile( webDavFile = WebDavFile(
fullURL, fullURL,
authorization, authorization,
@@ -13,10 +13,10 @@ class WebDavFile(
val contentType: String, val contentType: String,
val resourceType: String, val resourceType: String,
val lastModify: Long val lastModify: Long
) : WebDav(urlStr, authorization) { ) : WebDav(urlStr, authorization) {
val isDir by lazy { val isDir by lazy {
contentType == "httpd/unix-directory" || resourceType.lowercase().contains("collection") contentType == "httpd/unix-directory" || resourceType.lowercase().contains("collection")
} }
} }
@@ -272,7 +272,7 @@ class AnalyzeRule(
} }
if (result == null) result = "" if (result == null) result = ""
val str = if (unescape) { val str = if (unescape) {
StringEscapeUtils.unescapeHtml3(result.toString()) StringEscapeUtils.unescapeHtml4(result.toString())
} else result.toString() } else result.toString()
if (isUrl) { if (isUrl) {
return if (str.isBlank()) { return if (str.isBlank()) {
@@ -134,7 +134,7 @@ object LocalBook {
} }
if (book.isEpub) { if (book.isEpub) {
content = content?.replace("&lt;img", "&lt; img", true) ?: return null content = content?.replace("&lt;img", "&lt; img", true) ?: return null
return StringEscapeUtils.unescapeHtml3(content) return StringEscapeUtils.unescapeHtml4(content)
} }
return content return content
} }
@@ -40,7 +40,9 @@ class RemoteBookWebDav(
val remoteWebDavFileList: List<WebDavFile> = WebDav(path, authorization).listFiles() val remoteWebDavFileList: List<WebDavFile> = WebDav(path, authorization).listFiles()
//转化远程文件信息到本地对象 //转化远程文件信息到本地对象
remoteWebDavFileList.forEach { webDavFile -> remoteWebDavFileList.forEach { webDavFile ->
if (webDavFile.isDir || bookFileRegex.matches(webDavFile.displayName) || archiveFileRegex.matches(webDavFile.displayName) if (webDavFile.isDir
|| bookFileRegex.matches(webDavFile.displayName)
|| archiveFileRegex.matches(webDavFile.displayName)
) { ) {
//扩展名符合阅读的格式则认为是书籍 //扩展名符合阅读的格式则认为是书籍
remoteBooks.add(RemoteBook(webDavFile)) remoteBooks.add(RemoteBook(webDavFile))
@@ -70,7 +72,7 @@ class RemoteBookWebDav(
if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用") if (!NetworkUtils.isAvailable()) throw NoStackTraceException("网络不可用")
val localBookUri = Uri.parse(book.bookUrl) val localBookUri = Uri.parse(book.bookUrl)
val putUrl = "$rootBookUrl${File.separator}${book.originName}" val putUrl = "$rootBookUrl${File.separator}${book.originName}"
val webDav = WebDav(putUrl, authorization) val webDav = WebDav(putUrl, authorization)
if (localBookUri.isContentScheme()) { if (localBookUri.isContentScheme()) {
webDav.upload( webDav.upload(
byteArray = localBookUri.readBytes(appCtx), byteArray = localBookUri.readBytes(appCtx),
@@ -80,8 +82,8 @@ class RemoteBookWebDav(
webDav.upload(localBookUri.path!!) webDav.upload(localBookUri.path!!)
} }
book.origin = BookType.webDavTag + CustomUrl(putUrl) book.origin = BookType.webDavTag + CustomUrl(putUrl)
.putAttribute("serverID", serverID) .putAttribute("serverID", serverID)
.toString() .toString()
book.save() book.save()
} }
@@ -18,6 +18,7 @@ import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.async import kotlinx.coroutines.async
import kotlinx.coroutines.ensureActive import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.apache.commons.text.StringEscapeUtils
import splitties.init.appCtx import splitties.init.appCtx
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
@@ -168,6 +169,7 @@ object BookContent {
//获取正文 //获取正文
var content = analyzeRule.getString(contentRule.content, unescape = false) var content = analyzeRule.getString(contentRule.content, unescape = false)
content = HtmlFormatter.formatKeepImg(content, rUrl) content = HtmlFormatter.formatKeepImg(content, rUrl)
content = StringEscapeUtils.unescapeHtml4(content)
//获取下一页链接 //获取下一页链接
if (getNextPageUrl) { if (getNextPageUrl) {
val nextUrlRule = contentRule.nextContentUrl val nextUrlRule = contentRule.nextContentUrl
@@ -17,7 +17,6 @@ import io.legado.app.constant.AppLog
import io.legado.app.constant.EventBus import io.legado.app.constant.EventBus
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSourcePart import io.legado.app.data.entities.BookSourcePart
import io.legado.app.data.entities.toBookSource
import io.legado.app.databinding.ActivityBookSourceBinding import io.legado.app.databinding.ActivityBookSourceBinding
import io.legado.app.databinding.DialogEditTextBinding import io.legado.app.databinding.DialogEditTextBinding
import io.legado.app.help.DirectLinkUpload import io.legado.app.help.DirectLinkUpload
@@ -71,6 +70,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private var sortAscending = true private var sortAscending = true
private var snackBar: Snackbar? = null private var snackBar: Snackbar? = null
private var isPaused = false private var isPaused = false
private var searchKey: String? = null
private val qrResult = registerForActivityResult(QrCodeResult()) { private val qrResult = registerForActivityResult(QrCodeResult()) {
it ?: return@registerForActivityResult it ?: return@registerForActivityResult
showDialogFragment(ImportBookSourceDialog(it)) showDialogFragment(ImportBookSourceDialog(it))
@@ -235,6 +235,7 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
private fun upBookSource(searchKey: String? = null) { private fun upBookSource(searchKey: String? = null) {
this.searchKey = searchKey
sourceFlowJob?.cancel() sourceFlowJob?.cancel()
sourceFlowJob = launch { sourceFlowJob = launch {
when { when {
@@ -376,7 +377,12 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.selection.toTypedArray()) R.id.menu_bottom_sel -> viewModel.bottomSource(*adapter.selection.toTypedArray())
R.id.menu_add_group -> selectionAddToGroups() R.id.menu_add_group -> selectionAddToGroups()
R.id.menu_remove_group -> selectionRemoveFromGroups() R.id.menu_remove_group -> selectionRemoveFromGroups()
R.id.menu_export_selection -> viewModel.saveToFile(adapter.selection.toBookSource()) { file -> R.id.menu_export_selection -> viewModel.saveToFile(
adapter,
searchKey,
sortAscending,
sort
) { file ->
exportDir.launch { exportDir.launch {
mode = HandleFileContract.EXPORT mode = HandleFileContract.EXPORT
fileData = HandleFileContract.FileData( fileData = HandleFileContract.FileData(
@@ -387,7 +393,12 @@ class BookSourceActivity : VMBaseActivity<ActivityBookSourceBinding, BookSourceV
} }
} }
R.id.menu_share_source -> viewModel.saveToFile(adapter.selection.toBookSource()) { R.id.menu_share_source -> viewModel.saveToFile(
adapter,
searchKey,
sortAscending,
sort
) {
share(it) share(it)
} }
@@ -2,14 +2,19 @@ package io.legado.app.ui.book.source.manage
import android.app.Application import android.app.Application
import android.text.TextUtils import android.text.TextUtils
import io.legado.app.R
import io.legado.app.base.BaseViewModel import io.legado.app.base.BaseViewModel
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.data.entities.BookSourcePart import io.legado.app.data.entities.BookSourcePart
import io.legado.app.data.entities.toBookSource
import io.legado.app.help.config.SourceConfig import io.legado.app.help.config.SourceConfig
import io.legado.app.utils.* import io.legado.app.utils.*
import splitties.init.appCtx
import java.io.BufferedOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
import io.legado.app.ui.book.source.manage.BookSourceActivity.Sort
/** /**
* 书源管理数据修改 * 书源管理数据修改
@@ -56,10 +61,10 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
if (items.isEmpty()) return if (items.isEmpty()) return
execute { execute {
val firstSortNumber = items[0].customOrder val firstSortNumber = items[0].customOrder
items.forEachIndexed { index, bookSource -> val array = items.mapIndexed { index, bookSource ->
bookSource.customOrder = firstSortNumber + index bookSource.copy(customOrder = firstSortNumber + index)
} }
appDb.bookSourceDao.upOrder(items) appDb.bookSourceDao.upOrder(array)
} }
} }
@@ -122,13 +127,15 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
} }
@Suppress("BlockingMethodInNonBlockingContext") @Suppress("BlockingMethodInNonBlockingContext")
fun saveToFile(sources: List<BookSource>, success: (file: File) -> Unit) { private fun saveToFile(sources: List<BookSource>, success: (file: File) -> Unit) {
execute { execute {
val path = "${context.filesDir}/shareBookSource.json" val path = "${context.filesDir}/shareBookSource.json"
FileUtils.delete(path) FileUtils.delete(path)
val file = FileUtils.createFileWithReplace(path) val file = FileUtils.createFileWithReplace(path)
FileOutputStream(file).use { FileOutputStream(file).use { out ->
GSON.writeToOutputStream(it, sources) BufferedOutputStream(out, 64 * 1024).use {
GSON.writeToOutputStream(it, sources)
}
} }
file file
}.onSuccess { }.onSuccess {
@@ -138,6 +145,107 @@ class BookSourceViewModel(application: Application) : BaseViewModel(application)
} }
} }
fun saveToFile(
adapter: BookSourceAdapter,
searchKey: String?,
sortAscending: Boolean,
sort: Sort,
success: (file: File) -> Unit
) {
execute {
val selection = adapter.selection
val selectedRate = selection.size.toFloat() / adapter.itemCount.toFloat()
val sources = if (selectedRate == 1f) {
getBookSources(searchKey, sortAscending, sort)
} else if (selectedRate < 0.3) {
selection.toBookSource()
} else {
val keys = selection.map { it.bookSourceUrl }.toHashSet()
val bookSources = getBookSources(searchKey, sortAscending, sort)
bookSources.filter {
keys.contains(it.bookSourceUrl)
}
}
saveToFile(sources, success)
}
}
private fun getBookSources(
searchKey: String?,
sortAscending: Boolean,
sort: Sort
): List<BookSource> {
return when {
searchKey.isNullOrEmpty() -> {
appDb.bookSourceDao.all
}
searchKey == appCtx.getString(R.string.enabled) -> {
appDb.bookSourceDao.allEnabled
}
searchKey == appCtx.getString(R.string.disabled) -> {
appDb.bookSourceDao.allDisabled
}
searchKey == appCtx.getString(R.string.need_login) -> {
appDb.bookSourceDao.allLogin
}
searchKey == appCtx.getString(R.string.no_group) -> {
appDb.bookSourceDao.allNoGroup
}
searchKey.startsWith("group:") -> {
val key = searchKey.substringAfter("group:")
appDb.bookSourceDao.groupSearch(key)
}
else -> {
appDb.bookSourceDao.search(searchKey)
}
}.let { data ->
if (sortAscending) when (sort) {
Sort.Weight -> data.sortedBy { it.weight }
Sort.Name -> data.sortedWith { o1, o2 ->
o1.bookSourceName.cnCompare(o2.bookSourceName)
}
Sort.Url -> data.sortedBy { it.bookSourceUrl }
Sort.Update -> data.sortedByDescending { it.lastUpdateTime }
Sort.Respond -> data.sortedBy { it.respondTime }
Sort.Enable -> data.sortedWith { o1, o2 ->
var sortNum = -o1.enabled.compareTo(o2.enabled)
if (sortNum == 0) {
sortNum = o1.bookSourceName.cnCompare(o2.bookSourceName)
}
sortNum
}
else -> data
}
else when (sort) {
Sort.Weight -> data.sortedByDescending { it.weight }
Sort.Name -> data.sortedWith { o1, o2 ->
o2.bookSourceName.cnCompare(o1.bookSourceName)
}
Sort.Url -> data.sortedByDescending { it.bookSourceUrl }
Sort.Update -> data.sortedBy { it.lastUpdateTime }
Sort.Respond -> data.sortedByDescending { it.respondTime }
Sort.Enable -> data.sortedWith { o1, o2 ->
var sortNum = o1.enabled.compareTo(o2.enabled)
if (sortNum == 0) {
sortNum = o1.bookSourceName.cnCompare(o2.bookSourceName)
}
sortNum
}
else -> data.reversed()
}
}
}
fun addGroup(group: String) { fun addGroup(group: String) {
execute { execute {
val sources = appDb.bookSourceDao.noGroup val sources = appDb.bookSourceDao.noGroup
@@ -32,9 +32,6 @@ object HtmlFormatter {
.replace("\\s*\\n+\\s*".toRegex(), "\n  ") .replace("\\s*\\n+\\s*".toRegex(), "\n  ")
.replace("^[\\n\\s]+".toRegex(), "  ") .replace("^[\\n\\s]+".toRegex(), "  ")
.replace("[\\n\\s]+$".toRegex(), "") .replace("[\\n\\s]+$".toRegex(), "")
.let {
StringEscapeUtils.unescapeHtml3(it)
}
} }
fun formatKeepImg(html: String?, redirectUrl: URL? = null): String { fun formatKeepImg(html: String?, redirectUrl: URL? = null): String {
@@ -9,16 +9,12 @@ import java.io.InputStream
@Suppress("unused") @Suppress("unused")
object MD5Utils { object MD5Utils {
private val MD5Digester by lazy {
DigestUtil.digester("MD5")
}
fun md5Encode(str: String?): String { fun md5Encode(str: String?): String {
return MD5Digester.digestHex(str) return DigestUtil.digester("MD5").digestHex(str)
} }
fun md5Encode(inputStream: InputStream): String { fun md5Encode(inputStream: InputStream): String {
return MD5Digester.digestHex(inputStream) return DigestUtil.digester("MD5").digestHex(inputStream)
} }
fun md5Encode16(str: String): String { fun md5Encode16(str: String): String {
@@ -1,5 +1,6 @@
package io.legado.app.utils package io.legado.app.utils
import android.annotation.SuppressLint
import android.net.ConnectivityManager import android.net.ConnectivityManager
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.os.Build import android.os.Build
@@ -21,6 +22,7 @@ object NetworkUtils {
/** /**
* 判断是否联网 * 判断是否联网
*/ */
@SuppressLint("ObsoleteSdkInt")
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
fun isAvailable(): Boolean { fun isAvailable(): Boolean {
if (Build.VERSION.SDK_INT < 23) { if (Build.VERSION.SDK_INT < 23) {
@@ -31,7 +33,9 @@ object NetworkUtils {
// 移动数据 // 移动数据
mWiFiNetworkInfo.type == ConnectivityManager.TYPE_MOBILE || mWiFiNetworkInfo.type == ConnectivityManager.TYPE_MOBILE ||
// 以太网 // 以太网
mWiFiNetworkInfo.type == ConnectivityManager.TYPE_ETHERNET mWiFiNetworkInfo.type == ConnectivityManager.TYPE_ETHERNET ||
// VPN
mWiFiNetworkInfo.type == ConnectivityManager.TYPE_VPN
} }
} else { } else {
val network = connectivityManager.activeNetwork val network = connectivityManager.activeNetwork
@@ -43,7 +47,9 @@ object NetworkUtils {
// 移动数据 // 移动数据
nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) ||
// 以太网 // 以太网
nc.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) nc.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) ||
// VPN
nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)
} }
} }
} }