android - Establezca la URL base dinámica usando Retrofit 2.0 y Dagger 2
kotlin mvp dagger 2 retrofit (4)
Gracias a @EpicPandaForce por tu ayuda. Si alguien se enfrenta a IllegalArgumentException, este es mi código de trabajo.
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);
}
}
Estoy tratando de realizar una acción de inicio de sesión con Retrofit 2.0 con Dagger 2
Así es como configuro la dependencia de 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;
}
Aquí está la interfaz API.
interface LoginAPI {
@GET(relative_path)
Call<Boolean> logMe();
}
Tengo tres URL base diferentes en las que los usuarios pueden iniciar sesión. Por lo tanto, no puedo establecer una URL estática al configurar la dependencia de Retrofit. Creé los métodos setUrl () y getUrl () en la clase de aplicación. Al iniciar sesión, configuro la URL en la aplicación antes de invocar la llamada API.
Yo uso la inyección perezosa para una modificación como esta
Lazy<Retrofit> retrofit
De esa manera, Dagger inyecta dependencia solo cuando puedo llamar
retrofit.get()
Esta parte funciona bien. Obtuve la url configurada para actualizar la dependencia. Sin embargo, el problema surge cuando el usuario escribe una URL de base incorrecta (por ejemplo, mywifi.domain.com), entiende que es incorrecta y la cambia (por ejemplo, mydata.domain.com). Dado que Dagger ya creó la dependencia para la actualización, no volverá a funcionar. Entonces tengo que volver a abrir la aplicación y escribir la URL correcta.
Leí diferentes publicaciones para configurar URL dinámicas en Retrofit usando Dagger. Nada realmente funcionó bien en mi caso. ¿Echo de menos algo?
La biblioteca Retrofit2 viene con una anotación
@Url
.
Puede anular
baseUrl
esta manera:
Interfaz API:
public interface UserService {
@GET
public Call<ResponseBody> profilePicture(@Url String url);
}
Y llame a la API de esta manera:
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");
Para obtener más detalles, consulte este enlace: https://futurestud.io/tutorials/retrofit-2-how-to-use-dynamic-urls-for-requests
Puede crear una instancia de un nuevo objeto utilizando el método de suministro sin ámbito.
@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;
}
}
Ahora puede cambiar la URL base al obtener baseUrlHolder del componente
App.appComponent.getBaseUrlHolder().set("https://www.changed.com");
this.loginApi = App.appComponent.getLoginApi();
El soporte para este caso de uso se eliminó en Retrofit2. La recomendación es utilizar un interceptor OkHttp en su lugar.
HostSelectionInterceptor
hecho por
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());
}
}
O bien, puede reemplazar su instancia de Retrofit (y posiblemente almacenar la instancia en un
RetrofitHolder
en el que puede modificar la instancia en sí y proporcionar el titular a través de Dagger) ...
public class RetrofitHolder {
Retrofit retrofit;
//getter, setter
}
O reutilice su instancia de Retrofit actual y piratee la nueva URL con reflexión, porque atornille las reglas.
Retrofit tiene un parámetro
baseUrl
que es
private final
, por lo tanto, solo puede acceder a él con reflexión.
Field field = Retrofit.class.getDeclaredField("baseUrl");
field.setAccessible(true);
okhttp3.HttpUrl newHttpUrl = HttpUrl.parse(newUrl);
field.set(retrofit, newHttpUrl);