11

I'm trying to set the User-Agent with React Native on Android. Did some research and it looks like I should use an okhttp Interceptor. An example that I've found explains how this should be done(Link) but then I am not sure on how to register the Interceptor.

So in order to set the User-Agent I am using this class:

public class CustomInterceptor implements Interceptor {
    @Override public Response intercept(Interceptor.Chain chain) throws IOException {
      Request originalRequest = chain.request();
      Request requestWithUserAgent = originalRequest.newBuilder()
          .removeHeader("User-Agent")
          .header("User-Agent", "Trevor")
          .build();
      return chain.proceed(requestWithUserAgent);
    }
}

Then what's left is to register the above interceptor so where it should be done? Maybe in MainActivity.java?

OkHttpClient okHttp = new OkHttpClient();
okHttp.interceptors().add(new CustomInterceptor());

I am not getting any errors when building the app so I think that the CustomInterceptor should be fine - just need to make the app use it.

UPDATE: I'm currently trying to register the interceptor in MainActivity but it won't pick it up:

public class MainActivity extends ReactActivity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    OkHttpClient client = new OkHttpClient();
    client.networkInterceptors().add(new CustomInterceptor());

  };

};
manosim
  • 3,630
  • 12
  • 45
  • 68
  • Hello @ekonstantinidis , I try using `okhttp` with `react-native` too. However I get an error when I run the command of `react-native run-android`. How did you succeed to overcome that? – efkan Jul 02 '16 at 11:56
  • I guess because of you use `okhttp` lib you didn't encounter an error. `react-native` uses `okhttp3` lib and I try to use the same lib unfortunately. – efkan Jul 02 '16 at 11:59

5 Answers5

10

None of the answers here worked for me for RN 0.63.2. I was able to get it working and in my research was able to find the (albeit very scarce) documentation for the support of this feature.

The only documentation I could find for this was this PR where someone added support for this feature (and broke the currently accepted answer). When I tried adding the interceptor as documented in the PR I got an exception related to CookieJar which I was able to find a solution to in this (unresolved ) issue.

TLDR:

Add a Java class in the same folder as your MainApplication called UserAgentInterceptor.java and place this in it:

package YOUR.PACKAGE.NAME; // <-- REPLACE ME

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;

public class UserAgentInterceptor implements Interceptor {

  public UserAgentInterceptor() {}

  @Override
  public Response intercept(Interceptor.Chain chain) throws IOException {
    Request originalRequest = chain.request();
    Request requestWithUserAgent = originalRequest.newBuilder()
      .removeHeader("User-Agent")
      .addHeader("User-Agent", "YOUR USER AGENT") // <-- REPLACE ME
      .build();

    return chain.proceed(requestWithUserAgent);
  }

}

Then create another Java class in the same folder named UserAgentClientFactory.java and place this in it:

package YOUR.PACKAGE.NAME; // <-- REPLACE ME

import com.facebook.react.modules.network.OkHttpClientFactory;
import com.facebook.react.modules.network.ReactCookieJarContainer;

import okhttp3.OkHttpClient;

public class UserAgentClientFactory implements OkHttpClientFactory {
  public OkHttpClient createNewNetworkModuleClient() {
    return new OkHttpClient.Builder()
      .cookieJar(new ReactCookieJarContainer())
      .addInterceptor(new UserAgentInterceptor())
      .build();
  }
}

Then in your MainApplication onCreate method register the factory like this:

...
import com.facebook.react.modules.network.OkHttpClientProvider;
...

@Override
public void onCreate() {
  super.onCreate();

  OkHttpClientProvider.setOkHttpClientFactory(new UserAgentClientFactory());

  // Your other code stuffs

}

And that's it!

KX Jaw
  • 141
  • 1
  • 7
harryisaac
  • 1,121
  • 1
  • 10
  • 18
7

So I've finally figured it out. Here is the solution for overriding the User-Agent of okhttp3 with React Native.

Create a file called CustomInterceptor.java:

package com.trevor;

import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;

import java.io.IOException;

public class CustomInterceptor implements Interceptor {

    public CustomInterceptor() {}

    @Override
    public Response intercept(Interceptor.Chain chain) throws IOException {
        Request originalRequest = chain.request();
        Request requestWithUserAgent = originalRequest.newBuilder()
            .removeHeader("User-Agent")
            .addHeader("User-Agent", "Trevor")
            .build();

        return chain.proceed(requestWithUserAgent);
    }

}

Then in MainActivity.java override the onCreate method:

...
import com.facebook.react.modules.network.OkHttpClientProvider;
...

public class MainActivity extends ReactActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        attachInterceptor();
    }

    private void attachInterceptor() {
        OkHttpClient client = OkHttpClientProvider.getOkHttpClient();
        client.networkInterceptors().add(new CustomInterceptor());
    }
}

Note that I'm importing com.facebook.react.modules.network.OkHttpClientProvider; and overriding that client instead of creating a vanilla OkHttpClient since this is the one that React Native will use.

odemolliens
  • 2,581
  • 2
  • 32
  • 34
manosim
  • 3,630
  • 12
  • 45
  • 68
  • 1
    This answer no longer works in the latest version of RN. This is the current answer: https://stackoverflow.com/a/66163168/1795671 – harryisaac Feb 12 '21 at 12:09
5

React Native is iterating so quickly that the accepted answer didn't work for me.

For RN 0.27.2 I had to import okhttp3.OkHttpClient in my CustomInterceptor and change the attachInterceptor() method in MainActivity to replace the client.

private void attachInterceptor() {
    OkHttpClient currentClient = OkHttpClientProvider.getOkHttpClient();
    OkHttpClient replacementClient = currentClient.newBuilder().addNetworkInterceptor(new CustomInterceptor()).build();
    OkHttpClientProvider.replaceOkHttpClient(replacementClient);
}

Everything else from ekonstantinidis's answer works for me.

Steven
  • 1,670
  • 4
  • 17
  • 26
3

Old issue, but we still ran into the same problem with React Native 0.59. This is what we did to fix (in Kotlin), as recent versions of okhttp prevent (and throw an exception) when trying to add an interceptor to an already initialized client:

import android.os.Build
import com.facebook.react.modules.network.OkHttpClientFactory
import com.jaredrummler.android.device.DeviceName
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response

class UserAgentInterceptor(val userAgent: String): Interceptor {
    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()

        val correctRequest = originalRequest.newBuilder()
                .removeHeader("User-Agent")
                .addHeader("User-Agent", userAgent)
                .build()
        return chain.proceed(correctRequest)
    }
}

class UserAgentClientFactory(val appName: String, val appVersion: String, val buildNumber: String): OkHttpClientFactory {
    private fun userAgentValue(): String {
        val deviceName = DeviceName.getDeviceName()
        val osVersion = Build.VERSION.RELEASE
        return "$appName/$appVersion (build: $buildNumber; device: $deviceName; OS: Android $osVersion)"
    }

    override fun createNewNetworkModuleClient(): OkHttpClient {
        val builder = com.facebook.react.modules.network.OkHttpClientProvider.createClientBuilder()
        return builder.addInterceptor(UserAgentInterceptor(userAgent = userAgentValue())).build()
    }
}

This was done in a shared library between 2 apps, thus why we passed in the app name, version, and build number.

Usage from the app itself looked like:

private fun configureUserAgent() {
    val versionName = BuildConfig.VERSION_NAME
    val versionCode = BuildConfig.VERSION_CODE
    OkHttpClientProvider.setOkHttpClientFactory(UserAgentClientFactory(appName = "My App", appVersion = versionName, buildNumber = "$versionCode"))
}

This was called from the onCreate method in the main activity of the app.

Hope this helps!

benkraus
  • 707
  • 1
  • 9
  • 15
0

I've implemented this functionality using OkHttp and my code is pretty the same as yours - and everything works fine.

Consider using addHeader("User-Agent", "Trevor") instead of header("User-Agent", "Trevor"), because the latter will replace all of already set headers.

I'm using okHttp.networkInterceptors().add(new CustomInterceptor()); instead of okHttp.interceptors().add(new CustomInterceptor());, but I don't think it's a matter of concern here.

Update I do it in onCreate() method too. Everything works as it should.

Vitaly Zinchenko
  • 4,871
  • 5
  • 36
  • 52
  • That sounds right! What I'm looking for is a way to register that Interceptor. Should I do that in the `MainActivity` overriding `onCreate` and how? I've added an example on the question. – manosim Feb 01 '16 at 19:57