2

I have an app that will be deployed to multiple customers on different sites. It uses RetroFit to communicate with the server product.

The problem is that each customer will deploy this server product on their own local server, with its own BASE_URL, so the BASE_URL cannot be hardcoded into the app. It needs to be configured per-device when deploying the app on-site, rather than having a build of the app for each customer.

I have created a Settings screen with a field to edit the BASE_URL and store it in SharedPreferences. My question is this: Is it possible to replace the BASE_URL with this value from SharedPreferences on each Call?

Actually, it doesn't have to be SharedPreferences. I just need to be able to configure the BASE_URL and store it wherever. Even storing a file on the SD card might be sufficient.

Does anyone have any suggestions? Thanks.

UPDATE: Here is my client code:

public class RestClient {
    private static RestInterface REST_CLIENT;
    private static final String API_BASE_URL = "http://myurl/";

    static {
        setupRestClient();
    }

    private RestClient() {
    }

    public static RestInterface get() {
        return REST_CLIENT;
    }

    private static void setupRestClient() {
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(API_BASE_URL)
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        REST_CLIENT = retrofit.create(RestInterface.class);
    }
}

Thanks.

eoinzy
  • 2,152
  • 4
  • 36
  • 67
  • 1
    As described in the documentation the url will usually be set in the `Retrofit.Builder` class with the method `baseUrl(String baseUrl)`. It's perfectly fine to read the url from the `SharedPreferences`. Be aware of incorrect url handling. So what is your problem? – momo Apr 14 '16 at 13:32
  • I will update with my code and you will see the problem. I am creating the `Retrofit` client statically. so I don't have access to `context`. – eoinzy Apr 14 '16 at 13:37
  • 1
    Have a look at https://gist.github.com/laaptu/feb3cae85f07c0c5fe3e and http://stackoverflow.com/questions/27816507/retrofit-multiple-endpoints-with-same-restadapter/27816635#27816635 – momo Apr 14 '16 at 14:17
  • Thanks actually. You pointed me in the right direction, by having me type out my problem!! I've slightly refactored the above code and it works perfectly. – eoinzy Apr 14 '16 at 16:21

1 Answers1

1

Here's the solution that I came to:

public class RestClient {
    private static RestInterface REST_CLIENT;
    private static final String API_BASE_URL = "http://myurl/";

    private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder();

    public static RestInterface get(@NonNull Context context) {
        if (null == REST_CLIENT) {
            setupRestClient(context);
        }
        return REST_CLIENT;
    }

    private static void setupRestClient(@NonNull Context context) {

        String baseUrl = CustomPrefs.getInstance(context).getEndpointBaseUrl();
        httpClient.addInterceptor(getInterceptorWithAuth(context));
        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(baseUrl)
                .client(httpClient.build())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

        REST_CLIENT = retrofit.create(RestInterface.class);
    }

    private static Interceptor getInterceptorWithAuth(@NonNull final Context context) {
        final String username = CustomPrefs.getInstance(context).getHttpUsername();
        final String password = CustomPrefs.getInstance(context).getHttpPassword();
        final String credentials = username + ":" + password;
        final String basic = "Basic " + Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

        return new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Request original = chain.request();

                Request.Builder requestBuilder = original.newBuilder()
                        .header("Authorization", basic)
                        .header("Accept", "application/json")
                        .header("User-Agent", "myApp")
                        .method(original.method(), original.body());

                Request request = requestBuilder.build();
                return chain.proceed(request);
            }
        };
    }
}

I also added in HTTP Basic Auth. Remove httpClient and the getInterceptorWithAuth() method if you don't need Auth.

USAGE:

call = RestClient.get(context).whateverMethod();
eoinzy
  • 2,152
  • 4
  • 36
  • 67