diff --git a/app/build.gradle b/app/build.gradle deleted file mode 100644 index 673dce791..000000000 --- a/app/build.gradle +++ /dev/null @@ -1,321 +0,0 @@ -import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile - -import java.text.SimpleDateFormat - -apply plugin: 'com.android.application' -apply plugin: 'com.mikepenz.aboutlibraries.plugin' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: 'kotlin-parcelize' -apply plugin: 'kotlinx-serialization' -apply plugin: 'com.github.zellius.shortcut-helper' - -shortcutHelper.filePath = './shortcuts.xml' - -ext { - // Git is needed in your system PATH for these commands to work. - // If it's not installed, you can return a random value as a workaround - getCommitCount = { - return 'git rev-list --count HEAD'.execute().text.trim() - // return "1" - } - - getGitSha = { - return 'git rev-parse --short HEAD'.execute().text.trim() - // return "1" - } - - getBuildTime = { - def df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'") - df.setTimeZone(TimeZone.getTimeZone("UTC")) - return df.format(new Date()) - } -} - -android { - compileSdkVersion AndroidConfig.compileSdk - buildToolsVersion AndroidConfig.buildTools - ndkVersion AndroidConfig.ndk - - defaultConfig { - applicationId "eu.kanade.tachiyomi" - minSdkVersion AndroidConfig.minSdk - targetSdkVersion AndroidConfig.targetSdk - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" - versionCode 54 - versionName "0.10.7" - - buildConfigField "String", "COMMIT_COUNT", "\"${getCommitCount()}\"" - buildConfigField "String", "COMMIT_SHA", "\"${getGitSha()}\"" - buildConfigField "String", "BUILD_TIME", "\"${getBuildTime()}\"" - buildConfigField "boolean", "INCLUDE_UPDATER", "false" - - multiDexEnabled true - - ndk { - abiFilters "armeabi-v7a", "arm64-v8a", "x86" - } - } - - buildFeatures { - viewBinding = true - } - - buildTypes { - debug { - versionNameSuffix "-${getCommitCount()}" - applicationIdSuffix ".debug" - } - release { -// postprocessing { -// obfuscate false -// optimizeCode true -// removeUnusedCode false -// removeUnusedResources true -// proguardFiles 'proguard-rules.pro' -// } - } - } - - flavorDimensions "default" - - productFlavors { - standard { - buildConfigField "boolean", "INCLUDE_UPDATER", "true" - dimension "default" - } - fdroid { - dimension "default" - } - dev { - resConfigs "en", "xxhdpi" - dimension "default" - } - } - - packagingOptions { - exclude 'META-INF/DEPENDENCIES' - exclude 'LICENSE.txt' - exclude 'META-INF/LICENSE' - exclude 'META-INF/LICENSE.txt' - exclude 'META-INF/NOTICE' - } - - dependenciesInfo { - includeInApk = false - } - - lintOptions { - disable 'MissingTranslation' - disable 'ExtraTranslation' - - abortOnError false - checkReleaseBuilds false - } - - compileOptions { - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = JavaVersion.VERSION_1_8.toString() - } -} - -dependencies { - - // Source models and interfaces from Tachiyomi 1.x - implementation 'tachiyomi.sourceapi:source-api:1.1' - - // AndroidX libraries - implementation 'androidx.annotation:annotation:1.2.0-alpha01' - implementation 'androidx.appcompat:appcompat:1.3.0-alpha02' - implementation 'androidx.biometric:biometric-ktx:1.2.0-alpha01' - implementation 'androidx.browser:browser:1.3.0' - implementation 'androidx.cardview:cardview:1.0.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.0-alpha2' - implementation 'androidx.coordinatorlayout:coordinatorlayout:1.1.0' - implementation 'androidx.core:core-ktx:1.5.0-alpha05' - implementation 'androidx.multidex:multidex:2.0.1' - implementation 'androidx.preference:preference-ktx:1.1.1' - implementation 'androidx.recyclerview:recyclerview:1.2.0-beta01' - implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01' - - final lifecycle_version = '2.3.0-rc01' - implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-process:$lifecycle_version" - implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" - - // Job scheduling - implementation "androidx.work:work-runtime-ktx:2.5.0-beta02" - - // UI library - implementation 'com.google.android.material:material:1.3.0-beta01' - - standardImplementation 'com.google.firebase:firebase-core:18.0.0' - - // ReactiveX - implementation 'io.reactivex:rxandroid:1.2.1' - implementation 'io.reactivex:rxjava:1.3.8' - implementation 'com.jakewharton.rxrelay:rxrelay:1.2.0' - implementation 'com.github.pwittchen:reactivenetwork:0.13.0' - - // Network client - final okhttp_version = '4.10.0-RC1' - implementation "com.squareup.okhttp3:okhttp:$okhttp_version" - implementation "com.squareup.okhttp3:logging-interceptor:$okhttp_version" - implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttp_version" - implementation 'com.squareup.okio:okio:2.9.0' - - // TLS 1.3 support for Android < 10 - implementation 'org.conscrypt:conscrypt-android:2.5.1' - - // REST - final retrofit_version = '2.9.0' - implementation "com.squareup.retrofit2:retrofit:$retrofit_version" - implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0" - - // JSON - final kotlin_serialization_version = '1.0.1' - implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlin_serialization_version" - implementation "org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlin_serialization_version" - implementation 'com.google.code.gson:gson:2.8.6' - implementation 'com.github.salomonbrys.kotson:kotson:2.5.0' - - // JavaScript engine - implementation 'com.squareup.duktape:duktape-android:1.3.0' - - // Disk - implementation 'com.jakewharton:disklrucache:2.0.2' - implementation 'com.github.inorichi:unifile:e9ee588' - implementation 'com.github.junrar:junrar:7.4.0' - - // HTML parser - implementation 'org.jsoup:jsoup:1.13.1' - - // Database - implementation 'androidx.sqlite:sqlite-ktx:2.1.0' - implementation 'com.github.inorichi.storio:storio-common:8be19de@aar' - implementation 'com.github.inorichi.storio:storio-sqlite:8be19de@aar' - implementation 'io.requery:sqlite-android:3.33.0' - - // Preferences - implementation 'com.github.tfcporciuncula.flow-preferences:flow-preferences:1.3.3' - - // Model View Presenter - final nucleus_version = '3.0.0' - implementation "info.android15.nucleus:nucleus:$nucleus_version" - implementation "info.android15.nucleus:nucleus-support-v7:$nucleus_version" - - // Dependency injection - implementation "com.github.inorichi.injekt:injekt-core:65b0440" - - // Image library - final glide_version = '4.11.0' - implementation "com.github.bumptech.glide:glide:$glide_version" - implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version" - kapt "com.github.bumptech.glide:compiler:$glide_version" - - implementation 'com.github.tachiyomiorg:subsampling-scale-image-view:6caf219' - - // Logging - implementation 'com.jakewharton.timber:timber:4.7.1' - - // Crash reports - implementation 'ch.acra:acra-http:5.7.0' - - // Sort - implementation 'com.github.gpanther:java-nat-sort:natural-comparator-1.1' - - // UI - implementation 'com.dmitrymalkovich.android:material-design-dimens:1.4' - implementation 'com.github.dmytrodanylyk.android-process-button:library:1.0.4' - implementation 'eu.davidea:flexible-adapter:5.1.0' - implementation 'eu.davidea:flexible-adapter-ui:1.0.0' - implementation 'com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0' - implementation 'com.github.chrisbanes:PhotoView:2.3.0' - implementation 'com.github.carlosesco:DirectionalViewPager:a844dbca0a' - - // 3.2.0+ introduces weird UI blinking or cut off issues on some devices - final material_dialogs_version = '3.1.1' - implementation "com.afollestad.material-dialogs:core:$material_dialogs_version" - implementation "com.afollestad.material-dialogs:input:$material_dialogs_version" - implementation "com.afollestad.material-dialogs:datetime:$material_dialogs_version" - - // Conductor - implementation 'com.bluelinelabs:conductor:2.1.5' - implementation("com.bluelinelabs:conductor-support:2.1.5") { - exclude group: "com.android.support" - } - implementation 'com.github.tachiyomiorg:conductor-support-preference:1.1.1' - - // FlowBinding - final flowbinding_version = '0.12.0' - implementation "io.github.reactivecircus.flowbinding:flowbinding-android:$flowbinding_version" - implementation "io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbinding_version" - implementation "io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbinding_version" - implementation "io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:$flowbinding_version" - implementation "io.github.reactivecircus.flowbinding:flowbinding-viewpager:$flowbinding_version" - - // Licenses - implementation "com.mikepenz:aboutlibraries:$BuildPluginsVersion.ABOUTLIB_PLUGIN" - - // Tests - testImplementation 'junit:junit:4.13' - testImplementation 'org.assertj:assertj-core:3.16.1' - testImplementation 'org.mockito:mockito-core:1.10.19' - - final robolectric_version = '3.1.4' - testImplementation "org.robolectric:robolectric:$robolectric_version" - testImplementation "org.robolectric:shadows-multidex:$robolectric_version" - testImplementation "org.robolectric:shadows-play-services:$robolectric_version" - - implementation "org.jetbrains.kotlin:kotlin-reflect:$BuildPluginsVersion.KOTLIN" - - final coroutines_version = '1.4.2' - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version" - implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version" - - // For detecting memory leaks; see https://square.github.io/leakcanary/ -// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.4' -} - -buildscript { - repositories { - mavenCentral() - } - dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$BuildPluginsVersion.KOTLIN" - } -} - -repositories { - mavenCentral() - jcenter() -} - -// See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api-markers -tasks.withType(AbstractKotlinCompile).all { - kotlinOptions.freeCompilerArgs += [ - "-Xopt-in=kotlin.Experimental", - "-Xopt-in=kotlin.RequiresOptIn", - "-Xuse-experimental=kotlin.ExperimentalStdlibApi", - "-Xuse-experimental=kotlinx.coroutines.FlowPreview", - "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi", - "-Xuse-experimental=kotlinx.serialization.ExperimentalSerializationApi", - ] -} - -// Duplicating Hebrew string assets due to some locale code issues on different devices -task copyHebrewStrings(type: Copy) { - from './src/main/res/values-he' - into './src/main/res/values-iw' - include '**/*' -} - -preBuild.dependsOn(formatKotlin, copyHebrewStrings) - -if (getGradle().getStartParameter().getTaskRequests().toString().contains("Standard")) { - apply plugin: 'com.google.gms.google-services' -} diff --git a/app/build.gradle.kts b/app/build.gradle.kts new file mode 100644 index 000000000..6534e0125 --- /dev/null +++ b/app/build.gradle.kts @@ -0,0 +1,338 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import java.io.ByteArrayOutputStream +import java.text.SimpleDateFormat +import java.util.Date +import java.util.TimeZone + +plugins { + id("com.android.application") + id("com.mikepenz.aboutlibraries.plugin") + kotlin("android") + kotlin("kapt") + kotlin("plugin.parcelize") + kotlin("plugin.serialization") + id("com.github.zellius.shortcut-helper") +} + +shortcutHelper.setFilePath("./shortcuts.xml") + + +fun runCommand(command: String): String { + val byteOut = ByteArrayOutputStream() + project.exec { + commandLine = command.split(" ") + standardOutput = byteOut + } + return String(byteOut.toByteArray()).trim() +} + +// Git is needed in your system PATH for these commands to work. +// If it's not installed, you can return a random value as a workaround +fun getCommitCount(): String { + return runCommand("git rev-list --count HEAD") + // return "1" +} + +fun getGitSha(): String { + return runCommand("git rev-parse --short HEAD") + // return "1" +} + +fun getBuildTime(): String { + val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'") + df.timeZone = TimeZone.getTimeZone("UTC") + return df.format(Date()) +} + + +android { + compileSdkVersion(AndroidConfig.compileSdk) + buildToolsVersion(AndroidConfig.buildTools) + ndkVersion = AndroidConfig.ndk + + defaultConfig { + applicationId = "eu.kanade.tachiyomi" + minSdkVersion(AndroidConfig.minSdk) + targetSdkVersion(AndroidConfig.targetSdk) + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + versionCode = 54 + versionName = "0.10.7" + + buildConfigField("String", "COMMIT_COUNT", "\"${getCommitCount()}\"") + buildConfigField("String", "COMMIT_SHA", "\"${getGitSha()}\"") + buildConfigField("String", "BUILD_TIME", "\"${getBuildTime()}\"") + buildConfigField("boolean", "INCLUDE_UPDATER", "false") + + multiDexEnabled = true + + ndk { + abiFilters += setOf("armeabi-v7a", "arm64-v8a", "x86") + } + } + + buildFeatures { + viewBinding = true + } + + buildTypes { + named("debug") { + versionNameSuffix = "-${getCommitCount()}" + applicationIdSuffix = ".debug" + } + named("release") { + /*named("postprocessing") { + postprocessing { + isObfuscate = false + isOptimizeCode = true + isRemoveUnusedCode = false + isRemoveUnusedResources = true + } + setProguardFiles(listOf("proguard-rules.pro")) + }*/ + } + } + + flavorDimensions("default") + + productFlavors { + create("standard") { + buildConfigField("boolean", "INCLUDE_UPDATER", "true") + dimension = "default" + } + create("fdroid") { + dimension = "default" + } + create("dev") { + resConfigs("en", "xxhdpi") + dimension = "default" + } + } + + packagingOptions { + exclude("META-INF/DEPENDENCIES") + exclude("LICENSE.txt") + exclude("META-INF/LICENSE") + exclude("META-INF/LICENSE.txt") + exclude("META-INF/NOTICE") + } + + dependenciesInfo { + includeInApk = false + } + + lintOptions { + disable("MissingTranslation", "ExtraTranslation") + isAbortOnError = false + isCheckReleaseBuilds = false + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_1_8.toString() + } +} + +dependencies { + + // Source models and interfaces from Tachiyomi 1.x + implementation("tachiyomi.sourceapi:source-api:1.1") + + // AndroidX libraries + implementation("androidx.annotation:annotation:1.2.0-alpha01") + implementation("androidx.appcompat:appcompat:1.3.0-alpha02") + implementation("androidx.biometric:biometric-ktx:1.2.0-alpha01") + implementation("androidx.browser:browser:1.3.0") + implementation("androidx.cardview:cardview:1.0.0") + implementation("androidx.constraintlayout:constraintlayout:2.1.0-alpha2") + implementation("androidx.coordinatorlayout:coordinatorlayout:1.1.0") + implementation("androidx.core:core-ktx:1.5.0-alpha05") + implementation("androidx.multidex:multidex:2.0.1") + implementation("androidx.preference:preference-ktx:1.1.1") + implementation("androidx.recyclerview:recyclerview:1.2.0-beta01") + implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.2.0-alpha01") + + val lifecycleVersion = "2.3.0-rc01" + implementation("androidx.lifecycle:lifecycle-common-java8:$lifecycleVersion") + implementation("androidx.lifecycle:lifecycle-process:$lifecycleVersion") + implementation("androidx.lifecycle:lifecycle-runtime-ktx:$lifecycleVersion") + + // Job scheduling + implementation("androidx.work:work-runtime-ktx:2.5.0-beta02") + + // UI library + implementation("com.google.android.material:material:1.3.0-beta01") + + implementation("com.google.firebase:firebase-core:18.0.0") + + // ReactiveX + implementation("io.reactivex:rxandroid:1.2.1") + implementation("io.reactivex:rxjava:1.3.8") + implementation("com.jakewharton.rxrelay:rxrelay:1.2.0") + implementation("com.github.pwittchen:reactivenetwork:0.13.0") + + // Network client + val okhttpVersion = "4.10.0-RC1" + implementation("com.squareup.okhttp3:okhttp:$okhttpVersion") + implementation("com.squareup.okhttp3:logging-interceptor:$okhttpVersion") + implementation("com.squareup.okhttp3:okhttp-dnsoverhttps:$okhttpVersion") + implementation("com.squareup.okio:okio:2.9.0") + + // TLS 1.3 support for Android < 10 + implementation("org.conscrypt:conscrypt-android:2.5.1") + + // REST + val retrofitVersion = "2.9.0" + implementation("com.squareup.retrofit2:retrofit:$retrofitVersion") + implementation("com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0") + + // JSON + val kotlinSerializationVersion = "1.0.1" + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinSerializationVersion") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$kotlinSerializationVersion") + implementation("com.google.code.gson:gson:2.8.6") + implementation("com.github.salomonbrys.kotson:kotson:2.5.0") + + // JavaScript engine + implementation("com.squareup.duktape:duktape-android:1.3.0") + + // Disk + implementation("com.jakewharton:disklrucache:2.0.2") + implementation("com.github.inorichi:unifile:e9ee588") + implementation("com.github.junrar:junrar:7.4.0") + + // HTML parser + implementation("org.jsoup:jsoup:1.13.1") + + // Database + implementation("androidx.sqlite:sqlite-ktx:2.1.0") + implementation("com.github.inorichi.storio:storio-common:8be19de@aar") + implementation("com.github.inorichi.storio:storio-sqlite:8be19de@aar") + implementation("io.requery:sqlite-android:3.33.0") + + // Preferences + implementation("com.github.tfcporciuncula.flow-preferences:flow-preferences:1.3.3") + + // Model View Presenter + val nucleusVersion = "3.0.0" + implementation("info.android15.nucleus:nucleus:$nucleusVersion") + implementation("info.android15.nucleus:nucleus-support-v7:$nucleusVersion") + + // Dependency injection + implementation("com.github.inorichi.injekt:injekt-core:65b0440") + + // Image library + val glideVersion = "4.11.0" + implementation("com.github.bumptech.glide:glide:$glideVersion") + implementation("com.github.bumptech.glide:okhttp3-integration:$glideVersion") + kapt("com.github.bumptech.glide:compiler:$glideVersion") + + implementation("com.github.tachiyomiorg:subsampling-scale-image-view:6caf219") + + // Logging + implementation("com.jakewharton.timber:timber:4.7.1") + + // Crash reports + implementation("ch.acra:acra-http:5.7.0") + + // Sort + implementation("com.github.gpanther:java-nat-sort:natural-comparator-1.1") + + // UI + implementation("com.dmitrymalkovich.android:material-design-dimens:1.4") + implementation("com.github.dmytrodanylyk.android-process-button:library:1.0.4") + implementation("eu.davidea:flexible-adapter:5.1.0") + implementation("eu.davidea:flexible-adapter-ui:1.0.0") + implementation("com.nightlynexus.viewstatepageradapter:viewstatepageradapter:1.1.0") + implementation("com.github.chrisbanes:PhotoView:2.3.0") + implementation("com.github.carlosesco:DirectionalViewPager:a844dbca0a") + + // 3.2.0+ introduces weird UI blinking or cut off issues on some devices + val materialDialogsVersion = "3.1.1" + implementation("com.afollestad.material-dialogs:core:$materialDialogsVersion") + implementation("com.afollestad.material-dialogs:input:$materialDialogsVersion") + implementation("com.afollestad.material-dialogs:datetime:$materialDialogsVersion") + + // Conductor + implementation("com.bluelinelabs:conductor:2.1.5") + implementation("com.bluelinelabs:conductor-support:2.1.5") { + exclude(group = "com.android.support") + } + implementation("com.github.tachiyomiorg:conductor-support-preference:1.1.1") + + // FlowBinding + val flowbindingVersion = "0.12.0" + implementation("io.github.reactivecircus.flowbinding:flowbinding-android:$flowbindingVersion") + implementation("io.github.reactivecircus.flowbinding:flowbinding-appcompat:$flowbindingVersion") + implementation("io.github.reactivecircus.flowbinding:flowbinding-recyclerview:$flowbindingVersion") + implementation("io.github.reactivecircus.flowbinding:flowbinding-swiperefreshlayout:$flowbindingVersion") + implementation("io.github.reactivecircus.flowbinding:flowbinding-viewpager:$flowbindingVersion") + + // Licenses + implementation("com.mikepenz:aboutlibraries:${BuildPluginsVersion.ABOUTLIB_PLUGIN}") + + // Tests + testImplementation("junit:junit:4.13") + testImplementation("org.assertj:assertj-core:3.16.1") + testImplementation("org.mockito:mockito-core:1.10.19") + + val robolectricVersion = "3.1.4" + testImplementation("org.robolectric:robolectric:$robolectricVersion") + testImplementation("org.robolectric:shadows-multidex:$robolectricVersion") + testImplementation("org.robolectric:shadows-play-services:$robolectricVersion") + + implementation(kotlin("reflect", version = BuildPluginsVersion.KOTLIN)) + + val coroutinesVersion = "1.4.2" + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion") + + // For detecting memory leaks; see https://square.github.io/leakcanary/ +// debugImplementation("com.squareup.leakcanary:leakcanary-android:2.4") +} + +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath(kotlin("gradle-plugin", version = BuildPluginsVersion.KOTLIN)) + } +} + +repositories { + mavenCentral() + jcenter() +} + +tasks { + // See https://kotlinlang.org/docs/reference/experimental.html#experimental-status-of-experimental-api(-markers) + withType { + kotlinOptions.freeCompilerArgs += listOf( + "-Xopt-in=kotlin.Experimental", + "-Xopt-in=kotlin.RequiresOptIn", + "-Xuse-experimental=kotlin.ExperimentalStdlibApi", + "-Xuse-experimental=kotlinx.coroutines.FlowPreview", + "-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi", + "-Xuse-experimental=kotlinx.serialization.ExperimentalSerializationApi" + ) + } + + // Duplicating Hebrew string assets due to some locale code issues on different devices + val copyHebrewStrings = task("copyHebrewStrings", type = Copy::class) { + from("./src/main/res/values-he") + into("./src/main/res/values-iw") + include("**/*") + } + + preBuild { + dependsOn(formatKotlin, copyHebrewStrings) + } +} + +if (gradle.startParameter.taskRequests.toString().contains("Standard")) { + apply(plugin = "com.google.gms.google-services") +}