版權聲明:本文為LooperJing原創文章,轉載請注明出處!
通常產品在迭代的時候,都有測試環境和正式環境,或者說是生產和開發環境,一般軟件開發階段都是在測試環境上運行調試,而正式打包發布時會配置正式環境的服務器,也就是不同的接口URL和數據庫的區別。所以開發人員經常要在測試環境與正式環境之間來回切換,這帶來了很大不便。本文提供了三種種方式來解決這個問題。
第一種方案:默認情況下,項目的buildTypes包含debug和release兩個構建版本,用來分別對應測試環境和生產環境,設置applicationIdSuffix ,這樣測試環境和生產環境實際上等于是已經分開的兩個app了,可以實現在同一個設備上來安裝同一個應用的不同版本。
第二種方案:在gradle構建的時候,Product Flavors中定義兩個渠道,分別對應測試環境和生產環境,并且每個渠道applicationId不同,也可以實現在同一個設備上來安裝同一個應用的不同版本。
第三種方案:手機SDCARD中創建隱藏文件,在程序啟動的時候,判斷有沒有隱藏文件,進行測試環境和正式環境的切換,這樣只需要一個apk,通過隱藏配置文件,動態進行環境的切換。
方案一和方案二的本質都是修改applicationId的值,構建打包出不同包名的apk安裝文件。方案三不需要同時安裝兩個apk文件就可以實現環境分離,不足是每次切換的時候,app要關閉重啟一下。下面簡述一下三種方案的實現。
方案一:buildTypes
在app/gradle中添加下列代碼
defaultConfig {
applicationId "com.environment.switch"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug{
applicationIdSuffix ".debug"
}
}
將debug類型的Application Id Suffix設置為“.debug”,然后在Application的onCreate中判斷是哪一個應用,設置不同的服務器地址。
public class ServerConfigManger {
private ServerConfigManger(){
};
private static class ServerConfigMangerHolder{
private static final ServerConfigManger instance=new ServerConfigManger();
}
public static ServerConfigManger getInstance(){
return ServerConfigMangerHolder.instance;
}
public String getServerURL(Application pApplication){
//測試環境服務器地址
String urlPrefix="text.xxx.com";
ApplicationInfo applicationInfo = pApplication.getApplicationInfo();
String processName = applicationInfo.processName;
if( processName.endsWith(".debug")){
return urlPrefix;
}else {
//正式環境服務器地址
urlPrefix="release.xxx.com";
return urlPrefix;
}
}
}
@Override
public void onCreate() {
super.onCreate();
String serverURL = ServerConfigManger.getInstance().getServerURL(this);
}
構建類型仍然是兩個,debug和release,如下圖:
只是現在的debug對應的是測試環境,而release對應的是正式環境,debug應用的包名是com.environment.switch.debug,release應用的包名是com.environment.switch;這種方式還可以繼續優化一下,因為這兩個應用安裝之后,桌面的應用圖標是一樣的,下面將debug版本的應用圖標換掉。
在src目錄下新建一個debug目錄,將main目錄下的res目錄復制一份到debug目錄下,修改各個分辨率下的桌面Icon和strings.xml文件中的應用名稱,如下圖:
到此第一種方案就OK了
方案二:Product Flavors
在app/gradle中添加下列代碼
productFlavors{
en1{
applicationId "com.environmentswitch_beta"
}
en2{
applicationId "com.environmentswitch"
}
}
所產生的構建如下,總共4個
可以將en1的debug和release對應測試環境,en2的debug和release對應正式環境,我們在Application中的onCreate中根據運行時選擇的是en1還是en2進行服務器地址取出不同的值。同 步驟一;
方案二:隱藏配置文件
在SDCARD中設置隱藏文件,根據隱藏文件判斷是哪一套環境,假設存在test1,就用測試環境1,存在test2,就用測試環境2,存在test3,就用測試環境3,現在新建ServerBuildConfig,遍歷SDCARD進行判斷。
public class ServerBuildConfig {
public static final int TEST_ENVIRONMENT_ONE = 0;
public static final int TEST_ENVIRONMENT_TWO = 1;
public static final int TEST_ENVIRONMENT_THREE = 2;
public static final int RELEASE_ENVIRONMENT = 3;
public static int mWhichEnvironment = 0;
static {
loadConfig();
}
private static void loadConfig() {
if(!Environment.getExternalStorageState().equals("mounted")) {
Log.w("ServerBuildConfig", "No valid SDCard, skip ServerBuildConfig!");
} else {
String buildConfigPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/.appconfig";
Log.i("ServerBuildConfig", "start to load configs for VSBuildConfig from: " + buildConfigPath);
File buildFile = new File(buildConfigPath);
if(buildFile.exists()) {
File[] listFiles = buildFile.listFiles(new ConfigFilenameFliter());
File testFile = null;
if(listFiles != null) {
for (File file : listFiles) {
if (file.getName().startsWith(".test")) {
if (testFile == null || file.lastModified() > testFile.lastModified()) {
testFile = file;
}
}
}
}
if(testFile != null) {
if(!".test".equals(testFile.getName()) && !".test1".equals(testFile.getName())) {
if(".test3".equals(testFile.getName())) {
mWhichEnvironment = 3;
} else if(".test2".equals(testFile.getName())) {
mWhichEnvironment = 2;
}
} else {
mWhichEnvironment = 1;
}
Log.i("ServerBuildConfig", "mWhichEnvironment = " + mWhichEnvironment);
}
}
}
}
private static class ConfigFilenameFliter implements FilenameFilter {
ConfigFilenameFliter() {
}
public boolean accept(File dir, String filename) {
return filename.startsWith(".");
}
}
}
然后在ServerConfigManger添加一個方法,返回不同的服務器地址
public String getServerURL(){
String urlPrefix="text1.xxx.com";
switch (ServerBuildConfig.mWhichEnvironment) {
case ServerBuildConfig.TEST_ENVIRONMENT_ONE:
urlPrefix="text1.xxx.com";
break;
case ServerBuildConfig.TEST_ENVIRONMENT_TWO:
urlPrefix="text2.xxx.com";
break;case
ServerBuildConfig.TEST_ENVIRONMENT_THREE:
urlPrefix="text3.xxx.com";
break;
case ServerBuildConfig.RELEASE_ENVIRONMENT:
urlPrefix="release.xxx.com";
break;
}
return urlPrefix;
}
在自定義的Application的onCreate中使用
String serverURL = ServerConfigManger.getInstance().getServerURL();
到此三種方案敘述完畢,對于第一種方案是最簡便的,但是在有多套設置環境的情況下,第一種就不能滿足需求了,就可以采取第二種以及第三種。總之,團隊有一個約定,采取哪一種無關緊要。