pull/2731/head
ag2s20150909 2 years ago
parent 3c4e7cb79e
commit 2bd68eb1a3
  1. 2
      app/build.gradle
  2. 17
      app/src/app/java/io/legado/app/lib/cronet/BodyUploadProvider.kt
  3. 5
      app/src/app/java/io/legado/app/lib/cronet/CronetCoroutineInterceptor.kt
  4. 15
      app/src/app/java/io/legado/app/lib/cronet/CronetHelper.kt
  5. 75
      app/src/app/java/io/legado/app/lib/cronet/LargeBodyUploadProvider.kt
  6. 2
      app/src/main/java/io/legado/app/help/config/AppConfig.kt

@ -49,6 +49,7 @@ android {
buildConfigField "String", "Cronet_Version", "\"$CronetVersion\"" buildConfigField "String", "Cronet_Version", "\"$CronetVersion\""
buildConfigField "String", "Cronet_Main_Version", "\"$CronetMainVersion\"" buildConfigField "String", "Cronet_Main_Version", "\"$CronetMainVersion\""
buildConfigField "boolean", "isGoogle", "false"
javaCompileOptions { javaCompileOptions {
annotationProcessorOptions { annotationProcessorOptions {
@ -104,6 +105,7 @@ android {
dimension "mode" dimension "mode"
applicationId "io.legado.play" applicationId "io.legado.play"
manifestPlaceholders.put("APP_CHANNEL_VALUE", "google") manifestPlaceholders.put("APP_CHANNEL_VALUE", "google")
buildConfigField "boolean", "isGoogle", "true"
} }
} }
compileOptions { compileOptions {

@ -13,9 +13,18 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
private val buffer = Buffer() private val buffer = Buffer()
@Volatile
private var filled: Boolean = false
init { init {
fillBuffer()
}
private fun fillBuffer() {
try { try {
buffer.clear()
body.writeTo(buffer) body.writeTo(buffer)
buffer.flush()
} catch (e: IOException) { } catch (e: IOException) {
e.printStackTrace() e.printStackTrace()
} }
@ -28,6 +37,9 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
@Throws(IOException::class) @Throws(IOException::class)
override fun read(uploadDataSink: UploadDataSink, byteBuffer: ByteBuffer) { override fun read(uploadDataSink: UploadDataSink, byteBuffer: ByteBuffer) {
if (!filled) {
fillBuffer()
}
check(byteBuffer.hasRemaining()) { "Cronet passed a buffer with no bytes remaining" } check(byteBuffer.hasRemaining()) { "Cronet passed a buffer with no bytes remaining" }
var read: Int var read: Int
var bytesRead = 0 var bytesRead = 0
@ -40,8 +52,9 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
@Throws(IOException::class) @Throws(IOException::class)
override fun rewind(uploadDataSink: UploadDataSink) { override fun rewind(uploadDataSink: UploadDataSink) {
buffer.clear() check(body.isOneShot()) { "Okhttp RequestBody is oneShot" }
body.writeTo(buffer) filled = false
fillBuffer()
uploadDataSink.onRewindSucceeded() uploadDataSink.onRewindSucceeded()
} }

@ -93,7 +93,10 @@ class CronetCoroutineInterceptor : Interceptor {
} }
buildRequest(request, callBack)?.start() val req = buildRequest(request, callBack)?.also { it.start() }
coroutine.invokeOnCancellation {
req?.cancel()
}
} }

@ -12,10 +12,13 @@ import okhttp3.MediaType
import okhttp3.Request import okhttp3.Request
import org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK import org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK
import org.chromium.net.ExperimentalCronetEngine import org.chromium.net.ExperimentalCronetEngine
import org.chromium.net.UploadDataProvider
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import org.json.JSONObject import org.json.JSONObject
import splitties.init.appCtx import splitties.init.appCtx
internal const val BUFFER_SIZE = 32 * 1024
val cronetEngine: ExperimentalCronetEngine? by lazy { val cronetEngine: ExperimentalCronetEngine? by lazy {
if (!AppConfig.isGooglePlay) { if (!AppConfig.isGooglePlay) {
CronetLoader.preDownload() CronetLoader.preDownload()
@ -85,10 +88,14 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
} else { } else {
addHeader("Content-Type", "text/plain") addHeader("Content-Type", "text/plain")
} }
setUploadDataProvider( val provider: UploadDataProvider = if (requestBody.contentLength() > BUFFER_SIZE) {
BodyUploadProvider(requestBody), LargeBodyUploadProvider(requestBody, okHttpClient.dispatcher.executorService)
okHttpClient.dispatcher.executorService } else {
) BodyUploadProvider(requestBody)
}
provider.use {
this.setUploadDataProvider(it, okHttpClient.dispatcher.executorService)
}
} }

@ -0,0 +1,75 @@
package io.legado.app.lib.cronet
import androidx.annotation.Keep
import okhttp3.RequestBody
import okio.BufferedSource
import okio.Pipe
import okio.buffer
import org.chromium.net.UploadDataProvider
import org.chromium.net.UploadDataSink
import java.io.IOException
import java.nio.ByteBuffer
import java.util.concurrent.ExecutorService
/**
* 用于上传大型文件
*
* @property body
* @property executorService
*/
@Keep
class LargeBodyUploadProvider(
private val body: RequestBody,
private val executorService: ExecutorService
) : UploadDataProvider(), AutoCloseable {
private val pipe = Pipe(BUFFER_SIZE.toLong())
private var source: BufferedSource = pipe.source.buffer()
@Volatile
private var filled: Boolean = false
override fun getLength(): Long {
return body.contentLength()
}
override fun read(uploadDataSink: UploadDataSink, byteBuffer: ByteBuffer) {
if (!filled) {
fillBuffer()
}
check(byteBuffer.hasRemaining()) { "Cronet passed a buffer with no bytes remaining" }
var read: Int
var bytesRead = 0
while (bytesRead <= 0) {
read = source.read(byteBuffer)
bytesRead += read
}
uploadDataSink.onReadSucceeded(false)
}
@Synchronized
private fun fillBuffer() {
executorService.submit {
try {
val writeSink = pipe.sink.buffer()
filled = true
body.writeTo(writeSink)
writeSink.flush()
} catch (e: IOException) {
e.printStackTrace()
}
}
}
override fun rewind(p0: UploadDataSink?) {
check(body.isOneShot()) { "Okhttp RequestBody is OneShot" }
filled = false
fillBuffer()
}
override fun close() {
pipe.cancel()
source.close()
super.close()
}
}

@ -12,7 +12,7 @@ import splitties.init.appCtx
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener { object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val isGooglePlay = appCtx.channel == "google" const val isGooglePlay = BuildConfig.isGoogle//appCtx.channel == "google"
val isCronet = appCtx.getPrefBoolean(PreferKey.cronet) val isCronet = appCtx.getPrefBoolean(PreferKey.cronet)
val useAntiAlias = appCtx.getPrefBoolean(PreferKey.antiAlias) val useAntiAlias = appCtx.getPrefBoolean(PreferKey.antiAlias)
var userAgent: String = getPrefUserAgent() var userAgent: String = getPrefUserAgent()

Loading…
Cancel
Save