How to download PDF file with Retrofit and Kotlin coroutines?

后端 未结 3 791
长发绾君心
长发绾君心 2020-12-21 02:23

I saw topics like How to download file in Android using Retrofit library?, they use @Streaming and RxJava / callbacks.

I have Kotlin, coroutines, Retrof

3条回答
  •  北海茫月
    2020-12-21 02:46

    You can change the return type of exportPdf to Call and then check the response code. If it's ok then read the body as a stream. If it's not then try to deserialize ExportResponse. It will look something like this I guess:

    val response = restAdapter.apiRequest().execute()
    if (response.isSuccessful) {
        response.body()?.byteStream()//do something with stream
    } else {
        response.errorBody()?.string()//try to deserialize json from string
    }
    

    Update

    Here is a complete listing of my test:

    import okhttp3.HttpUrl
    import okhttp3.OkHttpClient
    import okhttp3.ResponseBody
    import retrofit2.Call
    import retrofit2.Retrofit
    import retrofit2.http.GET
    import retrofit2.http.Url
    import java.io.File
    import java.io.InputStream
    
    fun main() {
        val queries = buildQueries()
        check(queries, "http://127.0.0.1:5000/error")
        check(queries, "http://127.0.0.1:5000/pdf")
    }
    
    private fun check(queries: Queries, url: String) {
        val response = queries.exportPdf(HttpUrl.get(url)).execute()
        if (response.isSuccessful) {
            response.body()?.byteStream()?.saveToFile("${System.currentTimeMillis()}.pdf")
        } else {
            println(response.errorBody()?.string())
        }
    }
    
    private fun InputStream.saveToFile(file: String) = use { input ->
        File(file).outputStream().use { output ->
            input.copyTo(output)
        }
    }
    
    private fun buildRetrofit() = Retrofit.Builder()
        .baseUrl("http://127.0.0.1:5000/")
        .client(OkHttpClient())
        .build()
    
    private fun buildQueries() = buildRetrofit().create(Queries::class.java)
    
    interface Queries {
        @GET
        fun exportPdf(@Url url: HttpUrl): Call
    }
    

    and here is simple sever built with Flask:

    from flask import Flask, jsonify, send_file
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def hello():
        return 'Hello, World!'
    
    
    @app.route('/error')
    def error():
        response = jsonify(error=(dict(body='some error')))
        response.status_code = 400
        return response
    
    
    @app.route('/pdf')
    def pdf():
        return send_file('pdf-test.pdf')
    

    all works fine for me

    Update 2

    Looks like you have to write this in your Api:

    @FormUrlEncoded
    @Streaming // You can also comment this line.
    @POST("export-pdf/")
    fun exportPdf(
        @Field("token") token: String
    ): Call
    

提交回复
热议问题