在Android运行时切换Retrofit Base URL:简化开发环境与生产环境的切换

科技   2024-07-03 09:29   浙江  

在Android运行时切换Retrofit Base URL:简化开发环境与生产环境的切换

在Android开发中,Retrofit是一个由Square开发的类型安全的HTTP客户端库。它为API认证和网络请求提供了一个强大的框架。然而,在开发过程中,我们常常需要在不同的环境(如开发环境和生产环境)之间切换Base URL,这一操作在过去通常需要多个Retrofit实例,非常繁琐。本文将介绍一种通过使用Interceptor来在运行时动态切换Retrofit Base URL的简便方法。

引言

当我们使用Retrofit进行网络请求时,通常会在初始化时设置默认的Base URL:

return new Retrofit.Builder()
            .client(okHttpClient)
            .baseUrl(BuildConfig.PRODUCTION_BASE_URL)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .build();

虽然这种方式简单直接,但在需要切换Base URL时会变得复杂。为了避免维护多个Retrofit实例,我们可以使用Interceptor来动态更改Base URL。接下来,我们将详细介绍这种实现方法。

依赖配置

首先,在项目的build.gradle文件中添加所需的依赖:

ext {
      okHttpVersion ="4.8.1"
      retrofitVersion ="2.9.0"
      hiltVersion ="2.38.1"
}

dependencies{
// OkHttp
    implementation "com.squareup.okhttp3:okhttp:$rootProject.okHttpVersion"
    implementation "com.squareup.okhttp3:logging-interceptor:$rootProject.okHttpVersion"

// Retrofit2
    implementation "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$rootProject.retrofitVersion"
    implementation "com.github.akarnokd:rxjava3-retrofit-adapter:3.0.0"
    implementation "com.squareup.retrofit2:converter-protobuf:$rootProject.retrofitVersion"

// Hilt
    implementation "com.google.dagger:hilt-android:$rootProject.hiltVersion"
    annotationProcessor "com.google.dagger:hilt-android-compiler:$rootProject.hiltVersion"
    annotationProcessor 'androidx.hilt:hilt-compiler:1.0.0'
}

实现Shared Preferences管理器

为了管理当前环境的选择状态,我们需要创建一个Shared Preferences管理器(PreferenceHelper),用于读取和写入当前环境选择状态:

public classPreferenceHelper{

privateSharedPreferences sharedPreferences;

@Inject
publicPreferenceHelper(Context context){
        sharedPreferences = context.getSharedPreferences("AppPrefs",Context.MODE_PRIVATE);
}

// 存储环境状态
publicvoidsetProdEnvironmentStatus(boolean status){
        sharedPreferences.edit().putBoolean("isProd", status).apply();
}

// 获取环境状态
publicbooleanisProdEnvironment(){
return sharedPreferences.getBoolean("isProd",false);
}
}

创建HostSelectionInterceptor

接下来,我们创建一个Interceptor来处理环境切换的工作:

@Singleton
publicclassHostSelectionInterceptorimplementsInterceptor{
privatevolatileHttpUrlhost=HttpUrl.parse(BuildConfig.DEVELOPMENT_BASE_URL);
privatefinalPreferenceHelper preferenceHelper;

@Inject
publicHostSelectionInterceptor(PreferenceHelper preferenceHelper){
this.preferenceHelper = preferenceHelper;
        setHostBaseUrl();
}

publicvoidsetHostBaseUrl(){
if(preferenceHelper.isProdEnvironment()){
this.host =HttpUrl.parse(BuildConfig.PRODUCTION_BASE_URL);
}else{
this.host =HttpUrl.parse(BuildConfig.DEVELOPMENT_BASE_URL);
}
}

@NotNull
@Override
public okhttp3.Responseintercept(Chain chain)throwsIOException{
Requestrequest= chain.request();
if(host !=null){
HttpUrl newUrl;
try{
                newUrl = request.url().newBuilder()
.scheme(host.scheme())
.host(host.url().toURI().getHost())
.build();
}catch(URISyntaxException e){
thrownewIOException(e);
}
            request = request.newBuilder().url(newUrl).build();
}
return chain.proceed(request);
}
}

配置Retrofit和OkHttpClient

然后,我们需要在提供Retrofit实例时注入HostSelectionInterceptor:

@Module
@InstallIn(SingletonComponent.class)
publicclassNetworkModule{

@Provides
@Singleton
publicRetrofitprovideRetrofitClient(ProtoConverterFactory protoConverterFactory, RxJava3CallAdapterFactory rxJava3CallAdapterFactory, OkHttpClient okHttpClient){
returnnewRetrofit.Builder()
.client(okHttpClient)
.baseUrl(BuildConfig.DEVELOPMENT_BASE_URL)// 默认Base URL
.addConverterFactory(protoConverterFactory)
.addCallAdapterFactory(rxJava3CallAdapterFactory)
.build();
}

@Provides
@Singleton
publicHostSelectionInterceptorprovideHostSelectionInterceptor(PreferenceHelper preferenceHelper){
returnnewHostSelectionInterceptor(preferenceHelper);
}

@Provides
@Singleton
publicOkHttpClientprovideOkHttpClient(@ApplicationContext Context context, HttpLoggingInterceptor httpLoggingInterceptor, HostSelectionInterceptor hostSelectionInterceptor){
longcacheSize=5*1024*1024;// 5 MB
Cachecache=newCache(context.getCacheDir(), cacheSize);
OkHttpClient.Builderbuilder=newOkHttpClient.Builder()
.cache(cache)
.retryOnConnectionFailure(true)
.connectTimeout(200,TimeUnit.SECONDS)
.readTimeout(200,TimeUnit.SECONDS)
.addInterceptor(httpLoggingInterceptor)
.addInterceptor(hostSelectionInterceptor)
.followRedirects(true)
.followSslRedirects(true);

return builder.build();
}
}

在ViewModel中注入HostSelectionInterceptor

为了简化环境切换操作,我们可以在ViewModel或Activity中注入HostSelectionInterceptor:

@HiltViewModel
publicclassMainViewModelextendsViewModel{

privatefinalHostSelectionInterceptor hostSelectionInterceptor;
privatefinalPreferenceHelper preferenceHelper;

@Inject
publicMainViewModel(HostSelectionInterceptor hostSelectionInterceptor, PreferenceHelper preferenceHelper){
this.hostSelectionInterceptor = hostSelectionInterceptor;
this.preferenceHelper = preferenceHelper;
}

publicvoidswitchEnvironment(boolean isProd){
        preferenceHelper.setProdEnvironmentStatus(isProd);
        hostSelectionInterceptor.setHostBaseUrl();
}
}

使用Spinner切换环境

我们可以通过Spinner来切换开发环境和生产环境。以下是一个示例:

public classMainActivityextendsAppCompatActivity{

@Inject
HostSelectionInterceptor hostSelectionInterceptor;

@Inject
PreferenceHelper preferenceHelper;

privateMainViewModel mainViewModel;

@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mainViewModel =newViewModelProvider(this).get(MainViewModel.class);

        setupHostSelectionSpinner();
}

privatevoidsetupHostSelectionSpinner(){
Spinnerspinner= findViewById(R.id.spinner_host_selection);
ArrayAdapter<String> adapter =newArrayAdapter<>(this, android.R.layout.simple_spinner_item,newString[]{"DEV","PROD"});
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapter);

        spinner.setOnItemSelectedListener(newAdapterView.OnItemSelectedListener(){
@Override
publicvoidonItemSelected(AdapterView<?> parent, View view, int position, long id){
if(position ==0){
                    mainViewModel.switchEnvironment(false);// 切换到开发环境
}else{
                    mainViewModel.switchEnvironment(true);// 切换到生产环境
}
}

@Override
publicvoidonNothingSelected(AdapterView<?> parent){}
});
}
}

总结

通过以上步骤,我们实现了在运行时动态切换Retrofit Base URL的功能。这种方法不仅简化了环境切换操作,还避免了维护多个Retrofit实例的繁琐工作。值得注意的是,这种环境切换主要适用于开发和调试阶段,因为所有请求都会经过这个Interceptor,可能会影响请求速度。

希望本文能为您在项目中实现动态切换Base URL提供帮助。如果有任何问题或建议,欢迎交流与讨论。


虎哥Lovedroid
Android技术达人 近10年一线开发经验 关注并分享Android、Kotlin新技术,新框架 多年Android底层框架修改经验,对Framework、Server、Binder等架构有深入理解
 最新文章