12

My android app does some http requests to my server. However sometimes I am debugging the new api code that runs on my development machine. I would like to be able to pass something (like an environment variable) so in my code, if it's present I would be able to use that as the hostname for the api requests from the android emulator.

So I'm looking for a way to pass something like:

API_SERVER=http://10.0.2.2/myapp/

and in my code I would use it somehow, for example:

final static String API_SERVER_REAL = "http://example.com/";
final String apiServerOverride = System.getenv("API_SERVER");
final String API_SERVER = (null != apiServerOverride && !apiServerOverride.isEmpty() ? apiServerOverride : API_SERVER_REAL);
Gavriel
  • 18,880
  • 12
  • 68
  • 105
  • And the question is how to set up a run configuration to make this easy from Android Studio? Instead of an environment variable I'd suggest a command-line parameter. – Scott Barta Feb 23 '14 at 18:37
  • I'm open to it as well. How do you pass a command line parameter from Android Studio to your Android app, running in the emulator? Which class gets it in your android app? I wonder if it's possible: http://stackoverflow.com/questions/20197242/android-native-application-command-line-arguments – Gavriel Feb 23 '14 at 19:14
  • Oh I thought you were talking about passing info to the server process. There's no command line for Android APKs; you could write a value to Sqlite via adb shell commands or maybe just write a file to the local filesystem. – Scott Barta Feb 23 '14 at 21:33
  • Possible duplicate of [Passing -P parameters to gradle from android studio](https://stackoverflow.com/questions/33216248/passing-p-parameters-to-gradle-from-android-studio) – Rostyslav Roshak Aug 04 '17 at 15:14
  • @RostyslavRoshak this question is from 2014, the other one is from 2015, so how can this be the duplicate of the other? Also the other question is about how to pass something to GRADLE, while this question is how to pass something to the JAVA code of the APP – Gavriel Aug 06 '17 at 10:43

4 Answers4

14

I know this thread is quite old, but in my opinion none of provided answers actually solves the problem. Flavors are ill-suited for parametrizing your build with things like API URLs, and even worse for things like API keys etc.

Firstly, build.gradle which defines flavors is part of project source, therefore it must not contain such information in order to be safely committed into source control systems.

Secondly, a need may arise to test different flavors against different API endpoints/keys. What if you just want to hit some debug http server you just created to solve a bug? Would you create a flavor for that? Probably not... Flavors are good for things like "free flavor" and "premium flavor".

This problem is easily solved using gradles -P flag. You can access gradle properties that are passed this way as regular variables inside your gradle.build, and you can vary it's behavior accordingly.

If you want to push this flags further into your application you can use Scott's solution that was posted here, combined with the provided flag.

The build command would then probably look like:

$ gradle build -Papiroot=http://www.example.com

And in your build.gradle you would define the writeValue task like this:

task writeValue(type:Exec) {
    commandLine '/usr/local/bin/adb', 'shell', "echo 'API_SERVER=${apiroot}' > /data/data/values.properties"
}

FYI the -P flag can be easily configured in Android Studio by navigating from the menu:

Run -> Run/Debug Configurations -> Defaults -> Gradle -> Script Parameters

Karol Majta
  • 246
  • 3
  • 7
  • 6
    I like this approach but it's missing one tiny thing: how to get the Android Studio Gradle plug-in to pass that -P variable when sync'ing the project to Android Studio? Do you know if this is at all possible? – Julian Cerruti Nov 09 '15 at 17:36
3

Probably the simplest thing is to write the data you want to pass to a file on the device in /data/data; your Android app can read the device trivially (perhaps make it a .properties file and use java.util.Properties to read it in). To write it out, use this kind of task in your build.gradle file (and use the correct path to the adb command for your setup):

task writeValue(type:Exec) {
    commandLine '/usr/local/bin/adb', 'shell', 'echo \'API_SERVER=http://10.0.2.2/myapp/\' > /data/data/values.properties'
}

There's documentation on Gradle exec tasks at http://www.gradle.org/docs/current/dsl/org.gradle.api.tasks.Exec.html

You can execute this task manually from Android Studio by using the Gradle tasks view:

Screen shot of Gradle tasks view

Scott Barta
  • 79,344
  • 24
  • 180
  • 163
  • Isn't it possible to hook the task into some other default "android build system" task so it gets executed automatically once you hit the "Run" button? – dirleyrls Jan 10 '15 at 17:10
1

Due to a bug in Android Studio, you cannot pass vm or script parameters from a gradle configuration. The issue is here.

As a workaround in Linux envs (probably Mac too), you can create a bash configuration where you will be able to add all desired parameters.

user2468170
  • 1,234
  • 2
  • 15
  • 19
0

I suggest using productFlavors. Each flavor can contain environment specific settings. I simply have a class called 'Environment' which contains all the public static final Strings that I need and each product flavor includes an different version of this class with the values set for the environment.

Nebu
  • 1,352
  • 1
  • 14
  • 21
  • The document you've linked is actually out-of-date and deprecated now. In this use case, the [buildTypes](https://developer.android.com/studio/build/build-variants.html#build-types) construct is more appropriate to use than productFlavors. The difference is discussed [here](https://stackoverflow.com/questions/27905934/why-are-build-types-distinct-from-product-flavors), and current documentation on both [here](https://developer.android.com/studio/build/build-variants.html). – ScottyC Feb 13 '18 at 20:12