There is a default (not a Design Pattern itself) of Android / Gradle to handle this. The prerequisite would be to use Android Studio and compile your apk using Gradle. For it is Gradle that provides this functionality.
To handle the generation of two different apk's, Gradle lets you define Build / Product Flavors .
Like Build Types (release or debug), Build / Product Flavors are, as the name says, "flavors" ( of features / code, features, settings, and so on) that your application may have. The most common ones are Free , Paid , Phone and Tablet (the latter two being unnecessary depending on the type of customization you will be doing). You can give the name you want for a flavor , it has no limitation.
Correction : Combining a Build Type with a Build Flavor generates a Build Variant . That would be used in fact compilation (this I explain better in the end).
And using Gradle you can generate an apk for each combination of flavor and build type available. Below I'll explain how to do this:
Build Configuration
A simple configuration of your build.gradle
file would be:
apply plugin: 'com.android.application'
android {
compileSdkVersion 21
buildToolsVersion "21.1.2"
defaultConfig {
applicationId "br.com.testegradleflavors"
minSdkVersion 10
targetSdkVersion 21
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
free {
applicationId "be.tamere.testegradleflavors.free"
}
paid {
applicationId "br.com.testegradleflavors"
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:21.0.3'
}
In this example, I define two flavors : free and paid . As Google Play requires, each apk must have a unique ID. Soon each flavor must have a applicationId
different because in the end it will generate a different apk.
It is neither necessary nor recommended to change the package structure to equal the applicationId
of each flavor . This is because Gradle can handle the merge of the current Build Variant files.
Of course, you can make this configuration more elaborate, like Build variables:
productFlavors {
free {
applicationId "be.tamere.testegradleflavors.free"
buildConfigField "String", "VARIAVEL_ESTATICA", "\"free\""
}
paid {
applicationId "br.com.testegradleflavors"
buildConfigField "String", "VARIAVEL_ESTATICA", "\"pago\""
}
}
There are other settings, such as up to Multi-flavor Variants that would be Flavors in multiple levels, but that goes far beyond the scope of the question.
To access these Build variables in Java code:
String variavel = BuildConfig.VARIAVEL_ESTATICA;
Code / resources configuration
Regarding code, just follow this design structure (following the gradle pattern):
Inthisimage,itillustratesmyprojectthathasthreefoldersatthesamehierarchicallevel:mainwiththe/resourcescodecommontoallpossibleBuildVariantsoftheapplication(defaultinaGradleprojectcurrentlycreated),paidwiththeclasses/resources/filesthatarespecifictopaidapkandfreewithclasses/resources/filesspecifictoapkfree.
WhenyoumodifyBuildVariants(bychoosingadifferentflavor),itvisuallydisassociatesfoldersthatarenotbeingused.IntheimageforexampletheMainActivity
appearswitharederrorsymbolinthefreefolder,butthatisbecausethefolderwasdisabledwhenIchoseflavorpaid.Whenyouchangeflavortofree,theinversewilloccur.
Itisgoodnottousethesameresourcename(classes,xmls,filesingeneral)betweenmainandfree/paid.Becausethefeaturesofthespecificpackages(freeandpaid)willoverridethefeaturesofthelessspecific(main).
Whenaflavorischosenforthebuild,itwillconsiderallclassesandresourcesandwillputeverythingtogetherinthesameapk,overwritingwhatithasrepeated(givingflavor).Thefilesthatexistinmainbutdonotexistinflavors,willbeincludedwithoutprobleminapk.
Atthetimeofthebuild,justchooseflavorandtype.Thiscaneitherbebycommandline:
gradlew assembleFreeRelease -- Build para o apk Free em modo Release
gradlew assemblePaidRelease -- Build para o apk Pago em modo Release
gradlew assembleFreeDebug -- Build para o apk Free em modo Debug
-- Demais configurações de build flavor e type
As for Graphical Interface: within Android Studio, just change the Build Variants combobox option as in the image of the project organization.
References for further study: