Skip to content

Commit

Permalink
1.完善README.md
Browse files Browse the repository at this point in the history
  • Loading branch information
Tears丶残阳 committed Jun 13, 2023
1 parent 9dfd652 commit ee49e15
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 76 deletions.
94 changes: 94 additions & 0 deletions FILE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
### 文件上传/下载
* 通过`OkHttp`的拦截器实现的下载、上传断点续传功能,同时支持`OkHttp``Retrofit`

* 断点续传
- 无需额外的操作,默认即支持下载的断点续传;
- 当文件存在时,并且与响应信息中的文件大小一致时,不会重复下载文件;
- 当文件错误时,或无法从响应信息中获取到文件信息时,完整的下载并覆盖原文件;
- 当文件只有一部分时,会下载剩余的部分数据,并追加到文件中。

### OkHttp

##### 安装方法
* 在构建`OkHttpClient`时,添加[`BreakpointResumeInterceptor`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/okhttp/file/BreakpointResumeInterceptor.kt)拦截器。

##### 使用方法
* 指定文件的位置可以用`tag(Class<T>, T)`方法向请求实例中添加一个`File`实例,此参数可以是一个文件,也可以是一个目录:
-`File`参数是文件时,下载的数据会写入到该文件中
-`File`参数是目录时,会自动从响应信息或请求信息中获取文件名,并在该目录下创建一个文件,下载的数据会写入到该文件中

```kotlin
val file = File("文件或存放目录")
val request = Request.Builder()
.tag(File::Class.java, file)
...
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful) {
TODO("操作file即可,下载的数据已写入file文件中或目录下")
}
```

### Retrofit

##### 安装方法
* 在构建`OkHttpClient`时,添加[`BreakpointResumeInterceptor`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/okhttp/file/BreakpointResumeInterceptor.kt)拦截器。
* 在构建`Retrofit`时,添加[`FileConverter`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/retrofit/FileConverter.kt)转换器。

##### 使用方法
* 在接口中使用`@Tag`注解标记一个`File`类型的参数用于指定要写入的文件或存放目录

```kotlin
interface FileApi {

/**
* url 文件的下载地址
* fileOrDir 要写入的文件或存放目录
* callback 下载进度的监听接口
* */
@GET
@Streaming
suspend fun download(@Url url: String, @Tag fileOrDir: File, @Tag callback: DlProgressCallback): File
}

// 创建API接口的实例
val fileApi = retrofit.create<FileApi>()
// 创建参数实例
val downloadUrl = "文件的下载地址"
val file = File("文件位置或存放目录")
val callback = DlProgressCallback { progress ->
TODO("处理下载进度")
}
// 请求网络,注:添加`FileConverter`后,可使用File类型直接接收文件
val file = fileApi.download(downloadUrl, file, callback)
TODO("处理file文件")
```

#### 上传断点续传
* 上传的断点续传需要服务端的支持,一般的处理逻辑如下:
1. app端计算文件的`MD5`值;
2.`MD5`值提交到服务器,服务器返回`已存在的文件长度`等信息;
3. app将文件转为输入流,并忽略服务器上已存在的长度,将剩余的数据提交到服务器。
* 鉴于服务端的实现各有不同,所以此处只提供基于`Retrofit`的部分的逻辑,剩余逻辑请自行处理。
* 处理方法参考如下:
```kotlin
val file = File("要上传的文件路径")
//获取文件的MD5值
val fileMd5 = file.getMd5()
//将MD5值提交到服务器查询服务器上已存在的数据长度
val existLength: Long = uploadApi.getExistLength(fileMd5)
//创建上传进度监听器
val upProgressCallback = UpProgressCallback { progress ->
TODO("处理上传进度")
}
val mediaType = TODO("获取MediaType.")
if(existLength <= 0) {
//正常上传
val requestBody = file.asRequestBody(mediaType)
uploadApi.upload(requestBody, upProgressCallback)
} else {
//断点续传,忽略掉前existLength的数据
val fileBytes = file.readBytes()
val requestBody = fileBytes.toRequestBoey(mediaType, existLength.toInt(), fileBytes.size - existLength.toInt())
uploadApi.upload(file, ContinuableUpProgressCallback(existLength, upProgressCallback))
}
```
106 changes: 38 additions & 68 deletions PROGRESS.md
Original file line number Diff line number Diff line change
@@ -1,92 +1,62 @@
### 下载进度监听
* 通过`OkHttp`的拦截器实现的下载、上传进度监听功能,同时支持断点续传,并且免去IO的操作过程,同时支持`OkHttp``Retrofit`
### 下载/上传进度监听
* 通过`OkHttp`的拦截器实现的下载、上传进度监听功能,同时支持`OkHttp``Retrofit`

#### 安装方法
*[`ProgressInterceptor`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/okhttp/ProgressInterceptor.kt)
添加到`OkHttpClient`中即可。
### `OkHttpClient`的使用方法

##### `OkHttpClient`的使用方法
* 在构建`Request`对象时,构建一个`DlProgressCallback`实例,并使用`tag(Class<T>, T)`方法添加到`Request.Builder`实例当中。
* 指定文件的位置可以用`tag(Class<T>, T)`方法向请求实例中添加一个`File`实例,此参数可以是一个文件,也可以是一个目录:
`File`参数是文件时,下载的数据会写入到该文件中
`File`参数是目录时,会自动从响应信息或请求信息中获取文件名,并在该目录下创建一个文件,下载的数据会写入到该文件中
##### 安装方法
*[`ProgressInterceptor`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/okhttp/file/ProgressInterceptor.kt)
添加到`OkHttpClient`中即可。

##### 监听下载进度
1. 在构建`Request`对象时,构建一个`DlProgressCallback`实例,并通过`tag(Class<T>, T)`方法添加到`Request.Builder`中。
2. 在下载文件或请求网络时,服务器数据传输到本地时会调用该回调实例的`update`方法,参数是一个`float`值,可通过`(progress * 100).toInt()`来得到下载进度的百分比。
3. 注意:`update`方法运行在子线程中(与`Interceptor.intercept`方法的调用线程一致)。
```kotlin
val file = File(TODO("文件或存放目录"))
val request = Request.Builder()
.tag(DlProgressCallback::class.java, DlProgressCallback {
.tag(DlProgressCallback::class.java, DlProgressCallback { progress ->
val percent = (progress * 100).toInt()
TODO("处理下载进度监听")
})
.tag(File::Class.java, file)
...
val response = okHttpClient.newCall(request).execute()
if (response.isSuccessful) {
TODO("处理file即可,无需处理IO操作")
}
```
#### `Retrofit`的使用方法

##### 安装方法

*`OkHttpClient`的安装方法
* 在构建`Retrofit`时,添加`FileConverterFactory`转换器,以支持在`Api接口`中支持声明`File`类型的返回结果
##### 监听上传进度
1. 上传进度则构建一个`UpProgressCallback`实例,并通过`tag(Class<T>, T)`方法添加到`Request.Builder`中。
2. 在上传文件或请求网络时,本地数据传输到服务器时会调用该回调实例的`update`方法,参数是一个`float`值,可通过`(progress * 100).toInt()`来得到下载进度的百分比。
3. 注意:`update`方法运行在子线程中(与`Interceptor.intercept`方法的调用线程一致)。
```kotlin
val request = Request.Builder()
.tag(UpProgressCallback::class.java, UpProgressCallback { progress ->
val percent = (progress * 100).toInt()
TODO("处理上传进度监听")
})
...
```

#### 使用方法
### `OkHttpClient`的使用方法

* 使用`@Tag`注解标记一个`DlProgressCallback`类型的参数用于处理进度监听
* 使用`@Tag`注解标记一个`File`类型的参数用于指定要写入的文件或存放目录
#### `Retrofit`的安装方法
* 参考`OkHttpClient`的安装方法,向`OkHttpClient`中添加[`ProgressInterceptor`](https://github.com/xiazunyang/http/blob/master/http/src/main/kotlin/cn/numeron/okhttp/file/ProgressInterceptor.kt)监听器,并添加到`Retrofit`中。

##### 监听下载进度
1. 在声明的接口中添加`DlProgressCallback`类型的参数,并标记`@Tag`注解。
2. 在调用该接口时,创建`DlProgressCallback`实例,并作为参数传递给该接口中即可。
```kotlin
/**
* url 文件的下载地址
* fileOrDir 要写入的文件或存放目录
* callback 下载进度的监听接口
* */
@GET
@Streaming
suspend fun download(@Url url: String, @Tag fileOrDir: File, @Tag callback: DlProgressCallback): File
suspend fun download(@Url url: String, @Tag callback: DlProgressCallback): Call<ResponseBody>
```
#### 下载断点续传
* 无需额外的操作,默认即支持下载的断点续传;
* 当文件存在时,并且与响应信息中的文件信息吻合时,不会重复下载文件;
* 当文件错误时,或无法从响应信息中获取到文件信息时,完整的下载并覆盖原文件;
* 当文件只有一部分时,会下载剩余的部分数据,并添加到文件中。

### 上传进度监听
* 适用于`OkHttpClient``Retrofit`的上传进度监听监听

#### 安装方法
* 同下载部分,支持下载进度监听的同时支持上传进度监听,无需另外安装
##### 监听上传进度
1. 在声明的接口中添加`UpProgressCallback`类型的参数,并标记`@Tag`注解。
2. 在调用该接口时,创建`UpProgressCallback`实例,并作为参数传递给该接口中即可。

#### 使用方法
* 同下载部分,只需要把`DlProgressCallback`换成`UpProgressCallback`即可。

#### 上传断点续传
* 上传的断点续传需要服务端的支持,一般的操作逻辑如下:
1. app端计算文件的`MD5`值;
2.`MD5`值提交到服务器,服务器返回`已存在的文件长度`等信息;
3. app将文件转为输入流,并忽略服务器上已存在的长度,将剩余的数据提交到服务器。
* 鉴于服务端的实现各有不同,所以此处只提供上传进度的回调监听,剩余逻辑请自行处理。
* 处理方法参考如下:
```kotlin
val file = File(TODO("要上传的文件路径"))
//获取文件的MD5值
val fileMd5 = file.getMd5()
//将MD5值提交到服务器查询服务器上已存在的数据长度
val existLength: Long = uploadApi.getExistLength(fileMd5)
//声明上传进度监听器
val upProgressCallback = UpProgressCallback {
TODO("处理上传进度")
}
val mediaType = TODO("获取MediaType.")
if(existLength < 0) {
//正常上传
val requestBody = file.asRequestBody(mediaType)
uploadApi.upload(requestBody, upProgressCallback)
} else {
//断点续传,忽略掉前existLength的数据
val fileBytes = file.readBytes()
val requestBody = fileBytes.toRequestBoey(mediaType, existLength.toInt(), fileBytes.size - existLength.toInt())
uploadApi.upload(file, ContinuableUpProgressCallback(existLength, upProgressCallback))
}
```
@POST
@Streaming
suspend fun upload(@Url url: String, @Tag callback: UpProgressCallback): Call<Unit>
```
12 changes: 9 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ allprojects {
implementation 'cn.numeron:http:latest_version'
```

#### 进度回调和断点续传
#### 进度回调
* 通过`OkHttp`的拦截器实现的下载、上传进度监听功能
* 同时支持断点续传
* 免去IO的操作过程
* 支持`OkHttp``Retrofit`

[点击此处](https://github.com/xiazunyang/http/blob/master/PROGRESS.md) 查看文档

#### 文件上传/下载
* 通过`OkHttp`的拦截器实现的下载、上传进度监听功能
* 同时支持断点续传
* 无需IO操作过程
* 支持`OkHttp``Retrofit`

[点击此处](https://github.com/xiazunyang/http/blob/master/FILE.md) 查看文档

#### Oauth授权管理
* 适用于`Oauth2`授权的APP端token管理工具
* 可添加其它请求头
Expand Down
4 changes: 2 additions & 2 deletions http/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ plugins {
id("com.github.dcendents.android-maven")
}

group = "com.github.xiazunyang"
version = "1.0.7"
group = "cn.numeron"
version = "1.0.8"

tasks.withType<KotlinCompile> {
kotlinOptions {
Expand Down
6 changes: 3 additions & 3 deletions http/src/main/kotlin/cn/numeron/retrofit/FileConverter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ class FileConverter : Converter<ResponseBody, File> {
return if (responseBody is FileResponseBody) {
responseBody.file
} else try {
val declaredField = responseBody::class.java.getDeclaredField("delegate")
declaredField.isAccessible = true
val delegate = declaredField.get(responseBody) as ResponseBody
val field = responseBody.javaClass.getDeclaredField("delegate")
field.isAccessible = true
val delegate = field.get(responseBody) as ResponseBody
getFile(delegate)
} catch (throwable: Throwable) {
throw RuntimeException("响应体中没有记录文件信息!或者没有使用Tag标记File类型的参数!", throwable)
Expand Down

0 comments on commit ee49e15

Please sign in to comment.