There are two product flavor in my application i-e
flavorOne(src/flavorOne/java) and flavorTwo(src/flavorTwo/java). Main (src/main/java) is directory form where both flavor are using the classes. I want to start activity src/flavorTwo/java/ActivityB.java from the Activity present in src/main/java/ActivityA. while running the flavorTwo it works but when i switch the flavorOne it shows the import com.packagename.ActivityB error.
+ App // module
|- src
|- main// shared srcDir
|- java
|- SharedActivity
+ flavorOne
|- java
|- FlavorOneActivity
+ flavorTwo
|- java
|- FlavorTwoActivity
Here is SharedActivity.java in dir src/main/java/SharedActivity.java
package com.example.buildvariants;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
/********************** works if it is in flavorOne otherwise it shows error on this package import ***********/
import com.example.buildvariants.flavorOne.LoginActivity;
public class SharedActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
//if flavor is flavorTwo hide the fab
//else flavor is flavorOne show fab and launch activity under flavorOne/java/LoginActivity.java
if (BuildConfig.FLAVOR.equalsIgnoreCase("flavorTwo")) {
fab.setVisibility(View.GONE);
} else {
fab.setVisibility(View.VISIBLE);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
startActivity(new Intent(SharedActivity.this, LoginActivity.class));
}
});
}
}
}
Activity under flavorOne src/flavorOne/FlavorOneMainActivity.java
package com.example.buildvariants.flavorOne;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.example.buildvariants.R;
import com.example.buildvariants.SharedActivity;
public class FlavorOneMainActivity extends AppCompatActivity {
private static final String TAG =FlavorOneMainActivity.class.getSimpleName() ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.flavor_one_activity_main);
Intent intent = new Intent(FlavorOneMainActivity.this, SharedActivity.class);
startActivity(intent);
}
}
Activity under flavorTwo src/flavorOne/FlavorTwoMainActivity.java
package com.example.buildvariants.flavorTwo;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import com.example.buildvariants.R;
import com.example.buildvariants.SharedActivity;
public class FlavorTwoMainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.flavor_two_activity_main);
startActivity(new Intent(FlavorTwoMainActivity.this, SharedActivity.class));
}
}
Shows error on package import of SharedActivity(src/main/java/) as listed below when i changed the build variants flavorTwo.
package com.example.buildvariants;
import android.content.Intent;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
/********error on package import***********/
import com.example.buildvariants.flavorOne.LoginActivity;
public class SharedActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
//if flavor is flavorTwo hide the fab
//else flavor is flavorOne show fab and launch activity under flavorOne/java/LoginActivity.java
if (BuildConfig.FLAVOR.equalsIgnoreCase("flavorTwo")) {
fab.setVisibility(View.GONE);
} else {
fab.setVisibility(View.VISIBLE);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
startActivity(new Intent(SharedActivity.this, LoginActivity.class));
}
});
}
}
}
What would be the best solution for this problem?
It's failing because when your building your app only one product flavor's code exists at a time. So what you really want to do is have a single Class name used in two product flavors.
Imagine we have a single class we want to be replaced per product flavor, lets call it ReplacableActivity.java
For the replacement to work both product flavors need to have this class and main's source set will not have the class
example:
src/main/com/blah/myApp/ReplacableActivity #<- should not exist
# exists and is the implementation of ReplacableActivity for `flavorOne`
src/flavorOne/com/blah/myApp/ReplacableActivity.java
# exists and is the implementation of ReplaceableActivity.java for `flavorTwo`
src/flavorTwo/com/blah/myApp/ReplacableActivity.java
Now for all product flavors your building the ReplacableActivity
exists and can be referenced from the main
source set. At build time only the ReplaceableActivity
for that specific flavor gets packaged with the app. And now your import will work as expected
import com.blah.myApp.ReplaceableActivity;
from the main
source set.
Edit:
If your only concern is hiding or showing a single element then the above is overkill. It would be much easier to get it from the BuildConfigField
android {
productFlavors {
flavorOne {
buildConfigField "boolean", "flavorShowsFab", 'false'
}
flavorTwo {
buildConfigField 'boolean', 'flavorShowsFab', 'true'
}
}
Then in your java code just do
findViewById(R.id.myHidableFab).setVisibility(BuildConfig.flavorShowsFab ? View.VISIBLE : View.GONE));
Instead of creating different code for each flavor you can maintain same code by using inheritance concept and few changes in gradle and manifest files, we can achieve this in three steps
1) merge the source sets for each flavor in app level build.gradle
file
sourceSets {
flavorOne {
java.srcDirs = ['src/main/java','src/flavorOne/java']
}
flavorTwo {
java.srcDirs = ['src/main/java','src/flavorTwo/java']
}
}
2) the main trick happens here, create manifest for each flavor with launcher activity defined for them but not in main flavor
In main manifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapplication">
<application
//no launcher defined here
</application>
</manifest>
In flavour one mainifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application>
<activity
android:name="{Your launcher activity}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
In flavour two manifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.myapplication">
<application>
<activity
android:name="{Your launcher activity}">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
so that we don't get error while merging manifest file while building gradle
3) So in main java src, create BaseSharedActivity.java
and write your normal implementation, create SharedActivity.java
in each flavor and call them from the launcher activity defined in each flavor.
In SharedActivity.java
of each flavour:
public class SharedActivity extends BaseSharedActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
//You can override whatever method you want from BaseSharedActivity here
}
This way you are not adding same code for SharedActivity and can give maximum customization for the same screen in different flavors, you can use the same logic for the launcher activity as well
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With