HiHex FleaMarket is a Gradle Plugin to quickly generate multiple APKs which share the same code, have have different resources or signatures. It is ideal for distributing APKs to multiple Android markets with analytics distinction or customized skins.
HiHex FleaMarket is basically a wrapper around the aapt tool, and provides seamless integration into the Gradle build system.
The Gradle Plugin for Android provides "productFlavor" to create multiple variants of some application. However, productFlavor allows different source code to be used, so this option is extremely slow due to multiple recompilations
Instead of branching off early, HiHex FleaMarket modifies the assembled APK, replacing resources and manifests to form new APKs. This makes the process much faster.
- HiHex FleaMarket uses Gradle 2.6+ and Android Plugin for Gradle 1.3.0+.
Add the plugin to the beginning of the build.gradle of the application module:
plugins {
id 'hihex.fleamarket' version '0.2.0'
}
apply plugin: 'com.android.application'
...The configurations that lead to different APKs are called "channels". These configurations are declared in the channels block:
channels {
defaultConfig {
filename { "${it.name}-v${VERSION_NAME}.apk" }
manifest { c -> analyticsChannel = c.name }
}
create 'google', 'amazon', 'getjar', 'slideme', 'fdroid', 'samsung'
create('baidu') {
resources file('src/customized/baidu/res')
}
}| Statement | Description |
|---|---|
defaultConfig { … } |
Provides the default configuration shared by all channels. Must present at the top of the channels block. |
create 'A', 'B', … |
Declares multiple channels, which shares the same configuration as the defaultConfig. |
create('A') { … } |
Declares a channel, and provide further customization based on the defaultConfig. |
All non-code resources may be customized, but currently HiHex FleaMarket supports the following modifications in each configuration:
defaultConfig {
filename { Channel c ->
"${c.name}.apk"
}
signingConfig android.signingConfig.release
buildType 'release'
flavors 'armv7', 'paidapp'
manifest { Channel c ->
analyticsChannel = c.name
}
values {
replaceStrings ~/MyOldBrand/, 'MyNewBrand'
}
asset 'www/index.html', file('src/customized/default/assets/www/index.html')
resources file('src/customized/default/res')
}| Method name | Description |
|---|---|
filename |
Defines the filename of the APK generated by this channel. The input can be a String or a Channel → String closure, so that the filename pattern may be defined directly in defaultConfig. |
signingConfig |
The private key used to sign the APK. If not specified, this plugin will use the debug key to sign the APK. |
buildType |
Which buildType the channel should modify from. Should be either release or debug. |
flavors |
The productFlavor the channel should modify from. Each channel should base on exactly one build variant (buildType + productFlavor). |
manifest |
Defines a Document.(Channel) → void) closure to modify the AndroidManifest.xml file. |
values |
Defines a ResValue.(Channel) → void) closure to modify all resource values (strings, colors, dimensions, integers, etc.) |
asset |
Insert or replace a file to the assets folder. |
resources |
Replaces existing resources (drawables, layouts, xmls, etc.). The folder should have the same structure as normal res/ folders. |
class Channel {
String name // Name of the channel, i.e. the name in the create() method
String[] flavors // List of productFlavors this channel is based on
String buildType // The buildType this channel is based on
}class ResValue {
String qualifier // Configuration qualifier, e.g. "en-rUS", "hdpi", etc. Nullable.
Element element // Element that represents this resource value in the values.xml.
String type // Tag name of the element, e.g. "string", "color", "dimen", etc.
String name // Name of the resource.
/// Perform regex replacement on all string resources (string, plurals, string-array).
def replaceStrings(Pattern pattern, replacement)
}This plugin provides some convenient extension methods to Document to perform some common operations on the AndroidManifest.xml:
interface Document {
/// Sets the value of XXXX_CHANNEL meta-data in the manifest. Covers most analytic SDKs that
/// supports multiple channels.
def setAnalyticsChannel(String channel)
/// Delete all tags which have the given tag name and `android:name`.
def deleteTagsWithName(String tagName, String name)
/// Adds a <uses-permission> tag
def addUsesPermission(String permissionName)
/// Changes the android:name of all tags
def renameTags(Pattern namePattern, replacement)
}The FleaMarket plugin provides two tasks.
To generate an APK, run the assembleChannelName task. The output APK can be found in build/outputs/flea-market/channelName.apk.
One may also list all channels using the listChannels task.
HiHex FleaMarket is licensed in GPL v3.0 or later.
- If you only need to generate different APKs for different markets, without modifying AndroidManifest nor resources, you may try the mulchannel plugin from Meituan, which promises a speed of 0.1s/APK. This plugin injects files into the META-INF/ folder to skip the code signing steps. Needless to say, this method is much less flexible in customization (e.g. you cannot change the display name or icon), and requires special handling inside the code in the first place.

