write once, ship multiple times
Post on 14-Apr-2017
129 Views
Preview:
TRANSCRIPT
A white label product is a product or service produced by one company (the producer) that other companies (the marketers) rebrand to make it appear as if they had made it.
- WIKIPEDIA
Provides your brand with a refined product.
Outsourcing the development to a trusted thirty-party company.
Saving time and money.
Fat clients
• not customisable on the fly
• new app version for each new
feature
• prone to errors
• hard to maintain
MAIN FLAVOUR
• default product
• used only for demo purposes
• contains shared code
• uses default set of resources
• can be customised by configuration file
FLAVOURS
• each flavour is an application
• holds product specific resources
• contains only product specific code
• should be as minimal as possible
ADVANTAGES
Easy to maintain and develop.
Easy to configure.
Resource and code sharing between main flavour and product flavour.
MAIN MODULE
• set of core functionalities
• default resources
• can be configured by configuration file
productFlavors {
white { dimension ‘product’ applicationId ‘com.infinum.white’ buildConfigField STRING, GOOGLE_ANALYTICS_ID, ‘”analyticsIdForWhite”’ buildConfigField STRING, API_URL, ‘”www.api.co/white/v1”’ manifestPlaceholders = [urlScheme: “white”] }
blue { dimension ‘product’ applicationId ‘com.infinum.blue’ buildConfigField STRING, GOOGLE_ANALYTICS_ID, ‘”analyticsIdForBlue”’ buildConfigField STRING, API_URL, ‘”www.api.co/blue/v1”’ manifestPlaceholders = [urlScheme: “blue”] } }
HostModule.setEndpoint(BuildConfig.API_URL);
AnalyticsModule.setGoogleAnalyticsId(BuildConfig. GOOGLE_ANALYTICS_ID);
applicationVariants.all { resValue XML_STRING, SEARCH_AUTHORITY, applicationId + '.providers.SearchSuggestionsProvider'}
Locally cached or obtained from the API.
More flexible that BuildConfig file.
Descriptive method naming.
public interface AppConfig {
boolean isSocialLoginEnabled();
List<MenuItem> getLoggedInUserNavigationMenu(); }
public class WhiteConfiguration implements AppConfig {
private static final List<MenuItem> LOGGED_IN_USER_NAVIGATION_MENU = Collections.unmodifiableList(Arrays.asList( new MenuItem(R.drawable.ic_gamepad, R.string.home), new MenuItem(R.drawable.ic_settings, R.string.settings), new MenuItem(R.drawable.ic_settings, R.string.info) ));
@Override public boolean isSocialLoginEnabled() { return !BuildConfig.DEBUG || BuildConfig.APPLICATION_ID.endsWith(STAGING_APP_ID); }
@Override public List<MenuItem> getLoggedInUserNavigationMenu() { return LOGGED_IN_USER_NAVIGATION_MENU; } }
DESCRIPTIVE METHODS
Method names should be descriptive and should not contain product names.
public interface AppConfig {
boolean isWhite();
boolean isBlue(); }
INTERFACES
Extract functionalities.
Integrate with external dependencies.
Default or product specific implementation.
public interface ImageLoader {
void displayImage(ImageView imageView, @NonNull String imageUrl);
void displayImage(ImageView imageView, @NonNull File imageFile);
}
@Module public class ProvidersModule {
@Provides public ImageLoader provideImageLoader(ImageLoaderType type) { switch(type){ case GLIDE: return new GlideImageLoader(); default: return new PicassoImageLoader(); } }
provided with
configuration file
Include external dependencies only for specific product types.
whiteCompile 'com.github.bumptech.glide:glide:3.6.1' blueCompile 'com.github.bumptech.glide:glide:3.5.0’
public interface Navigation {
<T> void createTrip(FragmentActivity activity, int createTripRequestCode, Map<String, T> params);
}
public interface NavigationBehaviour {
<T> void startCreateTripScreen(FragmentActivity activity, int createTripRequestCode, Map<String, T> params); }
public class NavigationManager implements Navigation {
private NavigationBehaviour navigationBehaviour;
public NavigationManager(NavigationBehaviour navigationBehaviour) { this.navigationBehaviour = navigationBehaviour; }
@Override public <T> void createTrip(FragmentActivity activity, int createTripRequestCode, Map<String, T> params) { navigationBehaviour.startCreateTripScreen(activity, createTripRequestCode, params);
} }
public class DefaultNavigationBehaviour implements NavigationBehaviour {
@Override public <Parcelable> void startCreateTripScreen(FragmentActivity activity, int createTripRequestCode, Map<String, Parcelable> params) {
Intent intent = CreateTripActivity.newIntent(activity, TripType.WALKING, recentStops); activity.startActivityForResult(intent, createTripRequestCode);
} }
public class BlueNavigationBehaviour implements NavigationBehaviour {
@Override public <Parcelable> void startCreateTripScreen(FragmentActivity activity, int createTripRequestCode, Map<String, Parcelable> params) {
Intent intent = PlanTripActivity.newIntent(activity, TripType.CAR, recentStops); activity.startActivityForResult(intent, createTripRequestCode);
} }
Visit infinum.co or find us on social networks:
infinum.co infinumco infinumco infinum
Thank you! ZELJKO.PLESAC@INFINUM.CO @ZELJKOPLESAC
top related