Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you manage multiple environments while developing Android apps?

Tags:

android

We're building an Android app that connects to the cloud. We have a test URL for our APIs and a production URL. We connect the app to our local development machines to talk to the database when developing but find ourselves modifying a global API URL to the production URL every time we generate an APk for the Play Store.

Is there a better way to manage environments for Android? Can we also have two versions of the app (development version) and the Play Store version? I am not able to have two versions as both the apps have the same signature. How do we best manage this?

like image 600
JackH Avatar asked Apr 10 '14 17:04

JackH


People also ask

Which software development environments can be used to make applications for Android?

Android Studio As the official integrated development environment for all Android applications, Android Studio always seems to top the list of preferred tools for developers.

Which of the following are development environment for Android?

Android Studio is the official Integrated Development Environment (IDE) for Android app development, based on IntelliJ IDEA .

How can we make 2 different apps interact?

At the simplest level, there are two different ways for apps to interact on Android: via intents, passing data from one application to another; and through services, where one application provides functionality for others to use.


3 Answers

With android studio and gradle its simple now.

inside your app build.gradle edit signing configs

signingConfigs {
    debug {
        storeFile file("debug.keystore")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }

    prod {
        storeFile file("prod.keystore")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }

    dev {
        storeFile file("dev.keystore")
        storePassword "..."
        keyAlias "..."
        keyPassword "..."
    }
}

add buildTypes

buildTypes {

    debug {
        buildConfigField 'String', 'BASE_URL', '"http://127.0.0.1:8080/"'
        ......
        signingConfig signingConfigs.debug
    }

    prod {

        minifyEnabled true
        shrinkResources true
        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        buildConfigField 'String', 'BASE_URL', '"http://prod.example.com"'
        ......
        signingConfig signingConfigs.prod
    }


    dev {
        buildConfigField 'String', 'BASE_URL', '"http://dev.example.com"'
        ......
        signingConfig signingConfigs.dev
    }
}

In your code take base url configured in gradle file by this code.

public final static String BASE_URL = BuildConfig.BASE_URL;

You can also put different KEY or whatever which is build type specific in gradle file and in code it will take according to the build type you are running.

Its even possible to have different package name.

productFlavors {
    my_prod {
        applicationId "com.example.packtwo"
    }
    my_dev {
        applicationId "com.example.packone"
    }
}

In recent gradle config, there are some updates in specifying package name. You have to add flavourDimensions if using productFlavours. See below code with added flavourDimensions

flavorDimensions "pack"

productFlavors {
    flavor_dev {
        applicationId 'com.example.packtwo'
        dimension "pack"
    }

    flavor_prod {
        applicationId 'com.example.packone'
        dimension "pack"
    }
}

This will give you more details about product flavours and dimensions

https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html

Check for more possibilities...

But if you are using different flavors you might have to deal with Manifest merging and all.

like image 178
shijin Avatar answered Oct 19 '22 15:10

shijin


This is can be achieved using product flavours.

For achieving this requirement:

First of all, Create 2 files under the app folder of your project say development.props and production.props. Or you can add these 2 files in a package under app folder say config.

enter image description here

Basically, these 2 files contain keys and values. This key is same for both files. But their values are different. These files contain one key say “SERVER_URL” and its value. It would be written like this:

SERVER_URL=”Server_url_value”

In this case, only URL is different. So, I have added only one key-value pair in Props file. You can add more.

Then, create ProductFlavours in the app build.gradle file say development and production. Now, access different props files containing URLs in their correseponding flavours like this:

productFlavors {
    development {
        getProps('./config/development.props').each { p ->
            buildConfigField 'String', p.key, p.value
        }
    }
    production {
        getProps('./config/production.props').each { p ->
            buildConfigField 'String', p.key, p.value
        }
    }
}

def getProps(path) {
    Properties props = new Properties()
    props.load(new FileInputStream(file(path)))
    return props
}

Now, For each flavour, there is a build type And this BuildType is added in app build.gradle. For example, Build type is Debug and release. And I have two flavours i.e. development and production. So, gradle task will be created using both flavour and build type like this:

assemble{flavourName}{BuildType}

Now, you need to type these commands only. It would generate required APK with its corresponding URL. Commands are:

./gradlew assembleProductionRelease would generate release build with Production URL.

./gradlew assembleDevelopmentDebug would generate debug build with Development URL.

./gradlew assembleProductionDebug would generate debug build with Production URL.

./gradlew assembleDevelopmentRelease would generate release build with development URL.

Top three gradle task would be very helpful. But the last task would generate Release build with development URL. But this is not recommended. So, we should stop developer to execute this task i.e. ./gradlew assembleDevelopmentRelease

Now To restrict developer to generate release build using Development URL, add this snippet in your app build.gradle file:

android.variantFilter { variant ->
    if(variant.buildType.name.equals('release')
            && variant.getFlavors().get(0).name.equals('development')) {
        variant.setIgnore(true);
    }
}

Now, If we try to execute task i.e. ./gradlew DevelopmentRelease. Gradle would stop generating the build and throw exception and would say: This task assembleDevelopmentRelease is not found in the root project.

like image 23
Juhi Matta Avatar answered Oct 19 '22 13:10

Juhi Matta


Use Ant to build at least the production versions. This way you can set certain config values/flags during building. Let's say you have a config.xml file that contains the URL to the server. You can have different Ant build targets that will change the URL to point to the appropriate server. Check out this tutorial. It explains exactly how that is done.

like image 3
SimonSays Avatar answered Oct 19 '22 15:10

SimonSays