2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-02 03:40:16 +00:00
iceraven-browser/app/build.gradle
Gabriel Luong 64a4a7f422
Provide add-on support (#8064)
Closes #5630, #6069, #6092, #6091, #6124, and #6147.

Co-authored-by: Simon Chae <chaesmn@gmail.com>
Co-authored-by: Arturo Mejia <arturomejiamarmol@gmail.com>
Co-authored-by: Christian Sadilek <christian.sadilek@gmail.com>
Co-authored-by: Gabriel Luong <gabriel.luong@gmail.com>
2020-02-04 01:41:51 -05:00

697 lines
28 KiB
Groovy

plugins {
id "com.jetbrains.python.envs" version "0.0.26"
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'jacoco'
apply from: "$project.rootDir/automation/gradle/versionCode.gradle"
apply plugin: 'androidx.navigation.safeargs.kotlin'
apply plugin: 'com.google.android.gms.oss-licenses-plugin'
import com.android.build.OutputFile
import org.gradle.internal.logging.text.StyledTextOutput.Style
import org.gradle.internal.logging.text.StyledTextOutputFactory
import static org.gradle.api.tasks.testing.TestResult.ResultType
android {
compileSdkVersion 28
defaultConfig {
applicationId "org.mozilla"
minSdkVersion Config.minSdkVersion
targetSdkVersion Config.targetSdkVersion
versionCode 1
versionName Config.generateDebugVersionName()
vectorDrawables.useSupportLibrary = true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
testInstrumentationRunnerArguments clearPackageData: 'true'
manifestPlaceholders.isRaptorEnabled = "false"
resValue "bool", "IS_DEBUG", "false"
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "false"
}
def releaseTemplate = {
shrinkResources true
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
matchingFallbacks = ['release'] // Use on the "release" build type in dependencies (AARs)
}
buildTypes {
debug {
shrinkResources false
minifyEnabled false
applicationIdSuffix ".fenix.debug"
manifestPlaceholders.isRaptorEnabled = "true"
resValue "bool", "IS_DEBUG", "true"
pseudoLocalesEnabled true
}
forPerformanceTest releaseTemplate >> { // the ">>" concatenates the raptor-specific options with the template
manifestPlaceholders.isRaptorEnabled = "true"
applicationIdSuffix ".fenix.performancetest"
debuggable true
}
fenixNightly releaseTemplate >> {
applicationIdSuffix ".fenix.nightly"
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
}
fenixBeta releaseTemplate >> {
applicationIdSuffix ".fenix.beta"
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
}
fenixProduction releaseTemplate >> {
applicationIdSuffix ".fenix"
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
}
fennecProduction releaseTemplate >> {
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
applicationIdSuffix ".firefox"
manifestPlaceholders = [
// This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
// its sharedUserId for all eternity. See:
// https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false&regexp=false&path=
// Shipping an app update without sharedUserId can have
// fatal consequences. For example see:
// - https://issuetracker.google.com/issues/36924841
// - https://issuetracker.google.com/issues/36905922
"sharedUserId": "org.mozilla.firefox.sharedID"
]
}
fennecBeta releaseTemplate >> {
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
applicationIdSuffix ".firefox_beta"
manifestPlaceholders = [
// This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
// its sharedUserId for all eternity. See:
// https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false&regexp=false&path=
// Shipping an app update without sharedUserId can have
// fatal consequences. For example see:
// - https://issuetracker.google.com/issues/36924841
// - https://issuetracker.google.com/issues/36905922
"sharedUserId": "org.mozilla.firefox.sharedID"
]
}
fennecNightly releaseTemplate >> {
buildConfigField "boolean", "USE_RELEASE_VERSIONING", "true"
applicationIdSuffix ".fennec_aurora"
manifestPlaceholders = [
// This release type is meant to replace Firefox (Release channel) and therefore needs to inherit
// its sharedUserId for all eternity. See:
// https://searchfox.org/mozilla-central/search?q=moz_android_shared_id&case=false&regexp=false&path=
// Shipping an app update without sharedUserId can have
// fatal consequences. For example see:
// - https://issuetracker.google.com/issues/36924841
// - https://issuetracker.google.com/issues/36905922
"sharedUserId": "org.mozilla.fennec.sharedID"
]
}
}
variantFilter { // There's a "release" build type that exists by default that we don't use (it's replaced by "nightly" and "beta")
if (buildType.name == 'release') {
setIgnore true
}
// Current build variant setup:
//
// | geckoNightly | geckoBeta |
// |--------------------|---------------|-----------|
// | debug | ✅ | ✅ | Both variants for testing and development.
// | forPerformanceTest | ✅ | ✅ | Both variants unless the perf team only cares about Nightly (TBD).
// | fenixNightly | ✅ | ✅ | Built with both, but only the "geckoNightly" one is published to Google Play
// | fenixBeta | ❌ | ✅ | Fenix Beta ships with GV Beta
// | fenixProduction | ❌ | ✅ | Fenix Production ships with GV Beta
// | fennecProduction | ❌ | ✅ | Fenix build to replace production Firefox builds
// | fennecBeta | ❌ | ✅ | Fenix build to replace beta Firefox builds
// | fennecNightly | ✅ | ❌ | Fenix build to replace Nightly Firefox builds
def flavors = flavors*.name.toString().toLowerCase()
if (buildType.name == 'fenixBeta' && flavors.contains("geckonightly")) {
setIgnore true
}
if (buildType.name == 'fenixProduction' && flavors.contains("geckonightly")) {
setIgnore true
}
if ((buildType.name == 'fennecProduction' || buildType.name == 'fennecBeta') && flavors.contains("geckonightly")) {
setIgnore true
}
if (buildType.name == 'fennecNightly' && flavors.contains("geckobeta")) {
setIgnore true
}
}
testOptions {
execution 'ANDROIDX_TEST_ORCHESTRATOR'
unitTests.includeAndroidResources = true
}
flavorDimensions "engine"
sourceSets {
androidTest {
resources.srcDirs += ['src/androidTest/resources']
}
fennecNightly {
java.srcDirs = ['src/migration/java']
manifest.srcFile "src/migration/AndroidManifest.xml"
}
fennecBeta {
java.srcDirs = ['src/migration/java']
manifest.srcFile "src/migration/AndroidManifest.xml"
}
fennecProduction {
java.srcDirs = ['src/migration/java']
manifest.srcFile "src/migration/AndroidManifest.xml"
}
}
productFlavors {
geckoNightly {
dimension "engine"
}
geckoBeta {
dimension "engine"
}
}
splits {
abi {
enable true
reset()
include "x86", "armeabi-v7a", "arm64-v8a", "x86_64"
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
lintConfig file("lint.xml")
}
packagingOptions {
exclude 'META-INF/atomicfu.kotlin_module'
}
testOptions {
unitTests.returnDefaultValues = true
}
}
def baseVersionCode = generatedVersionCode
android.applicationVariants.all { variant ->
// -------------------------------------------------------------------------------------------------
// Set up kotlin-allopen plugin for writing tests
// -------------------------------------------------------------------------------------------------
boolean hasTest = gradle.startParameter.taskNames.find { it.contains("test") || it.contains("Test") } != null
if (hasTest) {
apply plugin: 'kotlin-allopen'
allOpen {
annotation("org.mozilla.fenix.test.OpenClass")
}
}
// -------------------------------------------------------------------------------------------------
// Generate version codes for builds
// -------------------------------------------------------------------------------------------------
def isDebug = variant.buildType.resValues['IS_DEBUG']?.value ?: false
def useReleaseVersioning = variant.buildType.buildConfigFields['USE_RELEASE_VERSIONING']?.value ?: false
def versionName = Config.releaseVersionName(project)
println("----------------------------------------------")
println("Variant name: " + variant.name)
println("Application ID: " + [variant.mergedFlavor.applicationId, variant.buildType.applicationIdSuffix].findAll().join())
println("Build type: " + variant.buildType.name)
println("Flavor: " + variant.flavorName)
println("Telemetry enabled: " + !isDebug)
if (useReleaseVersioning) {
// The Google Play Store does not allow multiple APKs for the same app that all have the
// same version code. Therefore we need to have different version codes for our ARM and x86
// builds.
// Our generated version code now has a length of 9 (See automation/gradle/versionCode.gradle).
// Our x86 builds need a higher version code to avoid installing ARM builds on an x86 device
// with ARM compatibility mode.
variant.outputs.each { output ->
def abi = output.getFilter(OutputFile.ABI)
def versionCodeOverride
if (variant.name.contains("Fennec")) {
versionCodeOverride = Config.generateFennecVersionCode(abi)
} else if (abi == "x86_64") {
versionCodeOverride = baseVersionCode + 3
} else if (abi == "x86") {
versionCodeOverride = baseVersionCode + 2
} else if (abi == "arm64-v8a") {
versionCodeOverride = baseVersionCode + 1
} else if (abi == "armeabi-v7a") {
versionCodeOverride = baseVersionCode
} else {
throw RuntimeException("Unknown ABI: $abi")
}
println("versionCode for $abi = $versionCodeOverride")
output.versionNameOverride = versionName
output.versionCodeOverride = versionCodeOverride
}
}
// -------------------------------------------------------------------------------------------------
// BuildConfig: Set variables for Sentry, Crash Reporting, and Telemetry
// -------------------------------------------------------------------------------------------------
buildConfigField 'String', 'SENTRY_TOKEN', 'null'
if (!isDebug) {
buildConfigField 'boolean', 'CRASH_REPORTING', 'true'
// Reading sentry token from local file (if it exists). In a release task on taskcluster it will be available.
try {
def token = new File("${rootDir}/.sentry_token").text.trim()
buildConfigField 'String', 'SENTRY_TOKEN', '"' + token + '"'
} catch (FileNotFoundException ignored) {}
} else {
buildConfigField 'boolean', 'CRASH_REPORTING', 'false'
}
if (!isDebug) {
buildConfigField 'boolean', 'TELEMETRY', 'true'
} else {
buildConfigField 'boolean', 'TELEMETRY', 'false'
}
def buildDate = Config.generateBuildDate()
buildConfigField 'String', 'BUILD_DATE', '"' + buildDate + '"'
def variantName = variant.getName()
// -------------------------------------------------------------------------------------------------
// Adjust: Read token from local file if it exists (Only release builds)
// -------------------------------------------------------------------------------------------------
print("Adjust token: ")
if (!isDebug) {
try {
def token = new File("${rootDir}/.adjust_token").text.trim()
buildConfigField 'String', 'ADJUST_TOKEN', '"' + token + '"'
println "(Added from .adjust_token file)"
} catch (FileNotFoundException ignored) {
buildConfigField 'String', 'ADJUST_TOKEN', 'null'
println("X_X")
}
} else {
buildConfigField 'String', 'ADJUST_TOKEN', 'null'
println("--")
}
// -------------------------------------------------------------------------------------------------
// Leanplum: Read token from local file if it exists
// -------------------------------------------------------------------------------------------------
print("Leanplum token: ")
try {
def parts = new File("${rootDir}/.leanplum_token").text.trim().split(":")
def id = parts[0]
def key = parts[1]
buildConfigField 'String', 'LEANPLUM_ID', '"' + id + '"'
buildConfigField 'String', 'LEANPLUM_TOKEN', '"' + key + '"'
println "(Added from .leanplum_token file)"
} catch (FileNotFoundException ignored) {
buildConfigField 'String', 'LEANPLUM_ID', 'null'
buildConfigField 'String', 'LEANPLUM_TOKEN', 'null'
println("X_X")
}
// -------------------------------------------------------------------------------------------------
// Digital Asset Links: Read token from local file if it exists
// -------------------------------------------------------------------------------------------------
print("Digital Asset Links token: ")
try {
def token = new File("${rootDir}/.digital_asset_links_token").text.trim()
buildConfigField 'String', 'DIGITAL_ASSET_LINKS_TOKEN', '"' + token + '"'
println "(Added from .digital_asset_links_token file)"
} catch (FileNotFoundException ignored) {
buildConfigField 'String', 'DIGITAL_ASSET_LINKS_TOKEN', 'null'
println("X_X")
}
}
androidExtensions {
experimental = true
}
dependencies {
geckoNightlyImplementation Deps.mozilla_browser_engine_gecko_nightly
geckoBetaImplementation Deps.mozilla_browser_engine_gecko_beta
implementation Deps.kotlin_stdlib
implementation Deps.kotlin_coroutines
implementation Deps.kotlin_coroutines_android
testImplementation Deps.kotlin_coroutines_test
implementation Deps.androidx_appcompat
implementation Deps.androidx_constraintlayout
implementation Deps.androidx_coordinatorlayout
implementation Deps.sentry
implementation Deps.osslicenses_library
implementation Deps.leanplum_core
implementation Deps.leanplum_fcm
implementation Deps.mozilla_concept_engine
implementation Deps.mozilla_concept_push
implementation Deps.mozilla_concept_storage
implementation Deps.mozilla_concept_sync
implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_browser_awesomebar
implementation Deps.mozilla_feature_downloads
implementation Deps.mozilla_browser_domains
implementation Deps.mozilla_browser_icons
implementation Deps.mozilla_browser_menu
implementation Deps.mozilla_browser_search
implementation Deps.mozilla_browser_session
implementation Deps.mozilla_browser_state
implementation Deps.mozilla_browser_storage_sync
implementation Deps.mozilla_browser_toolbar
implementation Deps.mozilla_support_extensions
implementation Deps.mozilla_feature_addons
implementation Deps.mozilla_feature_accounts
implementation Deps.mozilla_feature_app_links
implementation Deps.mozilla_feature_awesomebar
implementation Deps.mozilla_feature_contextmenu
implementation Deps.mozilla_feature_customtabs
implementation Deps.mozilla_feature_downloads
implementation Deps.mozilla_feature_intent
implementation Deps.mozilla_feature_media
implementation Deps.mozilla_feature_prompts
implementation Deps.mozilla_feature_push
implementation Deps.mozilla_feature_pwa
implementation Deps.mozilla_feature_qr
implementation Deps.mozilla_feature_search
implementation Deps.mozilla_feature_session
implementation Deps.mozilla_feature_toolbar
implementation Deps.mozilla_feature_tabs
implementation Deps.mozilla_feature_findinpage
implementation Deps.mozilla_feature_site_permissions
implementation Deps.mozilla_feature_readerview
implementation Deps.mozilla_feature_tab_collections
implementation Deps.mozilla_feature_top_sites
implementation Deps.mozilla_feature_accounts_push
implementation Deps.mozilla_feature_webcompat
implementation Deps.mozilla_feature_webnotifications
implementation Deps.mozilla_service_sync_logins
implementation Deps.mozilla_service_firefox_accounts
implementation Deps.mozilla_service_glean
implementation Deps.mozilla_service_experiments
implementation Deps.mozilla_support_base
implementation Deps.mozilla_support_ktx
implementation Deps.mozilla_support_rustlog
implementation Deps.mozilla_support_utils
implementation Deps.mozilla_support_locale
implementation Deps.mozilla_support_migration
implementation Deps.mozilla_ui_colors
implementation Deps.mozilla_ui_icons
implementation Deps.mozilla_ui_publicsuffixlist
implementation Deps.mozilla_lib_crash
implementation Deps.mozilla_lib_push_firebase
implementation Deps.mozilla_lib_dataprotect
debugImplementation Deps.leakcanary
implementation Deps.androidx_legacy
implementation Deps.androidx_biometric
implementation Deps.androidx_paging
implementation Deps.androidx_preference
implementation Deps.androidx_fragment
implementation Deps.androidx_navigation_fragment
implementation Deps.androidx_navigation_ui
implementation Deps.androidx_recyclerview
implementation Deps.androidx_lifecycle_livedata
implementation Deps.androidx_lifecycle_runtime
implementation Deps.androidx_lifecycle_viewmodel
implementation Deps.androidx_core
implementation Deps.androidx_core_ktx
implementation Deps.androidx_transition
implementation Deps.androidx_work_ktx
implementation Deps.google_material
implementation Deps.lottie
implementation Deps.adjust
implementation Deps.installreferrer // Required by Adjust
implementation Deps.google_ads_id // Required for the Google Advertising ID
androidTestImplementation Deps.uiautomator
// Removed pending AndroidX fixes
androidTestImplementation "tools.fastlane:screengrab:2.0.0"
// androidTestImplementation "br.com.concretesolutions:kappuccino:1.2.1"
androidTestImplementation Deps.espresso_core, {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestImplementation(Deps.espresso_contrib) {
exclude module: 'appcompat-v7'
exclude module: 'support-v4'
exclude module: 'support-annotations'
exclude module: 'recyclerview-v7'
exclude module: 'design'
exclude module: 'espresso-core'
}
androidTestImplementation Deps.androidx_test_core
androidTestImplementation Deps.espresso_idling_resources
androidTestImplementation Deps.espresso_intents
androidTestImplementation Deps.tools_test_runner
androidTestImplementation Deps.tools_test_rules
androidTestUtil Deps.orchestrator
androidTestImplementation Deps.espresso_core, {
exclude group: 'com.android.support', module: 'support-annotations'
}
androidTestImplementation Deps.mockwebserver
testImplementation Deps.mozilla_support_test
testImplementation Deps.androidx_junit
testImplementation Deps.androidx_work_testing
testImplementation (Deps.robolectric) {
exclude group: 'org.apache.maven'
}
testImplementation 'org.apache.maven:maven-ant-tasks:2.1.3'
// For production builds, the native code for all `org.mozilla.appservices`
// dependencies gets compiled together into a single "megazord" build, and
// different megazords are published for different subsets of features. Ref
// https://mozilla.github.io/application-services/docs/applications/consuming-megazord-libraries.html
// We want to use the one that's specifically designed for Fenix.
implementation Deps.fenix_megazord
testImplementation Deps.fenix_megazord_forUnitTests
implementation Deps.mozilla_support_rusthttp
modules {
module('org.mozilla.appservices:full-megazord') {
replacedBy('org.mozilla.appservices:fenix-megazord', 'prefer the fenix megazord, to reduce final application size')
}
module('org.mozilla.appservices:fenix-megazord') {
replacedBy('org.mozilla.appservices:fenix-megazord-forUnitTests', 'prefer the forUnitTests variant if present')
}
}
testImplementation Deps.mockito_core
androidTestImplementation Deps.mockito_android
testImplementation Deps.mockk
testImplementation Deps.assertk
// For the initial release of Glean 19, we require consumer applications to
// depend on a separate library for unit tests. This will be removed in future releases.
testImplementation Deps.mozilla_service_glean_forUnitTests
}
if (project.hasProperty("raptor")) {
android.defaultConfig.manifestPlaceholders.isRaptorEnabled = "true"
}
if (project.hasProperty("coverage")) {
tasks.withType(Test) {
jacoco.includeNoLocationClasses = true
}
android.applicationVariants.all { variant ->
task "jacoco${variant.name.capitalize()}TestReport"(type: JacocoReport, dependsOn: "test${variant.name.capitalize()}UnitTest") {
reports {
xml.enabled = true
html.enabled = true
}
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*',
'**/*Test*.*', 'android/**/*.*', '**/*$[0-9].*']
def kotlinDebugTree = fileTree(dir: "$project.buildDir/tmp/kotlin-classes/${variant.name}", excludes: fileFilter)
def javaDebugTree = fileTree(dir: "$project.buildDir/intermediates/classes/${variant.flavorName}/${variant.buildType.name}",
excludes: fileFilter)
def mainSrc = "$project.projectDir/src/main/java"
sourceDirectories = files([mainSrc])
classDirectories = files([kotlinDebugTree, javaDebugTree])
executionData = fileTree(dir: project.buildDir, includes: [
"jacoco/test${variant.name.capitalize()}UnitTest.exec", 'outputs/code-coverage/connected/*coverage.ec'
])
}
}
android {
buildTypes {
debug {
testCoverageEnabled true
}
}
}
}
// -------------------------------------------------------------------------------------------------
// Task for printing APK information for the requested variant
// Usage: "./gradlew printVariants
// -------------------------------------------------------------------------------------------------
task printVariants {
doLast {
def variants = android.applicationVariants.collect {[
apks: it.variantData.outputScope.apkDatas.collect {[
abi: it.filters.find { it.filterType == 'ABI' }.identifier,
fileName: it.outputFileName,
]},
build_type: it.buildType.name,
engine: it.productFlavors.find { it.dimension == 'engine' }.name,
name: it.name,
]}
// AndroidTest is a special case not included above
variants.add([
apks: [[
abi: 'noarch',
fileName: 'app-geckoNightly-debug-androidTest.apk',
]],
build_type: 'androidTest',
engine: 'geckoNightly',
name: 'androidTest',
])
println 'variants: ' + groovy.json.JsonOutput.toJson(variants)
}
}
task buildTranslationArray {
def foundLocales = new StringBuilder()
foundLocales.append("new String[]{")
fileTree("src/main/res").visit { FileVisitDetails details ->
if(details.file.path.endsWith("/strings.xml")){
def languageCode = details.file.parent.tokenize('/').last().replaceAll('values-','').replaceAll('-r','-')
languageCode = (languageCode == "values") ? "en-US" : languageCode
foundLocales.append("\"").append(languageCode).append("\"").append(",")
}
}
foundLocales.append("}")
def foundLocalesString = foundLocales.toString().replaceAll(',}','}')
android.defaultConfig.buildConfigField "String[]", "SUPPORTED_LOCALE_ARRAY", foundLocalesString
}
def glean_android_components_tag = (
Versions.mozilla_android_components.endsWith('-SNAPSHOT') ?
'master' :
'v' + Versions.mozilla_android_components
)
// Generate markdown docs for the collected metrics.
ext.gleanGenerateMarkdownDocs = true
ext.gleanDocsDirectory = "$rootDir/docs"
apply from: 'https://github.com/mozilla-mobile/android-components/raw/' + glean_android_components_tag + '/components/service/glean/scripts/sdk_generator.gradle'
// For production builds, the native code for all `org.mozilla.appservices` dependencies gets compiled together
// into a single "megazord" build, and different megazords are published for different subsets of features.
// Ref https://mozilla.github.io/application-services/docs/applications/consuming-megazord-libraries.html
// Substitute all appservices dependencies with an appropriate megazord.
afterEvaluate {
// Format test output. Ported from AC #2401
tasks.matching {it instanceof Test}.all {
systemProperty "robolectric.logging", "stdout"
systemProperty "logging.test-mode", "true"
testLogging.events = []
def out = services.get(StyledTextOutputFactory).create("tests")
beforeSuite { descriptor ->
if (descriptor.getClassName() != null) {
out.style(Style.Header).println("\nSUITE: " + descriptor.getClassName())
}
}
beforeTest { descriptor ->
out.style(Style.Description).println(" TEST: " + descriptor.getName())
}
onOutput { descriptor, event ->
logger.lifecycle(" " + event.message.trim())
}
afterTest { descriptor, result ->
switch (result.getResultType()) {
case ResultType.SUCCESS:
out.style(Style.Success).println(" SUCCESS")
break
case ResultType.FAILURE:
out.style(Style.Failure).println(" FAILURE")
logger.lifecycle("", result.getException())
break
case ResultType.SKIPPED:
out.style(Style.Info).println(" SKIPPED")
break
}
logger.lifecycle("")
}
}
}
if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopsrcdir')) {
if (gradle.hasProperty('localProperties.dependencySubstitutions.geckoviewTopobjdir')) {
ext.topobjdir = gradle."localProperties.dependencySubstitutions.geckoviewTopobjdir"
}
ext.topsrcdir = gradle."localProperties.dependencySubstitutions.geckoviewTopsrcdir"
apply from: "${topsrcdir}/substitute-local-geckoview.gradle"
}
if (gradle.hasProperty('localProperties.autoPublish.android-components.dir')) {
ext.acSrcDir = gradle."localProperties.autoPublish.android-components.dir"
apply from: "../${acSrcDir}/substitute-local-ac.gradle"
}