web-dev-qa-db-fra.com

Définir l'URL de base dynamique à l'aide de Retrofit 2.0 et Dagger 2

J'essaie d'effectuer une action de connexion à l'aide de Retrofit 2.0 à l'aide de Dagger 2

Voici comment j'ai mis en place la dépendance Retrofit

@Provides
@Singleton
Retrofit provideRetrofit(Gson gson, OkHttpClient client) {
    Retrofit retrofit = new Retrofit.Builder()
                            .addConverterFactory(GsonConverterFactory.create(gson)
                            .client(client)
                            .baseUrl(application.getUrl())
                            .build();
    return retrofit;     
}

Voici l'interface de l'API.

interface LoginAPI {
   @GET(relative_path)
   Call<Boolean> logMe();
}

J'ai trois différentes URL de base auxquelles les utilisateurs peuvent se connecter. Je ne peux donc pas définir d'URL statique lors de la configuration de la dépendance de modification. J'ai créé une méthode setUrl () et getUrl () sur la classe Application. Lors de la connexion de l'utilisateur, j'ai défini l'URL sur Application avant d'appeler l'appel de l'API.

J'utilise l'injection paresseuse pour la rénovation comme ça

Lazy<Retrofit> retrofit

De cette façon, Dagger injecte la dépendance uniquement lorsque je peux appeler

retrofit.get()

Cette partie fonctionne bien. J'ai eu l'URL définie pour améliorer la dépendance. Cependant, le problème se pose lorsque l'utilisateur tape une mauvaise URL de base (par exemple, mywifi.domain.com), comprend que c'est la mauvaise et la modifie (dites à mydata.domain.com). Comme Dagger a déjà créé la dépendance pour la modernisation, cela ne se reproduira plus. Je dois donc rouvrir l'application et taper l'URL correcte.

J'ai lu différents articles sur la configuration d'URL dynamiques sur Retrofit à l'aide de Dagger. Rien n'a vraiment bien fonctionné dans mon cas. Est-ce que je manque quelque chose?

43
Renjith

La prise en charge de ce cas d'utilisation a été supprimée dans Retrofit2. Il est recommandé d'utiliser un intercepteur OkHttp à la place.

HostSelectionInterceptorfaite par swankjesse

import Java.io.IOException;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;

/** An interceptor that allows runtime changes to the URL hostname. */
public final class HostSelectionInterceptor implements Interceptor {
  private volatile String Host;

  public void setHost(String Host) {
    this.Host = Host;
  }

  @Override public okhttp3.Response intercept(Chain chain) throws IOException {
    Request request = chain.request();
    String Host = this.Host;
    if (Host != null) {
      //HttpUrl newUrl = request.url().newBuilder()
      //    .Host(host)
      //    .build();
      HttpUrl newUrl = HttpUrl.parse(Host);
      request = request.newBuilder()
          .url(newUrl)
          .build();
    }
    return chain.proceed(request);
  }

  public static void main(String[] args) throws Exception {
    HostSelectionInterceptor interceptor = new HostSelectionInterceptor();

    OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(interceptor)
        .build();

    Request request = new Request.Builder()
        .url("http://www.coca-cola.com/robots.txt")
        .build();

    okhttp3.Call call1 = okHttpClient.newCall(request);
    okhttp3.Response response1 = call1.execute();
    System.out.println("RESPONSE FROM: " + response1.request().url());
    System.out.println(response1.body().string());

    interceptor.setHost("www.pepsi.com");

    okhttp3.Call call2 = okHttpClient.newCall(request);
    okhttp3.Response response2 = call2.execute();
    System.out.println("RESPONSE FROM: " + response2.request().url());
    System.out.println(response2.body().string());
  }
}

Ou vous pouvez soit remplacer votre instance Retrofit (et éventuellement stocker l’instance dans un RetrofitHolder dans lequel vous pouvez modifier l’instance elle-même et fournir le titulaire via Dagger) ...

public class RetrofitHolder {
   Retrofit retrofit;

   //getter, setter
}

Ou réutilisez votre instance de modification actuelle et piratez la nouvelle URL avec réflexion, car respectez les règles. La conversion a un paramètre baseUrl qui est private final, vous ne pouvez donc y accéder qu’avec réflexion.

Field field = Retrofit.class.getDeclaredField("baseUrl");
field.setAccessible(true);
okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl);
field.set(retrofit, newHttpUrl);
44
EpicPandaForce

La bibliothèque Retrofit2 est livrée avec un @Url annotation. Vous pouvez remplacer baseUrl comme ceci:

Interface API:

public interface UserService {  
    @GET
    public Call<ResponseBody> profilePicture(@Url String url);
}

Et appelez l'API comme ceci:

Retrofit retrofit = Retrofit.Builder()  
    .baseUrl("https://your.api.url/");
    .build();

UserService service = retrofit.create(UserService.class);  
service.profilePicture("https://s3.Amazon.com/profile-picture/path");

Pour plus de détails, consultez ce lien: https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests

41
Jaydev Mehta

Merci à @EpicPandaForce pour son aide. Si quelqu'un fait face à IllegalArgumentException, c'est mon code de travail.

public class HostSelectionInterceptor implements Interceptor {
    private volatile String Host;

    public void setHost(String Host) {
        this.Host = HttpUrl.parse(Host).Host();
    }

    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        String reqUrl = request.url().Host();

        String Host = this.Host;
        if (Host != null) {
            HttpUrl newUrl = request.url().newBuilder()
                .Host(host)
                .build();
            request = request.newBuilder()
                .url(newUrl)
                .build();
        }
        return chain.proceed(request);
    }
}
2
indra

Vous êtes en mesure d'instancier un nouvel objet à l'aide de la méthode supply sans portée.

@Provides
LoginAPI provideAPI(Gson gson, OkHttpClient client, BaseUrlHolder baseUrlHolder) {
    Retrofit retrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)
                        .client(client)
                        .baseUrl(baseUrlHolder.get())
                        .build();
    return retrofit.create(LoginAPI.class);     
}

@AppScope
@Provides
BaseUrlHolder provideBaseUrlHolder() {
    return new BaseUrlHolder("https://www.default.com")
}


public class BaseUrlHolder {
    public String baseUrl;

    public BaseUrlHolder(String baseUrl) {
        this.baseUrl = baseUrl;
    }

    public String getBaseUrl() {
        return baseUrl;
    }

    public void setBaseUrl(String baseUrl) {
        this.baseUrl = baseUrl;
    }
}

Maintenant, vous pouvez changer l’URL de base en obtenant baseUrlHolder du composant

App.appComponent.getBaseUrlHolder().set("https://www.changed.com");
this.loginApi = App.appComponent.getLoginApi();
2
yoAlex5