Skip to content

Instantly share code, notes, and snippets.

@milosmns
Last active June 26, 2018 11:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save milosmns/3727211af5c1eb375b62d1a84a01c41f to your computer and use it in GitHub Desktop.
Save milosmns/3727211af5c1eb375b62d1a84a01c41f to your computer and use it in GitHub Desktop.
Android Library - publishing to Maven (THE SILVER BULLET)
This is used for my blog post about publishing Android apps. Start reading here:
https://angrybyte.me/post/174861019530/android-libraries-how-to-1
# Basic runner configuration
os: linux
language: android
sudo: false # Required for the new container-based infrastructure setup
branches:
except:
- release
# Setup environment variables
# ************************************************************** #
# #
# Don't forget to check versions in 'projectRoot > build.gradle' #
# #
# ************************************************************** #
env:
global:
- PLATFORM_TOOLS=27.0.1
- BUILD_TOOLS=27.0.3
- COMPILE_SDK=27
# Enable only JDK 8, source does not build with JDK 7
addons:
apt:
packages:
- oracle-java8-installer
jdk: oraclejdk8
# Pre-configuration step (accept all licenses manually)
install:
- echo y | android update sdk -u -a -t tools
- echo y | android update sdk -u -a -t platform-tools
- echo y | android update sdk -u -a -t build-tools-${BUILD_TOOLS}
- echo y | android update sdk -u -a -t android-${COMPILE_SDK}
- echo y | android update sdk -u -a -t extra-google-m2repository
- echo y | android update sdk -u -a -t extra-android-m2repository
- echo y | android update sdk -u -a -t extra-google-android-support
# Configure Android
android:
# Auto-accept these licenses
licenses:
- 'android-sdk-preview-license-.+'
- 'android-sdk-license-.+'
- 'google-gdk-license-.+'
- '.+'
# Build script config
components:
- tools # Workaround part 1: Get the new `repository-*.xml`
- tools # Workaround part 1: Install latest Android SDK tools
- build-tools-${BUILD_TOOLS}
- platform-tools
# Compile SDK
- android-${COMPILE_SDK}
# Additional components
- extra-google-m2repository
- extra-android-m2repository
- extra-google-android-support
# Use Gradle's cache (unlock on start)
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -rf $HOME/.gradle/caches/*/plugin-resolution/
cache:
apt: true
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache
# Execute the script
script:
- ./gradlew clean
- ./gradlew build
- ./gradlew assemble
# if you want to test: - ./gradlew demo:check
# if you want a test report: - ./gradlew build jacocoTestReport
# If you're tracking code coverage, then start CodeCov bash script when done with everything
# after_success:
# - bash <(curl -s https://codecov.io/bash)
# Basic runner configuration
os: linux
language: android
sudo: false # Required for the new container-based infrastructure setup
branches:
only:
- release
# Setup environment variables
# ************************************************************** #
# #
# Don't forget to check versions in 'projectRoot > build.gradle' #
# #
# ************************************************************** #
env:
global:
- PLATFORM_TOOLS=27.0.1
- BUILD_TOOLS=27.0.3
- COMPILE_SDK=27
- ANDROID_TARGET=android-22 # Enable for connected checks on emulators (Google doesn't support Linux ARMv7 emulation for SDK 23+)
- ANDROID_ABI=armeabi-v7a # Enable for connected checks on emulators
- ADB_INSTALL_TIMEOUT=15 # Wait up to 15 minutes for adb to connect to the emulator
# Enable only JDK 8, source does not build with JDK 7
addons:
apt:
packages:
- oracle-java8-installer
jdk: oraclejdk8
# Pre-configuration step (accept all licenses manually)
install:
- echo y | android update sdk -u -a -t tools
- echo y | android update sdk -u -a -t platform-tools
- echo y | android update sdk -u -a -t build-tools-${BUILD_TOOLS}
- echo y | android update sdk -u -a -t android-${COMPILE_SDK}
- echo y | android update sdk -u -a -t extra-google-m2repository
- echo y | android update sdk -u -a -t extra-android-m2repository
- echo y | android update sdk -u -a -t extra-google-android-support
- echo y | android update sdk -u -a -t addon-google_apis-google-${COMPILE_SDK}
# Configure Android
android:
# Auto-accept these licenses
licenses:
- 'android-sdk-preview-license-.+'
- 'android-sdk-license-.+'
- 'google-gdk-license-.+'
- '.+'
# Build script config
components:
- tools # Workaround part 1: Get the new `repository-*.xml`
- tools # Workaround part 1: Install latest Android SDK tools
- build-tools-${BUILD_TOOLS}
- platform-tools
# Compile SDK
- android-${COMPILE_SDK}
# Emulator SDK
- ${ANDROID_TARGET}
# Additional components
- extra-google-m2repository
- extra-android-m2repository
- extra-google-android-support
# To run emulator(s) during tests, enable some of these: (Linux ARMv7 goes up to 22 only)
# - sys-img-armeabi-v7a-android-22
# - sys-img-armeabi-v7a-android-21
# - sys-img-armeabi-v7a-android-19
# - sys-img-armeabi-v7a-android-14
# - sys-img-armeabi-v7a-android-9
- sys-img-${ANDROID_ABI}-${ANDROID_TARGET} # Configurable system image
# Use Gradle's cache (unlock on start)
before_cache:
- rm -f $HOME/.gradle/caches/modules-2/modules-2.lock
- rm -rf $HOME/.gradle/caches/*/plugin-resolution/
cache:
apt: true
directories:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/
- $HOME/.android/build-cache
# Start up the emulator
before_script:
- echo no | android create avd --force -n test -t $ANDROID_TARGET --abi $ANDROID_ABI
- emulator -avd test -no-skin -no-audio -no-window &
- android-wait-for-emulator
- adb shell setprop dalvik.vm.dexopt-flags v=n,o=v
- adb shell input keyevent 82 & # Unlock emulator if locked
# Execute the script
script:
# Build and prepare
- ./gradlew clean
- ./gradlew assemble
- ./gradlew app:check
- ./gradlew build
# if you want a test report: - ./gradlew build jacocoTestReport
# To run device Android (and CodeCov) tests, enable these lines (requires an Android emulator):
- ./gradlew assembleAndroidTest
- ./gradlew connectedCheck
# If you're tracking code coverage, then start CodeCov bash script when done with everything
# after_success:
# - bash <(curl -s https://codecov.io/bash)
# Setup the deployment step (only on release branches) - upload to GitHub Releases and Bintray
before_deploy:
- ./gradlew clean blinkerview:install blinkerview:bintrayUpload
- ./gradlew clean assemble
deploy:
provider: releases
api_key: ${GITHUB_OAUTH_TOKEN}
file_glob: true
file: app/build/outputs/apk/*
skip_cleanup: true
overwrite: true
on:
tag: true
branch: release
after_deploy:
- echo "Deployment finished."
apply plugin: 'com.android.application'
android {
// versions are declared in projectRoot > build.gradle
compileSdkVersion COMPILE_SDK
buildToolsVersion BUILD_TOOLS
defaultConfig {
// app ID should also be an external variable if you plan to change it
// in my case, I don't change it ever (since it's a demo app)
applicationId "me.angrybyte.blinkerdemo"
// versions are declared in projectRoot > build.gradle
minSdkVersion MINIMUM_SDK
targetSdkVersion TARGET_SDK
versionCode VERSION_CODE
versionName VERSION_NAME
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
// this is a demo app only, don't worry about signing :)
signingConfigs {
release {
keyAlias SIGNING_NAME
keyPassword SIGNING_NAME
storeFile file('../signing/keystore.jks')
storePassword SIGNING_NAME
}
}
// CI note: specific options for TravisCI emulators (they take a while to start)
adbOptions {
timeOutInMs 20 * 60 * 1000 // 20 minutes
installOptions "-d", "-t"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
// if you don't support Java 8 sugar, you can just delete this block
// but you really should look into supporting it
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
// versions are declared in projectRoot > build.gradle
implementation "com.android.support:appcompat-v7:$APPCOMPAT"
// this one should also go outside if you plan on changing it ever (I don't)
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
// to use your library as a local dependency (before uploading):
implementation project(':blinkerview')
// to use your library as a remote dependency (after uploading):
// and also change the package to be external if you plan on using this (I don't)
// implementation "me.angrybyte.blinkerview:blinkerview:$VERSION_NAME"
}
buildscript {
// repositories to fetch plugins from
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
}
}
// you may need to use the old syntax here for older Gradle versions (see the dependencies block above)
plugins {
id "com.github.dcendents.android-maven" version "2.1" // used for generating Maven files
id "com.jfrog.bintray" version "1.8.0" // used for uploading to Bintray/jCenter (sync to MavenCentral is automatic)
}
// repositories to fetch module dependencies from
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
// external variables, available outside of this file (i.e. in module config files)
ext {
// CI note: if changed, cherry-pick to 'release' branch to auto-deploy
// only *git tagged* commits on release branch will get deployed
VERSION_CODE = 101
VERSION_NAME = "1.0.1"
SIGNING_NAME = "blinkerview"
// CI note: don't forget to update this config in: '.travis.yml'
BUILD_TOOLS = "27.0.3"
MINIMUM_SDK = 15
COMPILE_SDK = 27
TARGET_SDK = 27
// app/library module dependency versions
APPCOMPAT = "27.1.1"
// ESPRESSO = "2.2.2"
// JUNIT = "4.12"
// ROBOLECTRIC = "3.3.2"
// anything else you might need
}
// apply the two plugins, one for generating Maven files, one for uploading to Bintray
apply plugin: 'com.jfrog.bintray'
apply plugin: 'com.github.dcendents.android-maven'
// *****************************************************************************************************
// NOTE: Configuration constants come from gradle.properties, local.properties and environment variables
// *****************************************************************************************************
// sets the project version
version = VERSION_NAME
group = GROUP
// Bintray deployment config
def projectName = project.rootProject.name
def localPropertiesName = 'local.properties'
def isLocalBuild = project.rootProject.file(localPropertiesName).exists()
def uploadConfig = [
user : '',
apiKey : '',
gpgPassword: '',
ossUser : '',
ossPassword: ''
]
if (!isLocalBuild) {
// CI build, load from environment variables
println "# $projectName: '$localPropertiesName' not found, loading deployment config from environment variables"
uploadConfig.user = System.env.BINTRAY_USER
uploadConfig.apiKey = System.env.BINTRAY_API_KEY
uploadConfig.gpgPassword = System.env.BINTRAY_GPG_PASSWORD
uploadConfig.ossUser = System.env.BINTRAY_OSS_USER
uploadConfig.ossPassword = System.env.BINTRAY_OSS_PASSWORD
} else {
// Local build, load from local.properties
println "# $projectName: '$localPropertiesName' found, loading deployment config from file"
Properties fileProperties = new Properties()
fileProperties.load(project.rootProject.file(localPropertiesName).newDataInputStream())
uploadConfig.user = fileProperties.getProperty('bintray.user')
uploadConfig.apiKey = fileProperties.getProperty('bintray.apikey')
uploadConfig.gpgPassword = fileProperties.getProperty('bintray.gpg.password')
uploadConfig.ossUser = fileProperties.getProperty('bintray.oss.user')
uploadConfig.ossPassword = fileProperties.getProperty('bintray.oss.password')
}
// configure the Bintray upload plugin
bintray {
user = uploadConfig.user
key = uploadConfig.apiKey
configurations = ['archives']
pkg {
repo = 'maven'
name = POM_ARTIFACT_ID
desc = POM_DESCRIPTION
websiteUrl = POM_URL
issueTrackerUrl = POM_ISSUE_URL
vcsUrl = POM_SCM_URL
licenses = ["Apache-2.0"]
publish = true
publicDownloadNumbers = true
// noinspection GroovyAssignabilityCheck
version {
desc = POM_DESCRIPTION
gpg {
sign = true // Determines whether to GPG sign the files. The default is false
passphrase = uploadConfig.gpgPassword // Optional. The passphrase for GPG signing
}
// Auto-sync to MavenCentral when uploaded to jCenter successfully
mavenCentralSync {
sync = true
user = uploadConfig.ossUser
password = uploadConfig.ossPassword
close = '1'
}
}
}
}
// configure the Maven plugin for Android and non-Android modules
if (project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')) {
install {
repositories.mavenInstaller {
configuration = configurations.archives
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
}
}
}
}
}
// Re-configure androidJavadocs as it may fail on some builds due to missing Gradle task (older versions)
task androidJavadocs(type: Javadoc) {
source = android.sourceSets.main.java.source
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
failOnError true // you can also disable this if you think docs ARE not IMPORTANT!!!!!!11one
println "# $projectName: Configured Android javadocs"
}
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
classifier = 'javadoc'
from androidJavadocs.destinationDir
}
task androidSourcesJar(type: Jar) {
classifier = 'sources'
from android.sourceSets.main.java.source
}
} else {
// this is config for a non-Android module
install {
repositories.mavenInstaller {
pom.groupId = GROUP
pom.artifactId = POM_ARTIFACT_ID
pom.version = VERSION_NAME
pom.project {
name POM_NAME
packaging POM_PACKAGING
description POM_DESCRIPTION
url POM_URL
scm {
url POM_SCM_URL
connection POM_SCM_CONNECTION
developerConnection POM_SCM_DEV_CONNECTION
}
licenses {
license {
name POM_LICENCE_NAME
url POM_LICENCE_URL
distribution POM_LICENCE_DIST
}
}
developers {
developer {
id POM_DEVELOPER_ID
name POM_DEVELOPER_NAME
email POM_DEVELOPER_EMAIL
}
}
}
}
}
// configure sources and documentation tasks (needed as default config fails on some newer Gradle versions)
task sourcesJar(type: Jar, dependsOn: classes) {
classifier = 'sources'
from sourceSets.main.allSource
}
task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.getDestinationDir()
failOnError false
println "# $projectName: Configured JAR javadocs"
}
}
// another workaround...
if (JavaVersion.current().isJava8Compatible()) {
allprojects {
tasks.withType(Javadoc) {
options.addStringOption('Xdoclint:none', '-quiet')
}
}
}
// one more output config specific for Android modules (but keeping the behavior for non-Android modules)
artifacts {
if (project.getPlugins().hasPlugin('com.android.application') || project.getPlugins().hasPlugin('com.android.library')) {
archives androidSourcesJar
archives androidJavadocsJar
} else {
archives sourcesJar
archives javadocJar
}
}
# Project-wide Gradle settings
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true << best if left disabled for CI builds
# POM project location config
POM_URL=https://github.com/milosmns/blinking-image-view
POM_SCM_URL=https://github.com/milosmns/blinking-image-view
POM_SCM_CONNECTION=scm:git:git://github.com/milosmns/blinking-image-view.git
POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com:milosmns/blinking-image-view.git
POM_ISSUE_URL=https://github.com/milosmns/blinking-image-view/issues
# POM licensing config
POM_LICENCE_NAME=GNU GENERAL PUBLIC LICENSE
POM_LICENCE_URL=https://www.gnu.org/licenses/gpl-3.0.en.html
POM_ALL_LICENCES=['GPL-3.0']
POM_LICENCE_DIST=repo
# POM project labeling
POM_NAME=Blinker View
POM_DESCRIPTION=A simple Android View that blinks the source image
POM_ARTIFACT_ID=blinkerview
POM_PACKAGING=aar
GROUP=me.angrybyte.blinkerview
# POM developer config
POM_DEVELOPER_ID=milosmns
POM_DEVELOPER_NAME=Milos Marinkovic
POM_DEVELOPER_EMAIL=milosmns@gmail.com
apply plugin: 'com.android.library'
android {
// versions are declared in projectRoot > build.gradle
compileSdkVersion COMPILE_SDK
buildToolsVersion BUILD_TOOLS
defaultConfig {
// versions are declared in projectRoot > build.gradle
minSdkVersion MINIMUM_SDK
targetSdkVersion TARGET_SDK
versionCode VERSION_CODE
versionName VERSION_NAME
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
// this is used in the demo app only, don't worry about signing :)
signingConfigs {
release {
keyAlias SIGNING_NAME
keyPassword SIGNING_NAME
storeFile file('../signing/keystore.jks')
storePassword SIGNING_NAME
}
}
// CI note: specific options for TravisCI emulators (they take a while to start)
adbOptions {
timeOutInMs 20 * 60 * 1000 // 20 minutes
installOptions "-d", "-t"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.release
}
}
// if you don't support Java 8 sugar, you can just delete this block
// but you really should look into supporting it
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
// versions are declared in projectRoot > build.gradle
implementation "com.android.support:appcompat-v7:$APPCOMPAT"
}
// a customized script that combines configuration for both Maven plugin and Bintray plugin
// it's located in `projectRoot/gradle`
apply from: '../gradle/gradle-mvn-push.gradle'
# This file is automatically generated by Android Studio.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED! << not really, this config was kept for years in my case
#
# This file must *NOT* be checked into Version Control Systems,
# as it contains information specific to your local configuration.
#
# Location of the SDK. This is only used by Gradle.
# For customization when using a Version Control System, please read the
# header note.
# Sun Apr 09 16:34:43 CEST 2016
sdk.dir=/wherever/your/sdk/is/located/
# jCenter config
bintray.user=username_placeholder
bintray.apikey=apikey_placeholder
bintray.gpg.password=password_placeholder
# MavenCentral config
bintray.oss.user=username_placeholder
bintray.oss.password=password_placeholder
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment