Android , Okhttp - how to add subprotocol to websocket connection - android

in my app I'm using OkHttp to establish Websocket connection. Here's method to start connection :
private fun start(token: String, id: String, url: String) {
val request: Request = Request
.Builder()
.url(url)
.header("Authorization", token)
.header("iD", id)
.build()
val listener = ValidationWebSocketListener
client.newWebSocket(request, listener)
client.dispatcher.executorService.shutdown()
}
However I have to add subprotocol - "websocket" . How can I achieve that ? Is it possible ?

I haven't confirmed but it should be possible with
request = Request.Builder()
.url(...)
.addHeader("Sec-WebSocket-Protocol", "graphql-ws")
...
.build();

Related

Android okhttp3 socket connection problem

Can't connect to socket server with error: java.net.ProtocolException: Expected HTTP 101 response but was '404 Not Found'.
Code:
`
private fun run() {
val client: OkHttpClient = OkHttpClient.Builder()
.readTimeout(3, TimeUnit.SECONDS)
.build()
val request: Request = Request.Builder()
.url(AppParams.SOCKET)
.build()
client.newWebSocket(request, this)
client.dispatcher.executorService.shutdown()
}
`
Url format is: "https://url.com:3003/".
The SocketIO library works correctly
Tried to remove the prefix, change the port, use another link..
You should change the link to "wss://url.com:3003/"

Can't use RapidApi with Retrofit

I'm new with Retrofit and I'm trying to use Google Translate Api from RapidApi with Retrofit but i can't convert okhttp code snippet to retrofit
This is the sample code snippet for Post request working with OkHttp:
val client = OkHttpClient()
val mediaType = MediaType.parse("application/x-www-form-urlencoded")
val body = RequestBody.create(mediaType, "q=Hello%2C%20world!&target=es")
val request = Request.Builder()
.url("https://google-translate1.p.rapidapi.com/language/translate/v2")
.post(body)
.addHeader("content-type", "application/x-www-form-urlencoded")
.addHeader("Accept-Encoding", "application/gzip")
.addHeader("X-RapidAPI-Host", "google-translate1.p.rapidapi.com")
.addHeader("X-RapidAPI-Key", API_KEY)
.build()
val response = client.newCall(request).execute()
i want to make same request with Retrofit in android
This is my api interface:
interface TranslatorApi {
#Headers(
"content-type: application/x-www-form-urlencoded",
"Accept-Encoding: application/gzip",
"X-RapidAPI-Host: google-translate1.p.rapidapi.com",
"X-RapidAPI-Key: API_KEY
)
#POST("translate/v2")
suspend fun translate(
#Body q: String,
#Query("target") target: String,
#Query("source") source: String
): Response<GoogleTranslateObject>
}

Retrofit2 can't test with localhost:8080

I am writing a Unit Test to test my API calls, using Retrofit2.
I have a mock of the server that I can launch locally (using localhost:8080)
I always receive a 403 error - Forbidden but it's working great with Postman
#Config(sdk = [28])
#RunWith(RobolectricTestRunner::class)
class MockServerTest {
private lateinit var result: Response<CacheResult>
private lateinit var api: FakeAPI
#Before
fun setUp() {
api = CompanySingleton.retrofit.create(FakeAPI::class.java)
}
#Test
fun getResult() {
runBlocking {
result = api.cache()
assertThat(result.isSuccessful, equalTo(true))
}
}
}
object CompanySingleton {
private val okHttpClient: OkHttpClient = OkHttpClient.Builder()
.addInterceptor(Interceptor { chain ->
val original = chain.request()
val requestBuilder = original
.newBuilder()
.addHeader("Content-Type", "application/json")
.addHeader("Authorization", "OAuth test")
.addHeader("x-device-id", "test")
val request = requestBuilder.build()
chain.proceed(request)
}
).build()
val retrofit: Retrofit = Retrofit.Builder()
.baseUrl("http://localhost:8080/")
.client(okHttpClient)
.addConverterFactory(GsonConverterFactory.create())
.build()
}
in my case testing with emulators I put http://10.0.2.2:8000 to access my local host
I assume that the api is being served on your laptop/pc (and postman definitely running on it can reach it using localhost). I think you should use the local IP of your laptop (e.g. 192.168.1.10) on android. Also don't forget to open 8080 port on your firewall (or simply turn it off)
When I have to test some local service, I usually use ngrok. It's simple to run, just in terminal you type:
./ngrok http 3000

Host interceptor HttpUrl.parse IllegalArguementException in latest Okhttp

I have to intercept host at run time . As my url is dynamic. below code is working fine in old okhttp3
Working with old Okhttp
class HostSelectionInterceptor #Inject constructor(val chiPrefs: ChiPrefs): Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
var request: Request = chain.request()
var host = String.format(Locale.ENGLISH, "https://%s.cognitiveintl.com",
chiPrefs.sitePrefix())
request.url().pathSegments().forEach {
host += "/$it"
}
if(host.isNotEmpty()){
val newUrl = HttpUrl.parse(host)
request = request.newBuilder().url(newUrl!!).build()
}
return chain.proceed(request)
}
}
but after upgrading it to latest version .
val newUrl = HttpUrl.parse(host) // deprecated..
HttpUrl.parse. become deprecated..
After r & d , I update my code like
val newUrl = request.url.newBuilder()
.host(host) ///crashed at this line
.build()
request = request.newBuilder()
.url(newUrl)
.build()
It give IllegalArguementException . Suggest a solution to it.
Crash :
FATAL EXCEPTION: OkHttp Dispatcher
Process: com.chi.doctorapp.dev, PID: 2906
java.lang.IllegalArgumentException: unexpected host: https://chi-dev1.cognitiveintl.com/api/doctor_app/GetProfile
at okhttp3.HttpUrl$Builder.host(HttpUrl.kt:961)
at com.chi.doctorapp.di.interceptors.HostSelectionInterceptor.intercept(HostSelectionInterceptor.kt:28)
at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.kt:100)
Replace this:
HttpUrl.parse(host)
With this:
host.toHttpUrlOrNull()
You'll need this import:
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull()
This is documented in the upgrade guide.
Using
request.url.newBuilder()
.host(host)
.build()
would be the correct way.
The reason this crashes for you, is that pass a complete url as host.
For example for the url https://subdomain.example.com/some/path
the host is subdomain.example.com
So instead try this:
class HostSelectionInterceptor #Inject constructor(val chiPrefs: ChiPrefs): Interceptor{
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
//Notice the removed "https://"
val host = String.format(Locale.ENGLISH, "%s.weburlintl.com",
chiPrefs.sitePrefix())
// This will keep the path, query parameters, etc.
val newUrl = request.url.newBuilder()
.host(host)
.build()
val newRequest = request
.newBuilder()
.url(newUrl)
.build()
return chain.proceed(newRequest)
}
}

OkHttp Websockets - Add a body when connecting to websocket

I am using the okHttp websocket library and I am successfully connecting to my websocket server, but currently I am only getting the connection id when connected. I want to send some extra info in the body, but I don't know how to add it using okHttp
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.build();
I have tried
RequestBody requestBody = new FormBody.Builder()
.add("camera_id", "e9502c54-927c-4639-a94f-8d03149c9c62")
.build();
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.method("POST", requestBody)
.build();
Request request = new Request.Builder()
.url("wss://mywebsocketurl.com")
.post(requestBody)
.build();
But it keeps returning
java.lang.IllegalArgumentException: method GET must not have a request body.
I know it's too late to answer.
The url should anyways be GET only. So i made the connection and on onOpen callback function, i send the body. It worked.
private fun initializeSocket(url: String) {
val request: Request = Request.Builder().url(url).build()
val listener = WebSocketListener()
webSocket = client!!.newWebSocket(request, listener)
client?.dispatcher()?.executorService()?.shutdown()
}
private class WebSocketListener : WebSocketListener() {
override fun onOpen(webSocket: WebSocket, response: Response?) {
val content = "{\n" +
" \"messageType\": \"INIT_CONNECTION\"\n" +
"}"
webSocket.send(content)
}
...
}

Categories

Resources