I have an app that has 3 different flavors, full
, part1
and part2
.
All different flavors have different package names, so I can ship them as different apps.
Now I want that only part1
gets a menu item called Reload
. The other 2 flavors shouldn't have this menu item. Is this possible?
I tried the following with the menu resources:
app
|
+-src
|
+-full
|
+-main
| |
| +-res
| |
| +-menu
| |
| +-main_activity.xml
|
+-part1
| |
| +-res
| |
| +-menu
| |
| +-main_activity.xml
|
+-part2
Where main_activity.xml
for part1
is:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/action_reload"
android:icon="@drawable/ic_reload"
android:title="@string/action_reload"
app:showAsAction="always"/>
</menu>
And main_activity.xml
for main
is:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
</menu>
However, if I build the app in any other build variant than part1
, I get a compilation error in my MainActivity
where I need to react to the menu selection:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_reload: // Compile error: This item is not available
// TODO reload
return true;
default:
return super.onOptionsItemSelected(item);
}
}
It's quite obvious why that is. But do you have any suggestion what the solution is to customize menus for different build flavors?
Create a MainActivity
in the main source folder where you handle the normal common code. Create another MainActivity
in the part1 source folder where you override onOptionsItemSelected
where it's not a problem to have references to R.id.action_reload
. That should work.
There's another way - create value file with boolean resource, with different value for each flavor e.g.:
main/res/values/bool.xml :
<resources>
<bool name="show_reload">false</bool>
</resources>
part1/res/values/bool.xml :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="show_reload">true</bool>
</resources>
and then in your menu reource set the visibility value dependent on resource:
<menu ..>
<item ..
android:visible="@bool/show_reload"
..
/>
</menu>
If You don't want to copy whole class file, but to detect flavour or setting for any flavour and adjust it then do this:
In gradle file create config field:
defaultConfig {
...
buildConfigField "boolean", "SHOW_MY_MENU_ITEM", "true"
}
productFlavors {
FooFlavour {
...
buildConfigField "boolean", "SHOW_MY_MENU_ITEM", "false"
}
}
then build gradle. You can access this config field in Activity like this:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.foo_menu, menu);
if (!BuildConfig.SHOW_MY_MENU_ITEM) {
MenuItem myItem = menu.findItem(R.id.my_menu_item);
myItem.setVisible(false);
}
return super.onCreateOptionsMenu(menu);
}
You can also create another xml file in the menu folder and create the same resource id inside it, for example:
app
|
+-src
|
+-full
|
+-main
| |
| +-res
| |
| +-menu
| |
| +-main_activity.xml
| +-dummy_menus.xml
And then in the dummy menu create an item with the same id. You just won't use it because it will never be selected, as it never was inflated.
You can define the content of the onOptionsItemSelected(MenuItem item)
method in a helper and then using flavors load the needed helper :
@Override
public boolean onOptionsItemSelected(MenuItem item) {
HelperPart.selectItem(this, item);
}
// Helper loaded for flavor "part1"
static class MenuHelper{
public static boolean selectItem(Activity act, MenuItem item){
switch (item.getItemId()) {
case R.id.action_reload:
// TODO reload
return true;
default:
return act.onOptionsItemSelected(item);
}
}
}
// Helper loaded for flavor "part2" and "full"
static class MenuHelper{
public static boolean selectItem(Activity act, MenuItem item){
// Do nothing
}
}