Merge pull request #2731 from ag2s20150909/master

Cronet支持上传大文件
master
kunfei 2 years ago committed by GitHub
commit e99fa33d3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  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_Main_Version", "\"$CronetMainVersion\""
buildConfigField "boolean", "isGoogle", "false"
javaCompileOptions {
annotationProcessorOptions {
@ -104,6 +105,7 @@ android {
dimension "mode"
applicationId "io.legado.play"
manifestPlaceholders.put("APP_CHANNEL_VALUE", "google")
buildConfigField "boolean", "isGoogle", "true"
}
}
compileOptions {

@ -13,9 +13,18 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
private val buffer = Buffer()
@Volatile
private var filled: Boolean = false
init {
fillBuffer()
}
private fun fillBuffer() {
try {
buffer.clear()
body.writeTo(buffer)
buffer.flush()
} catch (e: IOException) {
e.printStackTrace()
}
@ -28,6 +37,9 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
@Throws(IOException::class)
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
@ -40,8 +52,9 @@ class BodyUploadProvider(private val body: RequestBody) : UploadDataProvider(),
@Throws(IOException::class)
override fun rewind(uploadDataSink: UploadDataSink) {
buffer.clear()
body.writeTo(buffer)
check(body.isOneShot()) { "Okhttp RequestBody is oneShot" }
filled = false
fillBuffer()
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 org.chromium.net.CronetEngine.Builder.HTTP_CACHE_DISK
import org.chromium.net.ExperimentalCronetEngine
import org.chromium.net.UploadDataProvider
import org.chromium.net.UrlRequest
import org.json.JSONObject
import splitties.init.appCtx
internal const val BUFFER_SIZE = 32 * 1024
val cronetEngine: ExperimentalCronetEngine? by lazy {
if (!AppConfig.isGooglePlay) {
CronetLoader.preDownload()
@ -85,10 +88,14 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
} else {
addHeader("Content-Type", "text/plain")
}
setUploadDataProvider(
BodyUploadProvider(requestBody),
okHttpClient.dispatcher.executorService
)
val provider: UploadDataProvider = if (requestBody.contentLength() > BUFFER_SIZE) {
LargeBodyUploadProvider(requestBody, 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")
object AppConfig : SharedPreferences.OnSharedPreferenceChangeListener {
val isGooglePlay = appCtx.channel == "google"
const val isGooglePlay = BuildConfig.isGoogle//appCtx.channel == "google"
val isCronet = appCtx.getPrefBoolean(PreferKey.cronet)
val useAntiAlias = appCtx.getPrefBoolean(PreferKey.antiAlias)
var userAgent: String = getPrefUserAgent()

Loading…
Cancel
Save