diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index e142d56bc..04be02dfb 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -22,6 +22,8 @@ jobs:
UPLOAD_ARTIFACT: 'true'
steps:
- uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
- uses: actions/cache@v2
with:
path: |
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9c62d0be3..f7e57679a 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -22,6 +22,8 @@ jobs:
UPLOAD_ARTIFACT: 'true'
steps:
- uses: actions/checkout@v2
+ with:
+ fetch-depth: 0
- uses: actions/cache@v2
with:
path: |
diff --git a/app/.gitignore b/app/.gitignore
index 796b96d1c..e431c26b5 100644
--- a/app/.gitignore
+++ b/app/.gitignore
@@ -1 +1,2 @@
/build
+/so
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index f2cc4727e..3d38e0742 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -3,6 +3,7 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
apply plugin: 'kotlin-kapt'
apply plugin: 'de.timfreiheit.resourceplaceholders'
+apply from:'download.gradle'
static def releaseTime() {
return new Date().format("yy.MMddHH", TimeZone.getTimeZone("GMT+8"))
@@ -55,14 +56,17 @@ android {
}
buildTypes {
release {
+ buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.myConfig
}
applicationIdSuffix '.release'
+
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
+ buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
if (project.hasProperty("RELEASE_STORE_FILE")) {
signingConfig signingConfigs.myConfig
}
diff --git a/app/cronetlib/src/cronet_api-src.jar b/app/cronetlib/src/cronet_api-src.jar
deleted file mode 100644
index c175fb4e0..000000000
Binary files a/app/cronetlib/src/cronet_api-src.jar and /dev/null differ
diff --git a/app/cronetlib/src/cronet_impl_common_java-src.jar b/app/cronetlib/src/cronet_impl_common_java-src.jar
deleted file mode 100644
index 6e9402d80..000000000
Binary files a/app/cronetlib/src/cronet_impl_common_java-src.jar and /dev/null differ
diff --git a/app/cronetlib/src/cronet_impl_native_java-src.jar b/app/cronetlib/src/cronet_impl_native_java-src.jar
deleted file mode 100644
index 83a357a91..000000000
Binary files a/app/cronetlib/src/cronet_impl_native_java-src.jar and /dev/null differ
diff --git a/app/cronetlib/src/cronet_impl_platform_java-src.jar b/app/cronetlib/src/cronet_impl_platform_java-src.jar
deleted file mode 100644
index 48c544ef7..000000000
Binary files a/app/cronetlib/src/cronet_impl_platform_java-src.jar and /dev/null differ
diff --git a/app/download.gradle b/app/download.gradle
new file mode 100644
index 000000000..ec479c2c2
--- /dev/null
+++ b/app/download.gradle
@@ -0,0 +1,110 @@
+import java.security.MessageDigest
+
+apply plugin: 'de.undercouch.download'
+
+def BASE_PATH = "https://storage.googleapis.com/chromium-cronet/android/" + CronetVersion + "/Release/cronet/"
+def assetsDir = projectDir.toString() + "/src/main/assets"
+def libPath = projectDir.toString() + "/cronetlib"
+def soPath = projectDir.toString() + "/so"
+
+/**
+ * 从文件生成MD5
+ * @param file
+ * @return
+ */
+static def generateMD5(final file) {
+ MessageDigest digest = MessageDigest.getInstance("MD5")
+ file.withInputStream() { is ->
+ byte[] buffer = new byte[1024]
+ int numRead = 0
+ while ((numRead = is.read(buffer)) > 0) {
+ digest.update(buffer, 0, numRead)
+ }
+ }
+ return String.format("%032x", new BigInteger(1, digest.digest())).toLowerCase()
+}
+
+/**
+ * 下载Cronet相关的jar
+ */
+task downloadJar(type: Download) {
+ src([
+ BASE_PATH + "cronet_api.jar",
+ BASE_PATH + "cronet_impl_common_java.jar",
+ BASE_PATH + "cronet_impl_native_java.jar",
+ BASE_PATH + "cronet_impl_platform_java.jar",
+ ])
+ dest libPath
+ overwrite true
+ onlyIfModified true
+}
+/**
+ * 下载Cronet的arm64-v8a so
+ */
+task downloadARM64(type: Download) {
+ src BASE_PATH + "libs/arm64-v8a/libcronet." + CronetVersion + ".so"
+ dest soPath + "/arm64-v8a.so"
+ overwrite true
+ onlyIfModified true
+}
+/**
+ * 下载Cronet的armeabi-v7a so
+ */
+task downloadARMv7(type: Download) {
+ src BASE_PATH + "libs/armeabi-v7a/libcronet." + CronetVersion + ".so"
+ dest soPath + "/armeabi-v7a.so"
+ overwrite true
+ onlyIfModified true
+}
+/**
+ * 下载Cronet的x86_64 so
+ */
+task downloadX86_64(type: Download) {
+ src BASE_PATH + "libs/x86_64/libcronet." + CronetVersion + ".so"
+ dest soPath + "/x86_64.so"
+ overwrite true
+ onlyIfModified true
+}
+/**
+ * 下载Cronet的x86 so
+ */
+task downloadX86(type: Download) {
+ src BASE_PATH + "libs/x86/libcronet." + CronetVersion + ".so"
+ dest soPath + "/x86.so"
+ overwrite true
+ onlyIfModified true
+}
+
+/**
+ * 更新Cronet版本时执行这个task
+ * 先更改gradle.properties 里面的版本号,然后再执行
+ * gradlew app:downloadCronet
+ */
+task downloadCronet() {
+ dependsOn downloadJar, downloadARM64, downloadARMv7, downloadX86_64, downloadX86
+
+ doLast {
+ StringBuilder sb = new StringBuilder("{")
+ def files = new File(soPath).listFiles()
+ for (File file : files) {
+ println file.name.replace(".so", "")
+ sb.append("\"").append(file.name.replace(".so", "")).append("\":\"").append(generateMD5(file)).append("\",")
+ }
+ sb.append("\"version\":\"").append(CronetVersion).append("\"}")
+
+ println sb.toString()
+
+ println assetsDir
+ def f1 = new File(assetsDir + "/cronet.json")
+ if (!f1.exists()) {
+ f1.parentFile.mkdirs()
+ f1.createNewFile()
+ }
+ f1.text = sb.toString()
+
+ }
+
+
+}
+
+
diff --git a/app/src/main/assets/cronet.json b/app/src/main/assets/cronet.json
new file mode 100644
index 000000000..1e118c39d
--- /dev/null
+++ b/app/src/main/assets/cronet.json
@@ -0,0 +1 @@
+{"arm64-v8a":"1f4e088f6e00175e12ee153e4004d283","armeabi-v7a":"a6726219c9a6217b95763baa3d61eb18","x86":"73b6a220fe16e0cdeebf1094980825c2","x86_64":"12fd5bb0a12664294b64fffccd326347","version":"92.0.4515.159"}
\ No newline at end of file
diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
index ca5abca0d..ab4353049 100644
--- a/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
+++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
@@ -1,6 +1,7 @@
package io.legado.app.help.http.cronet
import android.util.Log
+import com.google.android.gms.net.CronetProviderInstaller
import io.legado.app.help.AppConfig
import okhttp3.Headers
import okhttp3.MediaType
@@ -18,22 +19,24 @@ import java.util.concurrent.Executors
val executor: Executor by lazy { Executors.newCachedThreadPool() }
val cronetEngine: ExperimentalCronetEngine by lazy {
- CronetLoader.preDownload()
+ if (AppConfig.isGooglePlay) {
+ CronetProviderInstaller.installProvider(appCtx)
+ } else {
+ CronetLoader.preDownload()
+ }
+
val builder = ExperimentalCronetEngine.Builder(appCtx).apply {
- if (!AppConfig.isGooglePlay) {
+ if (!AppConfig.isGooglePlay&&CronetLoader.install()) {
setLibraryLoader(CronetLoader)//设置自定义so库加载
}
setStoragePath(appCtx.externalCacheDir?.absolutePath)//设置缓存路径
- enableHttpCache(HTTP_CACHE_DISK, (1024 * 1024 * 50))//设置缓存模式
+ enableHttpCache(HTTP_CACHE_DISK, (1024 * 1024 * 50).toLong())//设置缓存模式
enableQuic(true)//设置支持http/3
enableHttp2(true) //设置支持http/2
enablePublicKeyPinningBypassForLocalTrustAnchors(true)
- //enableNetworkQualityEstimator(true)
- //Brotli压缩
- enableBrotli(true)
- //setExperimentalOptions("{\"quic_version\": \"h3-29\"}")
+ enableBrotli(true)//Brotli压缩
}
val engine = builder.build()
Log.d("Cronet", "Cronet Version:" + engine.versionString)
diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
index 2038e461a..ccd63d415 100644
--- a/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
+++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
@@ -15,6 +15,7 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
} else try {
//移除Keep-Alive,手动设置会导致400 BadRequest
builder.removeHeader("Keep-Alive")
+ builder.removeHeader("Accept-Encoding")
val cookieStr = getCookie(original.url)
//设置Cookie
if (cookieStr.length > 3) {
@@ -44,7 +45,7 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
val callback = CronetUrlRequestCallback(request, call)
val urlRequest = buildRequest(request, callback)
urlRequest.start()
- return callback.waitForDone(urlRequest)
+ return callback.waitForDone(urlRequest)
}
private fun getCookie(url: HttpUrl): String {
diff --git a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
index f2d8ec058..ad9258c5e 100644
--- a/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
+++ b/app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
@@ -6,11 +6,12 @@ import android.content.pm.ApplicationInfo
import android.os.Build
import android.text.TextUtils
import android.util.Log
+import com.google.android.gms.net.CronetProviderInstaller
+import io.legado.app.BuildConfig
import io.legado.app.help.AppConfig
import io.legado.app.help.coroutine.Coroutine
-import io.legado.app.utils.getPrefString
-import io.legado.app.utils.putPrefString
import org.chromium.net.CronetEngine
+import org.json.JSONObject
import splitties.init.appCtx
import java.io.*
import java.math.BigInteger
@@ -19,28 +20,25 @@ import java.net.URL
import java.security.MessageDigest
import java.util.*
+
object CronetLoader : CronetEngine.Builder.LibraryLoader() {
- //https://storage.googleapis.com/chromium-cronet/android/92.0.4515.127/Release/cronet/libs/arm64-v8a/libcronet.92.0.4515.127.so
- //https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@92.0.4515.127/cronet/92.0.4515.127/arm64-v8a/libcronet.92.0.4515.127.so.js
+ //https://storage.googleapis.com/chromium-cronet/android/92.0.4515.127/Release/cronet/libs/arm64-v8a/libcronet.92.0.4515.159.so
+ //https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@92.0.4515.127/cronet/92.0.4515.127/arm64-v8a/libcronet.92.0.4515.159.so.js
private const val TAG = "CronetLoader"
- private const val soVersion = "92.0.4515.159"
+ private const val soVersion = BuildConfig.Cronet_Version
private const val soName = "libcronet.$soVersion.so"
private val soUrl: String
- private val md5Url: String
private val soFile: File
private val downloadFile: File
private var cpuAbi: String? = null
- private var md5: String? = appCtx.getPrefString("soMd5")
- private val version: String? = appCtx.getPrefString("soVersion", soVersion)
+ private var md5: String
var download = false
init {
soUrl = ("https://storage.googleapis.com/chromium-cronet/android/"
+ soVersion + "/Release/cronet/libs/"
+ getCpuAbi(appCtx) + "/" + soName)
- md5Url = ("https://cdn.jsdelivr.net/gh/ag2s20150909/cronet-repo@" +
- soVersion + "/cronet/" + soVersion + "/"
- + getCpuAbi(appCtx) + "/" + soName + ".js")
+ md5 = getMd5(appCtx)
val dir = appCtx.getDir("cronet", Context.MODE_PRIVATE)
soFile = File(dir.toString() + "/" + getCpuAbi(appCtx), soName)
downloadFile = File(appCtx.cacheDir.toString() + "/so_download", soName)
@@ -54,13 +52,20 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
if (AppConfig.isGooglePlay) {
return true
}
+ if (md5.length != 32 || !soFile.exists() || md5 != getFileMD5(soFile)) {
+ return false
+ }
return soFile.exists()
}
+
fun preDownload() {
- if (AppConfig.isGooglePlay) return
+ if (AppConfig.isGooglePlay) {
+ CronetProviderInstaller.installProvider(appCtx)
+ return
+ }
Coroutine.async {
- md5 = getUrlMd5(md5Url)
+ //md5 = getUrlMd5(md5Url)
if (soFile.exists() && md5 == getFileMD5(soFile)) {
Log.e(TAG, "So 库已存在")
} else {
@@ -70,6 +75,27 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
}
}
+ private fun getMd5(context: Context): String {
+ val stringBuilder = StringBuilder()
+ return try {
+ //获取assets资源管理器
+ val assetManager = context.assets
+ //通过管理器打开文件并读取
+ val bf = BufferedReader(
+ InputStreamReader(
+ assetManager.open("cronet.json")
+ )
+ )
+ var line: String?
+ while (bf.readLine().also { line = it } != null) {
+ stringBuilder.append(line)
+ }
+ JSONObject(stringBuilder.toString()).optString(getCpuAbi(context), "")
+ } catch (e: java.lang.Exception) {
+ return ""
+ }
+ }
+
@SuppressLint("UnsafeDynamicallyLoadedCode")
override fun loadLibrary(libName: String) {
Log.e(TAG, "libName:$libName")
@@ -89,9 +115,9 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
//如果找不到,则从远程下载
//删除历史文件
deleteHistoryFile(Objects.requireNonNull(soFile.parentFile), soFile)
- md5 = getUrlMd5(md5Url)
+ //md5 = getUrlMd5(md5Url)
Log.i(TAG, "soMD5:$md5")
- if (md5 == null || md5!!.length != 32 || soUrl.isEmpty()) {
+ if (md5.length != 32 || soUrl.isEmpty()) {
//如果md5或下载的url为空,则调用系统行为进行加载
System.loadLibrary(libName)
return
@@ -144,39 +170,6 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
return cpuAbi
}
- @Suppress("SameParameterValue")
- private fun getUrlMd5(url: String): String? {
- //这样在下载成功后,遇到无网条件下,只要版本未发生变化也能获取md5
- if (md5 != null && md5!!.length == 32 && version == soVersion) {
- appCtx.putPrefString("soMd5", md5)
- appCtx.putPrefString("soVersion", soVersion)
- return md5
- }
- val inputStream: InputStream
- val outputStream: OutputStream
- return try {
- outputStream = ByteArrayOutputStream()
- val connection = URL(url).openConnection() as HttpURLConnection
- inputStream = connection.inputStream
- val buffer = ByteArray(1024)
- var read: Int
- while (inputStream.read(buffer).also { read = it } != -1) {
- outputStream.write(buffer, 0, read)
- outputStream.flush()
- }
- val tmd5 = outputStream.toString()
- //成功获取到md5后保存md5和版本
- if (tmd5.length == 32) {
- appCtx.putPrefString("soMd5", tmd5)
- appCtx.putPrefString("soVersion", soVersion)
- }
-
- return tmd5
-
- } catch (e: IOException) {
- null
- }
- }
/**
* 删除历史文件
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index 4a79b1294..57936ae27 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -315,9 +315,9 @@
Espaço entre linhas
Espaço entre parágrafos
Na parte superior
- Seleção no topo
+ Seleção até o topo
Na parte inferior
- Seleção no fundo
+ Seleção até o final
Expansão automática de Descoberta
A expansão padrão da primeira Descoberta.
Linhas atuais %s
@@ -393,11 +393,11 @@
源分组(fonteGrupo)
自定义源分组
输入自定义源分组名称
- 并发率(concurrentRate)
- 分类Url(sortUrl)
+ 并发率(taxaSimultânea)
+ 分类Url(ordenarUrl)
登录URL(loginUrl)
- 登录UI(loginUi)
- 登录检查JS(loginCheckJs)
+ 登UI(loginIU)
+ 登录检查JS(loginVerifJs)
源注释(fonteComentário)
搜索地址(url)
发现地址规则(url)
@@ -849,20 +849,20 @@
Resetar
Nenhuma url
Dicionários
- 未知错误
- end
- 关闭替换分组/开启添加分组
- 媒体按钮•上一首|下一首
- 上一段|下一段/上一章|下一章
- 及时翻页,翻页时会停顿一下
- Verificar a fonte do livro mostra uma mensagem de depuração
- Exibir etapas de solicitação de rede e tempo durante a verificação da fonte do livro
- No export chapter names
- Autobackup failed
- Background image blurring
- Blurring radius
- Disabled when 0, enable range from 1 to 25\nThe greater the radius, the stronger the effect of blurring
- 需登录
- 使用Cronet网络组件
+ Erro desconhecido
+ fim
+ Desativar substituir agrupamento / Ativar adicionar agrupamento
+ Botões de mídia - Anterior|Próximo
+ Anterior|Próximo Parágrafo/Anterior|Próximo Capítulo
+ Virar as páginas durante tempo, com uma pausa ao virar as páginas
+ Marcando a fonte do livro mostra uma mensagem de depuração
+ Mostrar o status da rede com a data e hora durante a verificação da fonte
+ Não há nomes de capítulos de exportação
+ Auto-Backup falhou
+ Desfocagem da imagem de fundo
+ Raio da desfocagem
+ Desativado quando 0, Ativado entre 1 e 25\n Quanto maior o raio, mais forte o efeito de desfocagem
+ Login necessário
+ Usando componentes de rede Cronet
diff --git a/build.gradle b/build.gradle
index 967f30950..36559ec3b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,6 +13,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:7.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'de.timfreiheit.resourceplaceholders:placeholders:0.4'
+ classpath 'de.undercouch:gradle-download-task:4.1.2'
}
}
diff --git a/gradle.properties b/gradle.properties
index 7934fd0e7..e8357fd01 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -21,3 +21,5 @@ android.enableJetifier=true
kotlin.code.style=official
android.enableResourceOptimizations=true
+
+CronetVersion=92.0.4515.159