三種方案實現Android應用的環境分離

版權聲明:本文為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,如下圖:

build_type.png

只是現在的debug對應的是測試環境,而release對應的是正式環境,debug應用的包名是com.environment.switch.debug,release應用的包名是com.environment.switch;這種方式還可以繼續優化一下,因為這兩個應用安裝之后,桌面的應用圖標是一樣的,下面將debug版本的應用圖標換掉。
在src目錄下新建一個debug目錄,將main目錄下的res目錄復制一份到debug目錄下,修改各個分辨率下的桌面Icon和strings.xml文件中的應用名稱,如下圖:


修改桌面圖標.png

到此第一種方案就OK了

方案二:Product Flavors

在app/gradle中添加下列代碼

   productFlavors{
        en1{
            applicationId "com.environmentswitch_beta"
        }
        en2{
            applicationId "com.environmentswitch"
        }
    }

所產生的構建如下,總共4個


構建類型.png

可以將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();

到此三種方案敘述完畢,對于第一種方案是最簡便的,但是在有多套設置環境的情況下,第一種就不能滿足需求了,就可以采取第二種以及第三種。總之,團隊有一個約定,采取哪一種無關緊要。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容