Search code examples
javaandroidgoogle-chromekotlincronet

How to send json object as post request in CRONET?


I am developing android application in which i send data to server using cronet now i want to send data to server in json object but not know how to send in object?

Following is my snippet code for GET method (WORKING).

Can anyone share how to use POST Method in android cronet ?

Dependencies

 implementation 'org.chromium.net:cronet-embedded:71.3578.98'

MainActivity

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import org.chromium.net.CronetEngine
import java.util.concurrent.Executors

class MainActivity : AppCompatActivity() {

    companion object {
        // Web page url
        private const val JSON_PLACEHOLDER_API_URL = "https://jsonplaceholder.typicode.com/todos/1"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // Build a Cronet engine
        val cronetEngine =
            CronetEngine.Builder(this)
                .enableBrotli(true)
                .build()

        // Build the request
        val request =
            cronetEngine.newUrlRequestBuilder(
                JSON_PLACEHOLDER_API_URL,
                RequestCallback(),
                Executors.newSingleThreadExecutor()
            ).build()

        // Start the request
        request.start()
    }
}

RequestCallback

import android.util.Log
import org.chromium.net.CronetException
import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo
import java.nio.ByteBuffer
import java.nio.charset.Charset


/**
 * Different methods are invoked for different response status
 */

class RequestCallback : UrlRequest.Callback() {

    companion object {
        // Log cat tag
        private val TAG = RequestCallback::class.java.simpleName
    }

    override fun onResponseStarted(request: UrlRequest?, info: UrlResponseInfo?) {
        Log.i(TAG, "Response Started")
        val statusCode = info?.httpStatusCode
        Log.i(TAG, "Status Code $statusCode")
        if (statusCode == 200) {
            // Read the buffer
            request?.read(ByteBuffer.allocateDirect(32 * 1024))
        }
    }

    override fun onReadCompleted(request: UrlRequest?, info: UrlResponseInfo?, byteBuffer: ByteBuffer?) {
        Log.i(TAG, "Response Completed")

        // Flip the buffer
        byteBuffer?.flip()

        // Convert the byte buffer to a string
        byteBuffer?.let {
            val byteArray = ByteArray(it.remaining())
            it.get(byteArray)
            String(byteArray, Charset.forName("UTF-8"))
        }.apply {
            Log.d(TAG, "Response: $this")
        }

        // Clear the buffer
        byteBuffer?.clear()

        // Read the buffer
        request?.read(byteBuffer)
    }

    override fun onFailed(request: UrlRequest?, info: UrlResponseInfo?, error: CronetException?) {
        Log.e(TAG, "Response Failed: ${error?.message}")
    }

    override fun onSucceeded(request: UrlRequest?, info: UrlResponseInfo?) {
        Log.i(TAG, "Response Succeeded")
    }

    override fun onRedirectReceived(request: UrlRequest?, info: UrlResponseInfo?, newLocationUrl: String?) {
        Log.i(TAG, "Response Redirect to $newLocationUrl")
        request?.followRedirect()
    }

    override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
        super.onCanceled(request, info)
        Log.i(TAG, "Response cancelled")
    }
}

Output

Response: {
      "userId": 1,
      "id": 1,
      "title": "delectus aut autem",
      "completed": false
    }

Solution

  • Example:

        val myBuilder = CronetEngine.Builder(context)
        // Enable caching of HTTP data and
        // other information like QUIC server information, HTTP/2 protocol and QUIC protocol.
        val cronetEngine: CronetEngine = myBuilder
            .enableHttpCache(CronetEngine.Builder.HTTP_CACHE_IN_MEMORY, 100 * 1024.toLong())
            .enableHttp2(true)
            .enableQuic(true)
            .build()
        val executor: Executor = Executors.newSingleThreadExecutor()
        val requestBuilder = cronetEngine.newUrlRequestBuilder(
            "FULL-URL",
            MyUrlRequestCallback(),
            executor
        )
        // Content-Type is required, removing it will cause Exception
        requestBuilder.addHeader("Content-Type","application/json; charset=UTF-8")
        requestBuilder.setHttpMethod("POST")
        val myUploadDataProvider = MyUploadDataProvider()
        requestBuilder.setUploadDataProvider(myUploadDataProvider,executor)
        val request: UrlRequest = requestBuilder.build()
        request.start()
    

    MyUploadDataProvider Class:

    import android.util.Log
    import org.chromium.net.UploadDataProvider
    import org.chromium.net.UploadDataSink
    import java.lang.Exception
    import java.nio.ByteBuffer
    import java.nio.charset.StandardCharsets
    
    private const val TAG = "MyUploadDataProvider"
    //TODO replace username and passowrd "_user & _pass"
    var string: String ="{\"username\":\"_user\",\"password\":\"_pass\"}"
    val charset = StandardCharsets.UTF_8
    
    class MyUploadDataProvider() : UploadDataProvider() {
    
        override fun getLength(): Long {
        val size:Long = string.length.toLong()
        Log.e(TAG,"Length = "+size)
        return size
        }
    
        override fun rewind(uploadDataSink: UploadDataSink?) {
        Log.e(TAG,"REWIND IS CALLED")
        uploadDataSink!!.onRewindSucceeded()
        }
    
        override fun read(uploadDataSink: UploadDataSink?, byteBuffer: ByteBuffer?) {
        Log.e(TAG,"READ IS CALLED")
        byteBuffer!!.put(string.toByteArray(charset))
        //byteBuffer.rewind()
        //For chunked uploads, true if this is the final read. It must be false for non-chunked uploads.
        uploadDataSink!!.onReadSucceeded(false)
        }
    
    }