Skip to content

Commit

Permalink
Added build flavour support to different app stores (google play, git…
Browse files Browse the repository at this point in the history
…hub and fdroid now supported)

Fix for #1016: Added support to rewrite the Android versionName and versionCode on the fly without touching the original AndroidManifest.xml so that we're not changing it every version bump.
  • Loading branch information
crankycoder committed Oct 31, 2014
1 parent 945f78f commit 204d81c
Show file tree
Hide file tree
Showing 8 changed files with 129 additions and 110 deletions.
5 changes: 3 additions & 2 deletions .gitignore
Expand Up @@ -8,6 +8,7 @@ bin
gen
build
local.properties
gradle.properties

# ignore vim swap files
*.sw?
Expand All @@ -18,11 +19,11 @@ android/libs/*.jar
# ctags
tags

gradle.properties

# Mozilla Special Sauce
# Never commit your private.properties file or your keystore
private.properties
android/properties/**

*.keystore

# Ignore final release APK builds
Expand Down
22 changes: 13 additions & 9 deletions Makefile
@@ -1,25 +1,29 @@
test: unittest
./gradlew testUnittest --info

release_check:
./release_check.py

unittest:
./gradlew assembleUnittest

debug:
./gradlew assembleDebug

github: release_check
./gradlew assembleGithub
sh rename_release.sh github
github:
./release_check.py github
./gradlew assembleGithubRelease
sh rename_release.sh github-release

playstore: release_check
./gradlew assemblePlaystore
sh rename_release.sh playstore
playstore:
./release_check.py playstore
./gradlew assemblePlaystoreRelease
sh rename_release.sh playstore-release

fdroid:
./gradlew assembleFdroidRelease
sh rename_release.sh fdroid-release

clean:
rm -rf android/libs/*.jar
rm -rf outputs/*
./gradlew clean

install_debug:
Expand Down
168 changes: 73 additions & 95 deletions android/build.gradle
Expand Up @@ -2,11 +2,9 @@
def versionMajor = 1
def versionMinor = 2 // minor feature releases
def versionPatch = 0 // This should be bumped for hot fixes
def versionBuild = 0 // This is used to denote which release
// flavor is used (github/playstore/fdroid)

// Double check the versioning
for (versionPart in [versionBuild, versionPatch, versionMinor, versionMajor]) {
for (versionPart in [versionPatch, versionMinor, versionMajor]) {
assert 0 <= versionPart
assert versionPart <= 99
}
Expand Down Expand Up @@ -59,34 +57,49 @@ android {
minSdkVersion 10
targetSdkVersion 18

versionCode versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild
versionName "${versionMajor}.${versionMinor}.${versionPatch}.${versionBuild}"

// I'm so happy I have to compute the versionCode, versionName
// and then duplicate it in the manifest. yay android.
writeVersionCode(versionCode)
writeVersionName(versionName)
versionCode versionMajor * 1000000 + versionMinor * 10000 + versionPatch * 100
versionName "${versionMajor}.${versionMinor}.${versionPatch}"

buildConfigField "boolean", "ROBOLECTRIC", "false"
buildConfigField "String", "MOZILLA_API_KEY", getMozillaApiKey()
buildConfigField "String", "TILE_SERVER_URL", getTileServerUrl()
buildConfigField "String", "MOZILLA_API_KEY", "\"\""
buildConfigField "String", "TILE_SERVER_URL", "\"\""

buildConfigField "boolean", "LABEL_MAP_TILES", "false"

buildConfigField "boolean", "GITHUB", "false"
buildConfigField "boolean", "PLAYSTORE", "false"
buildConfigField "boolean", "FDROID", "false"

// Crash report settings
buildConfigField "String", "ACRA_URI", getAcraURI()
buildConfigField "String", "ACRA_USER", getAcraUser()
buildConfigField "String", "ACRA_PASS", getAcraPass()

buildConfigField "String", "ACRA_URI", "\"http://ec2-54-172-135-65.compute-1.amazonaws.com/acra-stumbler/_design/acra-storage/_update/report\""
buildConfigField "String", "ACRA_USER", "\"mozstumbler\""
buildConfigField "String", "ACRA_PASS", "\"attielintabl\""
}

signingConfigs {
release
}

productFlavors {
github {
buildConfigField "String", "MOZILLA_API_KEY", getMozillaApiKey('github')
buildConfigField "String", "TILE_SERVER_URL", getTileServerUrl('github')
buildConfigField "boolean", "GITHUB", "true"
}

playstore {
buildConfigField "String", "MOZILLA_API_KEY", getMozillaApiKey('playstore')
buildConfigField "String", "TILE_SERVER_URL", getTileServerUrl('playstore')
buildConfigField "boolean", "PLAYSTORE", "true"
}

fdroid {
buildConfigField "String", "MOZILLA_API_KEY", getMozillaApiKey('fdroid')
buildConfigField "String", "TILE_SERVER_URL", getTileServerUrl('fdroid')
buildConfigField "boolean", "FDROID", "true"
}
}

buildTypes {
debug {
jniDebugBuild true
Expand All @@ -103,20 +116,43 @@ android {
signingConfig signingConfigs.release
}

github.initWith(buildTypes.release)
github {
buildConfigField "boolean", "GITHUB", "true"
}

playstore.initWith(buildTypes.release)
playstore {
buildConfigField "boolean", "PLAYSTORE", "true"
}

unittest.initWith(buildTypes.debug)
unittest {
buildConfigField "boolean", "ROBOLECTRIC", "true"
}


applicationVariants.all { variant ->
variant.processManifest.doLast {
println("configuring AndroidManifest.xml");
copy {
from("${buildDir}/intermediates/manifests") {
include "${variant.dirName}/AndroidManifest.xml"
}
into("${buildDir}/intermediates/filtered_manifests")
}
def manifestFile = new
File("${buildDir}/intermediates/filtered_manifests/${variant.dirName}/AndroidManifest.xml")
def content = manifestFile.getText()

def updatedContent = content.replaceAll("ANDROID_VERSIONNAME",
defaultConfig.versionName).replaceAll("ANDROID_VERSIONCODE",
Long.toString(defaultConfig.versionCode))

manifestFile.write(updatedContent)
}
// This is a bit confusing, we want to swap in the
// filtered AndroidManifest.xml file so that we don't
// modify the original AndroidManifest.xml. This prevents
// accidental commit of the mapbox key into source
// control, so we actually modify the pointer in gradle.
variant.processResources.manifestFile = new
File("${buildDir}/intermediates/filtered_manifests/${variant.dirName}/AndroidManifest.xml")
}



}

sourceSets {
Expand All @@ -130,6 +166,7 @@ android {

}


dependencies {
androidTestCompile 'junit:junit:4.10'
androidTestCompile 'org.robolectric:robolectric:2.3'
Expand Down Expand Up @@ -159,7 +196,9 @@ dependencies {
compile "joda-time:joda-time:2.2"

// Acralyzer crash reports
compile 'ch.acra:acra:4.5.0'
compile('ch.acra:acra:4.5.0') {
exclude group: 'org.json'
}

// osmdroid stuff
compile "org.apache.httpcomponents:httpmime:4.0.1"
Expand All @@ -170,8 +209,8 @@ tasks.withType(JavaCompile) {
options.compilerArgs = ['-Xlint:all', '-Werror', '-Xlint:-deprecation']
}


File signFile = rootProject.file('private.properties')
File signFile = rootProject.file('android/properties/signing.properties')
println "Signing file: " + signFile.getAbsolutePath()
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
Expand All @@ -185,66 +224,24 @@ if (signFile.exists()) {
android.buildTypes.release.signingConfig = null
}

String getAcraURI() {
// Yeah, this is lame, opening the file again. Sosume.
File signFile = rootProject.file('private.properties')
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
if (p['ACRA_URI'] == null) {
return '""';
}
return '"' + p['ACRA_URI'] + '"'
}
return '""';
}

String getAcraUser() {
// Yeah, this is lame, opening the file again. Sosume.
File signFile = rootProject.file('private.properties')
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
if (p['ACRA_USER'] == null) {
return '""';
}
return '"' + p['ACRA_USER'] + '"'
}
return '""';
}

String getAcraPass() {
// Yeah, this is lame, opening the file again. Sosume.
File signFile = rootProject.file('private.properties')
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
if (p['ACRA_PASS'] == null) {
return '""';
}
return '"' + p['ACRA_PASS'] + '"'
}
return '""';
}


String getMozillaApiKey() {
String getMozillaApiKey(String scope) {
// Yeah, this is lame, opening the file again. Sosume.
File signFile = rootProject.file('private.properties')
File signFile = rootProject.file("android/properties/private-"+scope+".properties")
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
def result = '"' + p['MozAPIKey'] + '"';
println "Writing custom MozAPIKey: ["+result+"]";
return result;
}
println "No private.properties for Mozilla API Key configuration.."
println "No "+signFile.getAbsolutePath()+" for Mozilla API Key configuration."
return "null";
}

String getTileServerUrl() {
String getTileServerUrl(String scope) {
// Yeah, this is lame, opening the file again. Sosume.
File signFile = rootProject.file('private.properties')
File signFile = rootProject.file("android/properties/private-"+scope+".properties")
if (signFile.exists()) {
Properties p = new Properties()
p.load(new FileInputStream(signFile))
Expand All @@ -259,30 +256,11 @@ String getTileServerUrl() {
return result;
}
}
println "No private.properties for TileServer configuration."
println "No "+signFile.getAbsolutePath()+" for TileServer configuration."
return "null";
}


void writeVersionCode(int versionCode) {
def manifestFile = file("src/main/AndroidManifest.xml")
def pattern = Pattern.compile("versionCode=\"(\\d+)\"")
def manifestText = manifestFile.getText()
def matcher = pattern.matcher(manifestText)
matcher.find()
def manifestContent = matcher.replaceAll("versionCode=\"" + versionCode + "\"")
manifestFile.write(manifestContent)
}

void writeVersionName(String versionName) {
def manifestFile = file("src/main/AndroidManifest.xml")
def patternVersionNumber = Pattern.compile("versionName=\"[^\"]*\"")
def manifestText = manifestFile.getText()
def matcherVersionNumber = patternVersionNumber.matcher(manifestText)
def manifestContent = matcherVersionNumber.replaceAll("versionName=\"" + versionName + "\"")
manifestFile.write(manifestContent)
}

// Yay for apk basenames that you can only figure out by reading the
// gradle source.
project.archivesBaseName = "MozStumbler";
17 changes: 17 additions & 0 deletions android/properties/example.properties
@@ -0,0 +1,17 @@
# These are for signing using a release buildtype
#StoreFile=your_keystore_file_name
#StorePassword=your_keystore_password
#KeyAlias=your_key_alias
#KeyPassword=your_key_password

# This is an optional Mapbox API key
#MapAPIKey=your_mapbox_api_key

# This is your Mozilla Location Service API key
# used to submit data.
MozAPIKey=your_api_key_here

# This is to enable crash reports.
ACRA_URI=http://ec2-54-172-135-65.compute-1.amazonaws.com/acra-stumbler/_design/acra-storage/_update/report
ACRA_USER=mozstumbler
ACRA_PASS=attielintabl
15 changes: 15 additions & 0 deletions android/properties/private-fdroid.properties
@@ -0,0 +1,15 @@
# This is the F-Droid private.properties file
# The only thing specific to f-droid is the Mozilla API Key.
# If you are doing your own custom build, you can obtain
# a unique Mozilla API key from :
# https://location.services.mozilla.com/api

# Your Mozilla API key.
# Information to get an API key is here:
# https://location.services.mozilla.com/api
MozAPIKey=79c8c5e0-d178-4913-bd97-1e65bc377f74

# Common crash reporter keys
ACRA_URI=http://ec2-54-172-135-65.compute-1.amazonaws.com/acra-stumbler/_design/acra-storage/_update/report
ACRA_USER=mozstumbler
ACRA_PASS=attielintabl
4 changes: 2 additions & 2 deletions android/src/main/AndroidManifest.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.mozilla.mozstumbler"
android:versionCode="1020000"
android:versionName="1.2.0.0" >
android:versionCode="ANDROID_VERSIONCODE"
android:versionName="ANDROID_VERSIONNAME" >

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
Expand Down
6 changes: 5 additions & 1 deletion release_check.py
@@ -1,9 +1,13 @@
#!/usr/bin/env python

import sys

props = {}
for line in open('private.properties'):
for line in open('android/properties/private-%s.properties' % sys.argv[-1]):
if len(line.strip()) == 0:
continue
if line[0] == '#':
continue
k, v = line.strip().split('=')
props[k] = v
assert 'MapAPIKey' in props, 'MapAPIKey is ok'
Expand Down
2 changes: 1 addition & 1 deletion rename_release.sh
@@ -1,5 +1,5 @@
#!/bin/sh
# bad hack to rename the final apk
mkdir -p outputs
cmd="cp android/build/outputs/apk/MozStumbler-$1.apk outputs/MozStumbler-v`cat VERSION`.apk"
cmd="cp android/build/outputs/apk/MozStumbler-$1.apk outputs/MozStumbler-`git describe --abbrev=0 --tags`.apk"
`${cmd}`

0 comments on commit 204d81c

Please sign in to comment.