@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user