Bug 1411654 - Part 4: Use flavorDimensions to simplify {with,without}GeckoBinaries logic. r=maliu
MozReview-Commit-ID: 2rbsP6A0BY0
--- a/mobile/android/app/build.gradle
+++ b/mobile/android/app/build.gradle
@@ -1,15 +1,17 @@
buildDir "${topobjdir}/gradle/build/mobile/android/app"
apply plugin: 'com.android.application'
apply plugin: 'checkstyle'
apply plugin: 'com.getkeepsafe.dexcount'
apply plugin: 'findbugs'
+apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"
+
dexcount {
format = "tree"
}
android {
compileSdkVersion project.ext.compileSdkVersion
defaultConfig {
@@ -86,45 +88,23 @@ android {
// The "audience" flavour dimension distinguishes between _local_ builds (intended for
// development) and _official_ builds (intended for testing in automation and to ship in one of
// the Fennec distribution channels).
//
// The "skin" flavor dimension distinguishes between different user interfaces. We sometimes
// want to develop significant new user interface pieces in-tree that don't ship (even in the
// Nightly channel) while under development. A new "skin" flavour allows us to develop such
// pieces in Gradle without changing the mainline configuration.
- flavorDimensions "audience", "skin"
+
+ project.configureProductFlavors.delegate = it
+ project.configureProductFlavors()
+
+ flavorDimensions "audience", "geckoBinaries", "minApi", "skin"
productFlavors {
- // For API 21+ - with pre-dexing, this will be faster for local development.
- local {
- dimension "audience"
-
- // For pre-dexing, setting `minSdkVersion 21` allows the Android gradle plugin to
- // pre-DEX each module and produce an APK that can be tested on
- // Android Lollipop without time consuming DEX merging processes.
- minSdkVersion 21
- dexOptions {
- preDexLibraries true
- }
- }
- // For API < 21 - does not support pre-dexing because local development
- // is slow in that case.
- localOld {
- dimension "audience"
- }
-
- // Automation builds. We use "official" rather than "automation" to drive these builds down
- // the list of configurations that Android Studio offers, thereby making it _not_ the
- // default. This avoids a common issue with "omni.ja" not being packed into the default APK
- // built and deployed by Android Studio.
- official {
- dimension "audience"
- }
-
// Since Firefox 57, the mobile user interface has followed the Photon design.
// Before Firefox 57, the user interface followed the Australis design.
photon {
dimension "skin"
}
}
sourceSets {
@@ -256,25 +236,20 @@ dependencies {
if (mozconfig.substs.MOZ_ANDROID_GCM) {
implementation "com.google.android.gms:play-services-basement:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
implementation "com.google.android.gms:play-services-base:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
implementation "com.google.android.gms:play-services-gcm:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
implementation "com.google.android.gms:play-services-measurement:${mozconfig.substs.ANDROID_GOOGLE_PLAY_SERVICES_VERSION}"
}
- // Include LeakCanary in most gradle based builds. LeakCanary adds about 5k methods, so we disable
- // it for the (non-proguarded, non-predex) localOld builds to allow space for other libraries.
- // Gradle based tests include the no-op version. Mach based builds only include the no-op version
- // of this library.
- // It doesn't seem like there is a non-trivial way to be conditional on 'localOld', so instead we explicitly
- // define a version of leakcanary for every flavor:
+ // Include LeakCanary in local builds, but not in official builds. Mach
+ // builds target the official audience, so LeakCanary will not be included
+ // in any Mach build.
localImplementation 'com.squareup.leakcanary:leakcanary-android:1.4-beta1'
- localOldImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
- officialImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
officialImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1'
implementation project(path: ':geckoview')
implementation project(path: ':thirdparty')
testImplementation 'junit:junit:4.12'
testImplementation 'org.robolectric:robolectric:3.5.1'
@@ -366,28 +341,25 @@ android.applicationVariants.all { varian
// re-entrant. Official builds are driven by the moz.build system and
// should never be re-entrant in this way.
if (!((variant.productFlavors*.name).contains('official'))) {
syncPreprocessedJava.dependsOn rootProject.generateCodeAndResources
syncPreprocessedRes.dependsOn rootProject.generateCodeAndResources
rewriteManifestPackage.dependsOn rootProject.generateCodeAndResources
}
- // Official automation builds don't include Gecko binaries, since those binaries are not
- // produced until after build time (at package time). official Therefore, automation builds
- // include the Gecko binaries into the APK at package time. The "withGeckoBinaries" variant of
- // the :geckoview project also does this. (It does what it says on the tin!) For notes on this
- // approach, see mobile/android/gradle/with_gecko_binaries.gradle.
-
- // Like 'local' or 'localOld'.
- def audienceDimension = variant.productFlavors[0].name
-
- // :app uses :geckoview:release and handles it's own Gecko binary inclusion,
- // even though this would be most naturally done in the :geckoview project.
- if (!audienceDimension.equals('official')) {
+ // When driven from moz.build via |mach build|, Gradle does not require or
+ // use Gecko binaries. It's only |mach package| that packs the Gecko
+ // binaries into the resulting APK. The "withoutGeckoBinaries" variants
+ // handle this. When driven from Android Studio or Gradle, the
+ // "withGeckoBinaries" variants handle packing the Gecko binaries into the
+ // resulting APK (for on-device deployment). They also update the Omnijars
+ // as necessary, smoothing out the edit-compile-test development cycle.
+ // They do what they say on the tin!
+ if ((variant.productFlavors*.name).contains('withGeckoBinaries')) {
configureVariantWithGeckoBinaries(variant)
}
}
android.applicationVariants.all { variant ->
configureApplicationVariantWithJNIWrappers(variant, "Fennec")
}
--- a/mobile/android/geckoview/build.gradle
+++ b/mobile/android/geckoview/build.gradle
@@ -1,12 +1,14 @@
buildDir "${topobjdir}/gradle/build/mobile/android/geckoview"
apply plugin: 'com.android.library'
+apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"
+
// This converts MOZ_APP_VERSION into an integer
// version code.
//
// We take something like 58.1.2a1 and come out with 5800102
// This gives us 3 digits for the major number, and 2 digits
// each for the minor and build number. Beta and Release
def computeVersionCode() {
String appVersion = mozconfig.substs.MOZ_APP_VERSION
@@ -94,24 +96,18 @@ android {
// Official corresponds, roughly, to whether this build is performed on
// Mozilla's continuous integration infrastructure. You should disable
// developer-only functionality when this flag is set.
// This makes no sense for GeckoView and should be removed as soon as possible.
buildConfigField 'boolean', 'MOZILLA_OFFICIAL', mozconfig.substs.MOZILLA_OFFICIAL ? 'true' : 'false';
}
- buildTypes {
- withGeckoBinaries {
- initWith release
- }
- withoutGeckoBinaries { // For clarity and consistency throughout the tree.
- initWith release
- }
- }
+ project.configureProductFlavors.delegate = it
+ project.configureProductFlavors()
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
dexOptions {
javaMaxHeapSize "2g"
@@ -152,24 +148,19 @@ android {
dependencies {
implementation "com.android.support:support-v4:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
implementation "com.android.support:palette-v7:${mozconfig.substs.ANDROID_SUPPORT_LIBRARY_VERSION}"
}
apply from: "${topsrcdir}/mobile/android/gradle/with_gecko_binaries.gradle"
android.libraryVariants.all { variant ->
- // Like 'debug', 'release', or 'withGeckoBinaries'.
- def buildType = variant.buildType.name
-
- // It would be most natural for :geckoview to always include the Gecko
- // binaries, but that's difficult; see the notes in
- // mobile/android/gradle/with_gecko_binaries.gradle. Instead :app uses
- // :geckoview:release and handles it's own Gecko binary inclusion.
- if (buildType.equals('withGeckoBinaries')) {
+ // See the notes in mobile/android/app/build.gradle for details on including
+ // Gecko binaries and the Omnijar.
+ if ((variant.productFlavors*.name).contains('withGeckoBinaries')) {
configureVariantWithGeckoBinaries(variant)
}
// Javadoc and Sources JAR configuration cribbed from
// https://github.com/mapbox/mapbox-gl-native/blob/d169ea55c1cfa85cd8bf19f94c5f023569f71810/platform/android/MapboxGLAndroidSDK/build.gradle#L85
// informed by
// https://code.tutsplus.com/tutorials/creating-and-publishing-an-android-library--cms-24582,
// and amended from numerous Stackoverflow posts.
@@ -195,22 +186,22 @@ android.libraryVariants.all { variant ->
options.docTitle = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
options.header = "GeckoView ${mozconfig.substs.MOZ_APP_VERSION} API"
options.noTimestamp = true
options.noIndex = true
options.noQualifiers = ['java.lang']
options.tags = ['hide:a:']
}
- task "javadocJar${name.capitalize()}"(type: Jar, dependsOn: javadoc) {
+ def javadocJar = task("javadocJar${name.capitalize()}", type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from javadoc.destinationDir
}
- task "sourcesJar${name.capitalize()}"(type: Jar) {
+ def sourcesJar = task("sourcesJar${name.capitalize()}", type: Jar) {
classifier 'sources'
description = "Generate Javadoc for build variant $name"
destinationDir = new File(destinationDir, variant.baseName)
from files(variant.javaCompile.source)
}
}
android.libraryVariants.all { variant ->
@@ -238,32 +229,32 @@ uploadArchives {
}
// This is all related to the withGeckoBinaries approach; see
// mobile/android/gradle/with_gecko_binaries.gradle.
afterEvaluate {
// The bundle tasks are only present when the particular configuration is
// being built, so this task might not exist. (This is due to the way the
// Android Gradle plugin defines things during configuration.)
- def bundleWithGeckoBinaries = tasks.findByName('bundleWithGeckoBinaries')
+ def bundleWithGeckoBinaries = tasks.findByName('bundleOfficialWithGeckoBinariesNoMinApiRelease')
if (!bundleWithGeckoBinaries) {
return
}
// Remove default configuration, which is the release configuration, when
// we're actually building withGeckoBinaries. This makes `gradle install`
// install the withGeckoBinaries artifacts, not the release artifacts (which
// are withoutGeckoBinaries and not suitable for distribution.)
def Configuration archivesConfig = project.getConfigurations().getByName('archives')
archivesConfig.artifacts.removeAll { it.extension.equals('aar') }
artifacts {
// Instead of default (release) configuration, publish one with Gecko binaries.
- archives bundleWithGeckoBinaries
+ archives bundleOfficialWithGeckoBinariesNoMinApiRelease
// Javadoc and sources for developer ergononomics.
- archives javadocJarWithGeckoBinaries
- archives sourcesJarWithGeckoBinaries
+ archives javadocJarOfficialWithGeckoBinariesNoMinApiRelease
+ archives sourcesJarOfficialWithGeckoBinariesNoMinApiRelease
}
}
// Bug 1353055 - Strip 'vars' debugging information to agree with moz.build.
apply from: "${topsrcdir}/mobile/android/gradle/debug_level.gradle"
android.libraryVariants.all configureVariantDebugLevel
--- a/mobile/android/geckoview_example/build.gradle
+++ b/mobile/android/geckoview_example/build.gradle
@@ -1,64 +1,44 @@
buildDir "${topobjdir}/gradle/build/mobile/android/geckoview_example"
apply plugin: 'com.android.application'
+apply from: "${topsrcdir}/mobile/android/gradle/product_flavors.gradle"
+
android {
compileSdkVersion project.ext.compileSdkVersion
defaultConfig {
targetSdkVersion project.ext.targetSdkVersion
minSdkVersion project.ext.minSdkVersion
manifestPlaceholders = project.ext.manifestPlaceholders
applicationId "org.mozilla.geckoview_example"
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
- // This is extremely frustrating, but the only way to do it automation for
- // now. Without this, we only get a "debugAndroidTest" configuration; we
- // have no "withoutGeckoBinariesAndroidTest" configuration.
- testBuildType "withoutGeckoBinaries"
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
- withGeckoBinaries { // For consistency with :geckoview project in Task Cluster invocations.
- initWith debug
- }
- withoutGeckoBinaries { // Logical negation of withGeckoBinaries.
- initWith debug
- }
}
+
+ project.configureProductFlavors.delegate = it
+ project.configureProductFlavors()
}
dependencies {
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:support-annotations:23.4.0'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:2.2.2'
androidTestImplementation 'com.android.support.test:runner:0.5'
// Not defining this library again results in test-app assuming 23.1.1, and the following errors:
// "Conflict with dependency 'com.android.support:support-annotations'. Resolved versions for app (23.4.0) and test app (23.1.1) differ."
androidTestImplementation 'com.android.support:support-annotations:23.4.0'
implementation project(path: ':geckoview')
}
-
-apply from: "${topsrcdir}/mobile/android/gradle/with_gecko_binaries.gradle"
-
-android.applicationVariants.all { variant ->
- // Like 'debug', 'release', or 'withoutGeckoBinaries'.
- def buildType = variant.buildType.name
-
- // It would be most natural for :geckoview to always include the Gecko
- // binaries, but that's difficult; see the notes in
- // mobile/android/gradle/with_gecko_binaries.gradle. Instead we handle our
- // own Gecko binary inclusion.
- if (!buildType.equals('withoutGeckoBinaries')) {
- configureVariantWithGeckoBinaries(variant)
- }
-}
--- a/mobile/android/gradle.configure
+++ b/mobile/android/gradle.configure
@@ -41,30 +41,33 @@ set_config('GRADLE', gradle)
def gradle_android_build_config():
def capitalize(s):
# str.capitalize lower cases trailing letters.
if s:
return s[0].upper() + s[1:]
else:
return s
- # It's not really possible to abstract the GeckoView details just yet; post
- # Android-Gradle plugin 3.0+, the configurations can be more sensible and
- # we'll do this work.
def variant(productFlavors, buildType):
return namespace(
productFlavors=productFlavors,
buildType=buildType,
# Like 'OfficialWithoutGeckoBinariesPhotonDebug'
name = ''.join(capitalize(t) for t in chain(productFlavors, (buildType, )))
)
return namespace(
app=namespace(
- variant=variant(('official', 'photon'), 'debug'),
+ variant=variant(('official', 'withoutGeckoBinaries', 'noMinApi', 'photon'), 'debug'),
+ ),
+ geckoview=namespace(
+ variant=variant(('official', 'withGeckoBinaries', 'noMinApi'), 'release'),
+ ),
+ geckoview_example=namespace(
+ variant=variant(('official', 'withGeckoBinaries', 'noMinApi'), 'debug'),
),
)
@depends(gradle_android_build_config)
def gradle_android_app_variant_name(build_config):
'''Like "officialPhotonDebug".'''
def uncapitalize(s):
@@ -77,17 +80,17 @@ def gradle_android_app_variant_name(buil
set_config('GRADLE_ANDROID_APP_VARIANT_NAME', gradle_android_app_variant_name)
@depends(gradle_android_build_config)
def gradle_android_app_tasks(build_config):
'''Gradle tasks run by |mach android assemble-app|.'''
return [
- 'geckoview:generateJNIWrappersForGeneratedRelease',
+ 'geckoview:generateJNIWrappersForGenerated{geckoview.variant.name}'.format(geckoview=build_config.geckoview),
'app:generateJNIWrappersForFennec{app.variant.name}'.format(app=build_config.app),
'app:assemble{app.variant.name}'.format(app=build_config.app),
'app:assemble{app.variant.name}AndroidTest'.format(app=build_config.app),
]
set_config('GRADLE_ANDROID_APP_TASKS', gradle_android_app_tasks)
@@ -170,19 +173,19 @@ def gradle_android_findbugs_tasks(build_
set_config('GRADLE_ANDROID_FINDBUGS_TASKS', gradle_android_findbugs_tasks)
@depends(gradle_android_build_config)
def gradle_android_archive_geckoview_tasks(build_config):
'''Gradle tasks run by |mach android archive-geckoview|.'''
return [
- 'geckoview:assembleWithGeckoBinaries',
- 'geckoview_example:assembleWithGeckoBinaries',
- 'geckoview_example:assembleWithGeckoBinariesAndroidTest',
+ 'geckoview:assemble{geckoview.variant.name}'.format(geckoview=build_config.geckoview),
+ 'geckoview_example:assemble{geckoview_example.variant.name}'.format(geckoview_example=build_config.geckoview_example),
+ 'geckoview_example:assemble{geckoview_example.variant.name}AndroidTest'.format(geckoview_example=build_config.geckoview_example),
'geckoview:uploadArchives',
]
set_config('GRADLE_ANDROID_ARCHIVE_GECKOVIEW_TASKS', gradle_android_archive_geckoview_tasks)
@depends(
gradle_android_app_tasks,
--- a/mobile/android/gradle/debug_level.gradle
+++ b/mobile/android/gradle/debug_level.gradle
@@ -1,20 +1,17 @@
/* -*- Mode: Groovy; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Bug 1353055 - Strip 'vars' debugging information to agree with moz.build.
ext.configureVariantDebugLevel = { variant ->
- // Like 'debug', 'release', or 'withGeckoBinaries'.
+ // Like 'debug' or 'release'.
def buildType = variant.buildType.name
- // For :app, like 'local', 'localOld', or 'official'. For other projects, null.
- def audienceDimension = variant.productFlavors[0]?.name
-
// The default is 'lines,source,vars', which includes debugging information
// that is quite large: roughly 500kb for Fennec. Therefore we remove
// 'vars' unless we're producing a debug build, where it is useful.
- if (!'debug'.equals(buildType) || 'official'.equals(audienceDimension)) {
+ if (!'debug'.equals(buildType) || (variant.productFlavors*.name).contains('official')) {
variant.javaCompile.options.debugOptions.debugLevel = 'lines,source'
}
}
new file mode 100644
--- /dev/null
+++ b/mobile/android/gradle/product_flavors.gradle
@@ -0,0 +1,48 @@
+/* -*- Mode: Groovy; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ext.configureProductFlavors = {
+ flavorDimensions "audience", "geckoBinaries", "minApi"
+ productFlavors {
+ local {
+ dimension "audience"
+ }
+
+ // Automation builds. We use "official" rather than "automation" to drive these builds down
+ // the list of configurations that Android Studio offers, thereby making it _not_ the
+ // default. This avoids a common issue with "omni.ja" not being packed into the default APK
+ // built and deployed by Android Studio.
+ official {
+ dimension "audience"
+ }
+
+ withGeckoBinaries {
+ dimension "geckoBinaries"
+ }
+
+ withoutGeckoBinaries {
+ dimension "geckoBinaries"
+ }
+
+ // For API 21+ - with pre-dexing, this will be faster for local development.
+ minApi21 {
+ dimension "minApi"
+
+ // For pre-dexing, setting `minSdkVersion 21` allows the Android gradle plugin to
+ // pre-DEX each module and produce an APK that can be tested on
+ // Android Lollipop without time consuming DEX merging processes.
+ minSdkVersion 21
+ dexOptions {
+ preDexLibraries true
+ }
+ }
+
+ // For API < 21 - does not support pre-dexing because local development
+ // is slow in that case.
+ noMinApi {
+ dimension "minApi"
+ }
+ }
+}
--- a/mobile/android/gradle/with_gecko_binaries.gradle
+++ b/mobile/android/gradle/with_gecko_binaries.gradle
@@ -1,51 +1,27 @@
/* -*- Mode: Groovy; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-// We run fairly hard into a fundamental limitation of the Android Gradle
-// plugin. There are many bugs filed about this, but
-// https://code.google.com/p/android/issues/detail?id=216978#c6 is a reason one.
-// The issue is that we need fine-grained control over when to include Gecko's
-// binary libraries into the GeckoView AAR and the Fennec APK, and that's hard
-// to achieve. In particular:
-//
-// * :app:official* wants :geckoview to not include Gecko binaries (official
-// * automation build, before package)
-//
-// * :geckoview:withLibraries wants :geckoview to include Gecko binaries
-// * (automation build, after package)
-//
-// * non-:app:official* wants :geckoview to include Gecko binaries (local
-// * build, always after package)
-//
-// publishNonDefault (see
-// http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Library-Publication)
-// is intended to address this, but doesn't handle our case. That option always
-// builds *all* configurations, which fails when the required Gecko binaries
-// don't exist (automation build, before package). So instead, we make both
-// :app and :geckoview both know how to include the Gecko binaries, and use a
-// non-default, non-published :geckoview:withGeckoBinaries configuration to
-// handle automation's needs. Simple, right?
-
// The omnijar inputs are listed as resource directory inputs to a dummy JAR.
// That arrangement labels them nicely in IntelliJ. See the comment in the
// :omnijar project for more context.
evaluationDependsOn(':omnijar')
-task buildOmnijar(type:Exec) {
+task buildOmnijars(type:Exec) {
dependsOn rootProject.generateCodeAndResources
// See comment in :omnijar project regarding interface mismatches here.
inputs.file(project(':omnijar').sourceSets.main.resources.srcDirs).skipWhenEmpty()
- // Produce a single output file.
+ // Produce both the Fennec and the GeckoView omnijars.
outputs.file "${topobjdir}/dist/fennec/assets/omni.ja"
+ outputs.file "${topobjdir}/dist/geckoview/assets/omni.ja"
workingDir "${topobjdir}"
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/base"
args 'gradle-omnijar'
@@ -55,80 +31,79 @@ task buildOmnijar(type:Exec) {
errorOutput = standardOutput
doLast {
if (execResult.exitValue != 0) {
throw new GradleException("Process '${commandLine}' finished with non-zero exit value ${execResult.exitValue}:\n\n${standardOutput.toString()}")
}
}
}
-task syncOmnijarFromDistDir(type: Sync) {
- // :app needs the full Fennec omni.ja, whereas other projects need the GeckoView-specific omni.ja.
+ext.configureVariantWithGeckoBinaries = { variant ->
+ // :app needs the full Fennec omni.ja, whereas other projects need the
+ // GeckoView-specific omni.ja.
def omnijar_dir = "app".equals(project.name) ? "fennec" : "geckoview"
- into("${project.buildDir}/generated/omnijar")
- from("${topobjdir}/dist/${omnijar_dir}/omni.ja",
- "${topobjdir}/dist/${omnijar_dir}/assets/omni.ja") {
- // Throw an exception if we find multiple, potentially conflicting omni.ja files.
- duplicatesStrategy 'fail'
- }
-}
+ def distDir = "${topobjdir}/dist/${omnijar_dir}"
-task checkLibsExistInDistDir {
- doLast {
- if (syncLibsFromDistDir.source.empty) {
- throw new GradleException("Required JNI libraries not found in ${topobjdir}/dist/fennec/lib. Have you built and packaged?")
+ def syncOmnijarFromDistDir = task("syncOmnijarFromDistDirFor${variant.name.capitalize()}", type: Sync) {
+ doFirst {
+ if (source.empty) {
+ throw new GradleException("Required omnijar not found in ${source.asPath}. Have you built and packaged?")
+ }
}
- }
-}
-task syncLibsFromDistDir(type: Sync, dependsOn: checkLibsExistInDistDir) {
- into("${project.buildDir}/generated/jniLibs")
- from("${topobjdir}/dist/fennec/lib")
-}
-
-task checkAssetsExistInDistDir {
- doLast {
- if (syncAssetsFromDistDir.source.empty) {
- throw new GradleException("Required assets not found in ${topobjdir}/dist/fennec/assets. Have you built and packaged?")
+ into("${project.buildDir}/moz.build/src/${variant.name}/omnijar")
+ from("${distDir}/omni.ja",
+ "${distDir}/assets/omni.ja") {
+ // Throw an exception if we find multiple, potentially conflicting omni.ja files.
+ duplicatesStrategy 'fail'
}
}
-}
-
-task syncAssetsFromDistDir(type: Sync, dependsOn: checkAssetsExistInDistDir) {
- into("${project.buildDir}/generated/assets")
- from("${topobjdir}/dist/fennec/assets") {
- exclude 'omni.ja'
- }
-}
-ext.configureVariantWithGeckoBinaries = { variant ->
- // Like 'localPhoton' or 'localOldPhoton'; may be null.
- def productFlavor = ""
- def productFlavorNames = variant.productFlavors.collect { it.name.capitalize() }
- if (!productFlavorNames.isEmpty()) {
- productFlavor = productFlavorNames.join()
- // Groovy's `uncapitilize` is not yet available.
- def c = productFlavor.toCharArray()
- c[0] = Character.toLowerCase(c[0])
- productFlavor = new String(c)
+ def syncLibsFromDistDir = task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
+ doFirst {
+ if (source.empty) {
+ throw new GradleException("Required JNI libraries not found in ${source.asPath}. Have you built and packaged?")
+ }
+ }
+
+ into("${project.buildDir}/moz.build/src/${variant.name}/jniLibs")
+ from("${distDir}/lib")
}
- // Like 'debug' or 'release'.
- def buildType = variant.buildType.name
+ def syncAssetsFromDistDir = task("syncAssetsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
+ doFirst {
+ if (source.empty) {
+ throw new GradleException("Required assets not found in ${source.asPath}. Have you built and packaged?")
+ }
+ }
+
+ into("${project.buildDir}/moz.build/src/${variant.name}/assets")
+ from("${distDir}/assets") {
+ exclude 'omni.ja'
+ }
+ }
- syncOmnijarFromDistDir.dependsOn buildOmnijar
- def generateAssetsTask = tasks.findByName("generate${productFlavor.capitalize()}${buildType.capitalize()}Assets")
- generateAssetsTask.dependsOn syncOmnijarFromDistDir
- generateAssetsTask.dependsOn syncLibsFromDistDir
- generateAssetsTask.dependsOn syncAssetsFromDistDir
+ // Local (read, not 'official') builds want to reflect developer changes to
+ // the Omnijar sources. To do this, the Gradle build calls out to the
+ // moz.build system, which can be re-entrant. Official builds are driven by
+ // the moz.build system and should never be re-entrant in this way.
+ if (!((variant.productFlavors*.name).contains('official'))) {
+ syncOmnijarFromDistDir.dependsOn buildOmnijars
+ }
- def sourceSet = productFlavor ? "${productFlavor}${buildType.capitalize()}" : buildType
- android.sourceSets."${sourceSet}".assets.srcDir syncOmnijarFromDistDir.destinationDir
- android.sourceSets."${sourceSet}".assets.srcDir syncAssetsFromDistDir.destinationDir
- android.sourceSets."${sourceSet}".jniLibs.srcDir syncLibsFromDistDir.destinationDir
+ def assetGenTask = tasks.findByName("generate${variant.name.capitalize()}Assets")
+ if ((variant.productFlavors*.name).contains('withGeckoBinaries')) {
+ assetGenTask.dependsOn syncOmnijarFromDistDir
+ assetGenTask.dependsOn syncLibsFromDistDir
+ assetGenTask.dependsOn syncAssetsFromDistDir
+
+ android.sourceSets."${variant.name}".assets.srcDir syncOmnijarFromDistDir.destinationDir
+ android.sourceSets."${variant.name}".assets.srcDir syncAssetsFromDistDir.destinationDir
+ android.sourceSets."${variant.name}".jniLibs.srcDir syncLibsFromDistDir.destinationDir
+ }
}
ext.configureLibraryVariantWithJNIWrappers = { variant, module ->
// Library variants have two essentially independent transform* tasks:
//
// - ...WithSyncLibJars... is used by assemble* and bundle*
// - ...WithPrepareIntermediateJars... is used by consuming applications.
//
--- a/taskcluster/ci/build/android.yml
+++ b/taskcluster/ci/build/android.yml
@@ -16,17 +16,17 @@ android-api-16/debug:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -68,17 +68,17 @@ android-x86/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -125,17 +125,17 @@ android-x86-nightly/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -173,17 +173,17 @@ android-api-16/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -274,17 +274,17 @@ android-api-16-nightly/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -327,17 +327,17 @@ android-x86-old-id/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -383,17 +383,17 @@ android-x86-old-id-nightly/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -432,17 +432,17 @@ android-api-16-old-id/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -483,17 +483,17 @@ android-api-16-old-id-nightly/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -532,17 +532,17 @@ android-api-16-gradle/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -578,17 +578,17 @@ android-aarch64/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config:
@@ -630,17 +630,17 @@ android-aarch64-nightly/opt:
artifacts:
- name: public/android/R
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/app/R
type: directory
- name: public/android/maven
path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview/maven/
type: directory
- name: public/build/geckoview_example.apk
- path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/geckoview_example-withGeckoBinaries.apk
+ path: /builds/worker/workspace/build/src/obj-firefox/gradle/build/mobile/android/geckoview_example/outputs/apk/officialWithGeckoBinariesNoMinApi/debug/geckoview_example-official-withGeckoBinaries-noMinApi-debug.apk
type: file
- name: public/build
path: /builds/worker/artifacts/
type: directory
run:
using: mozharness
actions: [get-secrets build multi-l10n update]
config: