Merge remote-tracking branch 'origin/master'

pull/1282/head
gedoor 3 years ago
commit 967462b891
  1. 2
      .github/workflows/release.yml
  2. 2
      .github/workflows/test.yml
  3. 1
      app/.gitignore
  4. 4
      app/build.gradle
  5. BIN
      app/cronetlib/src/cronet_api-src.jar
  6. BIN
      app/cronetlib/src/cronet_impl_common_java-src.jar
  7. BIN
      app/cronetlib/src/cronet_impl_native_java-src.jar
  8. BIN
      app/cronetlib/src/cronet_impl_platform_java-src.jar
  9. 110
      app/download.gradle
  10. 1
      app/src/main/assets/cronet.json
  11. 17
      app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
  12. 3
      app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
  13. 89
      app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
  14. 42
      app/src/main/res/values-pt-rBR/strings.xml
  15. 1
      build.gradle
  16. 2
      gradle.properties

@ -22,6 +22,8 @@ jobs:
UPLOAD_ARTIFACT: 'true'
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/cache@v2
with:
path: |

@ -22,6 +22,8 @@ jobs:
UPLOAD_ARTIFACT: 'true'
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/cache@v2
with:
path: |

1
app/.gitignore vendored

@ -1 +1,2 @@
/build
/so

@ -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
}

@ -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()
}
}

@ -0,0 +1 @@
{"arm64-v8a":"1f4e088f6e00175e12ee153e4004d283","armeabi-v7a":"a6726219c9a6217b95763baa3d61eb18","x86":"73b6a220fe16e0cdeebf1094980825c2","x86_64":"12fd5bb0a12664294b64fffccd326347","version":"92.0.4515.159"}

@ -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)

@ -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 {

@ -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
}
}
/**
* 删除历史文件

@ -315,9 +315,9 @@
<string name="line_size">Espaço entre linhas</string>
<string name="paragraph_size">Espaço entre parágrafos</string>
<string name="to_top">Na parte superior</string>
<string name="selection_to_top">Seleção no topo</string>
<string name="selection_to_top">Seleção até o topo</string>
<string name="to_bottom">Na parte inferior</string>
<string name="selection_to_bottom">Seleção no fundo</string>
<string name="selection_to_bottom">Seleção até o final</string>
<string name="auto_expand_find">Expansão automática de Descoberta</string>
<string name="default_expand_first">A expansão padrão da primeira Descoberta.</string>
<string name="threads_num">Linhas atuais %s</string>
@ -393,11 +393,11 @@
<string name="source_group">源分组(fonteGrupo)</string>
<string name="diy_source_group">自定义源分组</string>
<string name="diy_edit_source_group">输入自定义源分组名称</string>
<string name="source_concurrent_rate">并发率(concurrentRate)</string>
<string name="sort_url">分类Url(sortUrl)</string>
<string name="source_concurrent_rate">并发率(taxaSimultânea)</string>
<string name="sort_url">分类Url(ordenarUrl)</string>
<string name="login_url">登录URL(loginUrl)</string>
<string name="login_ui">UI(loginUi)</string>
<string name="login_check_js">登录检查JS(loginCheckJs)</string>
<string name="login_ui">登UI(loginIU)</string>
<string name="login_check_js">登录检查JS(loginVerifJs)</string>
<string name="comment">源注释(fonteComentário)</string>
<string name="r_search_url">搜索地址(url)</string>
<string name="r_find_url">发现地址规则(url)</string>
@ -849,20 +849,20 @@
<string name="reset">Resetar</string>
<string name="null_url">Nenhuma url</string>
<string name="dict">Dicionários</string>
<string name="unknown_error">未知错误</string>
<string name="end">end</string>
<string name="custom_group_summary">关闭替换分组/开启添加分组</string>
<string name="pref_media_button_per_next">媒体按钮•上一首|下一首</string>
<string name="pref_media_button_per_next_summary">上一段|下一段/上一章|下一章</string>
<string name="read_aloud_by_page_summary">及时翻页,翻页时会停顿一下</string>
<string name="check_source_show_debug_message">Verificar a fonte do livro mostra uma mensagem de depuração</string>
<string name="check_source_show_debug_message_summary">Exibir etapas de solicitação de rede e tempo durante a verificação da fonte do livro</string>
<string name="export_no_chapter_name">No export chapter names</string>
<string name="autobackup_fail">Autobackup failed</string>
<string name="background_image_blurring">Background image blurring</string>
<string name="background_image_blurring_radius">Blurring radius</string>
<string name="background_image_hint">Disabled when 0, enable range from 1 to 25\nThe greater the radius, the stronger the effect of blurring</string>
<string name="need_login">需登录</string>
<string name="pref_cronet_summary">使用Cronet网络组件</string>
<string name="unknown_error">Erro desconhecido</string>
<string name="end">fim</string>
<string name="custom_group_summary">Desativar substituir agrupamento / Ativar adicionar agrupamento</string>
<string name="pref_media_button_per_next">Botões de mídia - Anterior|Próximo</string>
<string name="pref_media_button_per_next_summary">Anterior|Próximo Parágrafo/Anterior|Próximo Capítulo</string>
<string name="read_aloud_by_page_summary">Virar as páginas durante tempo, com uma pausa ao virar as páginas</string>
<string name="check_source_show_debug_message">Marcando a fonte do livro mostra uma mensagem de depuração</string>
<string name="check_source_show_debug_message_summary">Mostrar o status da rede com a data e hora durante a verificação da fonte</string>
<string name="export_no_chapter_name">Não há nomes de capítulos de exportação</string>
<string name="autobackup_fail">Auto-Backup falhou</string>
<string name="background_image_blurring">Desfocagem da imagem de fundo</string>
<string name="background_image_blurring_radius">Raio da desfocagem</string>
<string name="background_image_hint">Desativado quando 0, Ativado entre 1 e 25\n Quanto maior o raio, mais forte o efeito de desfocagem</string>
<string name="need_login">Login necessário</string>
<string name="pref_cronet_summary">Usando componentes de rede Cronet</string>
</resources>

@ -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'
}
}

@ -21,3 +21,5 @@ android.enableJetifier=true
kotlin.code.style=official
android.enableResourceOptimizations=true
CronetVersion=92.0.4515.159

Loading…
Cancel
Save