Override string in a library with explicit package - android

I know that i have to keep the same name to override a resource of a library, but imagine a class inside this library that is using a string.
With an example i'll be more clear i think:
Library class:
package com.library.randomlibrarypackage;
import com.library.R;
public class RandomClass extends Activity{
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
String stringFromResource = getString(R.string.librarystring);
}
}
This string is contained under library's values resources:
<resources>
<string name="librarystring">This is from library</string>
</resources>
If i try to "override" it and use RandomClass.class, the value of stringFromResource still remains "This is from library".
There's a way to override it without override the entire class?

You can try to override it in gradle build file for your library like this
android {
buildTypes {
debug{
resValue "string", "librarystring", "Library string debug"
}
release {
resValue "string", "librarystring", "Library string release"
}
}
}

Related

Android's R file in androidTest is not generating when applicationIdSuffix is used

I've created an Android project from scratch, with package name com.example.myapplication
I've a strings.xml file in the main package (app module), with a String called yyy.
I've another strings.xml file in the androidTest package, with a String called xxx.
I can use both strings without problem in a instrumented test, simply using the correct R file:
class ExampleInstrumentedTest {
#Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val stringFromApp = appContext.getString(com.example.myapplication.R.string.yyy)
val stringFromTest = appContext.getString(com.example.myapplication.test.R.string.xxx)
assertEquals("com.example.myapplication", appContext.packageName)
}
}
But, if I add an applicationIdSuffix in debug variant, then androidTest's R file is not generated correctly. It seems a bug on the system:
debug {
applicationIdSuffix '.imasuffix'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
class ExampleInstrumentedTest {
#Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
val stringFromApp = appContext.getString(com.example.myapplication.R.string.yyy)
val stringFromTest = appContext.getString(com.example.myapplication.test.R.string.xxx)
val stringFromNewSuffix = appContext.getString(com.example.myapplication.imasuffix.test.R.string.xxx)
assertEquals("com.example.myapplication", appContext.packageName)
}
}
As you can see, Android Studio suggests me to use the com.example.myapplication.imasuffix.test.R file but is not working, even Rebuilding the project or invalidating caches.
I've seen a similar issue related with Roboelectric, but I'm using the standard AndroidJUnit4 tests.
Thanks.

How to pass customizable property when Android app launches

I would like to launch my Android app in such a way that I can set some external variable that my app can read. It would be nice if this was possible either in Gradle or as part of the debug/run configuration.
In essence, I would like to test for a variable to see if it is set. In this example I would like to set USE_FAKE_DATA:
if (USE_FAKE_DATA) {
...
} else {
...
}
One way is to use build variants and I have done this before. But I'm wondering if another way has been made available.
Gradle File
android {
buildTypes {
debug {
buildConfigField "boolean", "USE_FAKE_DATA", "true"
}
release {
buildConfigField "boolean", "USE_FAKE_DATA", "false"
}
}
}
Java File
class Test extends Activity {
#Override
public void onCreate(Bundle data) {
if (BuildConfig.USE_FAKE_DATA) {
...
} else {
...
}
}
}
Please refer this answer for more.

Exclude code segment depending on flavor

I have an Android app with a lot of flavors, and I want only specific flavors to include a certain code segment. More specifically, I want to use a 3rd party library and add that library's init code only in specific flavors.
public class MainApplication
extends Application {
#Override
public void onCreate() {
super.onCreate();
//The library is only included in the build of specific flavors, so having this code in other flavors will not compile
//I want the following code only to be included in the flavors that include the library
SomeLibrary.init();
//other code that is relevant for all flavors
...
}}
A) Use reflection
defaultConfig {
buildConfigField "boolean", "USE_THE_CRAZY_LIB", "false"
}
productFlavors {
crazyFlavor {
buildConfigField "boolean", "USE_THE_CRAZY_LIB", "true"
//... all the other things in this flavor
}
}
then in your Application
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
if (BuildConfig.USE_THE_CRAZY_LIB) {
Method method = clazz.getMethod("init", SomeLibrary.class);
Object o = method.invoke(null, args);
}
}
}
B) Use two different versions of the same class for two different flavors
(more information on that approach e.g. here)
For the other flavor (in src/otherFlavor/java):
public class FlavorController {
public static void init(){
}
}
For your flavor (in src/crazyFlavor/java):
public class FlavorController {
public static void init(){
SomeLibrary.init();
}
}
In your Application:
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
FlavorController.init();
}
}
You can also use gradle to solve this issue by using with custom configurations.
Use this pattern to create custom configurations this line to your build.gradle file ,
configurations {
prodFlavBuildTypeCompile
}
dependencies {
prodFlavBuildTypeCompile 'com.google.code.gson:gson:2.8.0'
}
For example , My app flavours are free and paid with build types dev and prod
configurations {
freeDevCompile
freeProdCompile
}
dependencies {
freeDevCompile 'com.google.code.gson:gson:2.8.0'
}
And in the main folder keep Application with common code.
public class BaseApp extends Application {
#Override
public void onCreate() {
super.onCreate();
}
}
And use the implementation code in each product flavours.
public class ApplicationImpl extends BaseApp {
#Override
public void onCreate() {
super.onCreate();
SomeLibrary.init();
}
}
code for other flavours,
public class ApplicationImpl extends BaseApp {
#Override
public void onCreate() {
super.onCreate();
// code for flavour 2
}
}

android gradle build set class attribute value

I want to set attribute values in my Application class from the build.gradle file like for example:
MyApplication.URL = "someurl.com"
that should be determined per build,
I tried :
productFlavors {
myApp {
qualified.package.path.MyApplication.URL = "someurl.com"
}
}
but it failed
You can write your fields inside BuildConfig class and then get them from there.
productFlavors {
myApp {
buildConfigField "String", "URL", "\"someurl.com\""
}
}
public class MyApplication extends Application {
private String URL;
#Override
public void onCreate() {
URL = BuildConfig.URL;
}
}

Set constant value with gradle

I just moved to the android gradle build system and it is not clear for me how to set constant values.
e.g. I have
API.java which contains
BASE_URL = "http://debug.server.com"
but when gradle builds release I need BASE_URL to be "http://release.server.com"
How to replace this value at the build time?
Gradle generates a class called BuildConfig which contains static members (such as the boolean DEBUG, which is set to true for debug variants).
You could either query this in java like so:
if (BuildConfig.DEBUG) {
BASE_URL = "http://debug.server.com"
} else {
BASE_URL = "http://release.server.com"
}
or the same thing as a one-liner:
BASE_URL = BuildConfig.DEBUG ? "http://debug.server.com" : "http://release.server.com"
OR
You could actually set the BASE_URL inside the the BuildConfig class using gradle like so:
android {
buildTypes {
debug {
buildConfigField "String", "BASE_URL", '"http://debug.server.com"'
}
release {
buildConfigField "String", "BASE_URL", '"http://release.server.com"'
}
}
}
Note the single and double quotations around the value in gradle, as others have mentioned in the comments. This way, the double quotes become part of the value.
As a result, the static reference BuildConfig.BASE_URL would point to the corresponding URL (i.e. "debug.server.com" for debug, "release.server.com" for release)
Answer of fifer-sheep is correct. Just wanted to leave a solution for more than two environments.
Two flavors for staging and live.
productFlavors {
staging {
...
}
production {
...
}
}
Whole app config relies on the current ENV. Using:
public static String ENV_DEVELOPMENT = "development";
public static String ENV_STAGING = "staging";
public static String ENV_PRODUCTION = "production";
ENV = BuildConfig.DEBUG ? ENV_DEVELOPMENT : BuildConfig.FLAVOR;
I can switch between all different ENVs while testing locally but force staging/live settings if released.

Categories

Resources