diff --git a/.github/workflows/api-compat.yml b/.github/workflows/api-compat.yml index cd8464d..30c3644 100644 --- a/.github/workflows/api-compat.yml +++ b/.github/workflows/api-compat.yml @@ -24,3 +24,66 @@ jobs: - name: Check API Compatibility run: ./gradlew :device-sdk:japicmp + + # japicmp only compares classes.jar, so nothing else guards the parts of the + # AAR that decide who can consume it. AGP derives minCompileSdk, + # minCompileSdkExtension and minCompileMinorSdk from the library's own + # compileSdk, so a compileSdk bump can raise the consumer floor without + # anyone editing this repo. The whole file is compared rather than a few + # keys, so an added or changed key has to be acknowledged here deliberately. + # + # minAndroidGradlePluginVersion=1.0.0 holds only while + # android.aar.metadata.autoEncodeMinAgpVersion stays off. Its default flips + # in AGP 10, after which AGP derives the value from compileSdk. If this + # fails during an AGP upgrade, that is a real consumer-facing change to + # decide on, not a stale expectation to edit away. + - name: Check AAR consumer metadata + if: ${{ !cancelled() }} + run: | + set -euo pipefail + + # Build what we inspect: japicmp happens to produce the AAR today, but + # only as a side effect of its own task graph. + ./gradlew :device-sdk:bundleReleaseAar + aar=device-sdk/build/outputs/aar/device-sdk-release.aar + tmp=$(mktemp -d) + + expected=$(printf '%s\n' \ + 'aarFormatVersion=1.0' \ + 'aarMetadataVersion=1.0' \ + 'coreLibraryDesugaringEnabled=false' \ + 'minAndroidGradlePluginVersion=1.0.0' \ + 'minCompileSdk=30' \ + 'minCompileSdkExtension=0') + metadata=$(unzip -p "$aar" META-INF/com/android/build/gradle/aar-metadata.properties) + echo "$metadata" + if ! diff <(sort <<<"$expected") <(sort <<<"$metadata"); then + echo "::error::AAR consumer metadata changed (< expected, > actual)" + exit 1 + fi + + manifest=$(unzip -p "$aar" AndroidManifest.xml) + echo "$manifest" + if ! grep -q 'android:minSdkVersion="27"' <<<"$manifest"; then + echo "::error::expected minSdkVersion 27 in the AAR manifest" + exit 1 + fi + + # Direct witness for the pinned Kotlin module name. japicmp catches a + # change to it only while DeviceTracker still has internal members whose + # mangled names reach the ABI, so it would stop guarding this after an + # ordinary refactor. + unzip -p "$aar" classes.jar >"$tmp/classes.jar" + entries=$(unzip -l "$tmp/classes.jar") + if ! grep -q 'META-INF/device-sdk_release\.kotlin_module' <<<"$entries"; then + echo "::error::expected META-INF/device-sdk_release.kotlin_module in classes.jar" + grep -i 'kotlin_module' <<<"$entries" || true + exit 1 + fi + + # Consumer ProGuard rules have to actually ship. + unzip -p "$aar" proguard.txt >"$tmp/proguard.txt" + if [ ! -s "$tmp/proguard.txt" ]; then + echo "::error::proguard.txt is missing or empty in the AAR" + exit 1 + fi diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3fb678..c7c3dcf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ jobs: # Use the MIT-licensed basic caching provider instead of the # default enhanced caching, which is proprietary. cache-provider: basic + # Checked in as a binary, so verify it against Gradle's published + # checksums. On by default, but stated explicitly so it cannot vanish + # in an action upgrade without a visible diff. + validate-wrappers: true - name: Build SDK run: ./gradlew :device-sdk:build @@ -39,8 +43,33 @@ jobs: - name: Build sample app run: ./gradlew :sample:assembleDebug + # Nothing else compiles the androidTest sources, and a toolchain upgrade is + # the likeliest thing to break them. Cheap, so it runs before the R8 build. + - name: Compile instrumented tests + if: ${{ !cancelled() }} + run: ./gradlew :device-sdk:assembleDebugAndroidTest + + # device-sdk's release build type and sample's debug build type are the only + # places isMinifyEnabled is set, both to false, so this is the only step + # that runs R8 over the SDK's classes at all. It does not reproduce the + # missing-class failure that motivates minCompileSdk: that needs a consumer + # compiling below 30, and the sample is at compileSdk 36. The floor itself + # is pinned by the metadata assertion in api-compat.yml. + # + # AGP also wires lintVitalRelease into the release assemble, so a failure + # here is not necessarily an R8 or keep-rule problem. + - name: Build minified sample app + if: ${{ !cancelled() }} + run: ./gradlew :sample:assembleRelease + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: test-results - path: device-sdk/build/reports/tests/ + # R8 failures are explained by missing_rules.txt and configuration.txt, + # not by the test reports, and those are otherwise discarded with the + # runner. + path: | + device-sdk/build/reports/tests/ + sample/build/outputs/mapping/release/ + sample/build/reports/ diff --git a/CHANGELOG.md b/CHANGELOG.md index d19b2ab..778656e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## 0.4.0 (TBD) + +- The published AAR now declares a `minCompileSdk` of 30. Consumers that minify, + or that set a Java 9 or later `sourceCompatibility`, already needed + `compileSdk` 30: `InstallationInfoHelper` references + `android.content.pm.InstallSourceInfo`, added in API 30, so R8 reported it as + a missing class, and the Android Gradle plugin separately refuses to configure + Java 9 or later compilation below 30. For consumers that do neither, this is a + new requirement rather than a pre-existing one. The API-30 call is guarded by + an `SDK_INT` check and is safe at runtime, so the floor trades an obscure R8 + failure for a clear Gradle error. If your build fails with a `minCompileSdk` + error, raise `compileSdk` to 30 or later, or stay on 0.3.1. Note this is your + app's `compileSdk` only: the SDK still supports API 27 and later devices, and + `minSdk` is unchanged. +- The SDK is now built with Gradle 9.6.1 and the Android Gradle plugin 9.3.1. + The public API and the published ABI are unchanged, and the artifact still + imposes no Android Gradle plugin floor on consumers, so the toolchain change + itself requires no action from consumers. + ## 0.3.1 (2026-07-24) - Removed the unused `androidx.lifecycle:lifecycle-runtime-ktx` dependency. In diff --git a/CLAUDE.md b/CLAUDE.md index 455b602..26efe7a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -33,7 +33,7 @@ Follow Kotlin conventions (kotlinlang.org/docs/coding-conventions.html): # Build SDK library only (fastest for SDK development) ./gradlew :device-sdk:assemble -# Build debug variants (skips minification issues) +# Build debug variants (no minification, so faster) ./gradlew assembleDebug # Build SDK library with all variants @@ -46,14 +46,12 @@ Follow Kotlin conventions (kotlinlang.org/docs/coding-conventions.html): ### Testing ```bash -# Run unit tests for SDK +# Run unit tests for SDK. Under AGP 9 this runs the suite once, against the +# debug variant: AGP 9 no longer registers testReleaseUnitTest. ./gradlew :device-sdk:test # Run specific test class ./gradlew :device-sdk:test --tests "com.maxmind.device.DeviceTrackerTest" - -# Run tests with coverage (JaCoCo) -./gradlew :device-sdk:testDebugUnitTest jacocoTestReport ``` ### Code Quality @@ -66,7 +64,7 @@ Follow Kotlin conventions (kotlinlang.org/docs/coding-conventions.html): ./gradlew ktlintFormat # Generate API documentation -./gradlew :device-sdk:dokkaHtml +./gradlew :device-sdk:dokkaGenerate # Output: device-sdk/build/dokka/ ``` @@ -237,24 +235,22 @@ mise run setup # Accepts licenses, installs platform packages, creates loca **Manual setup:** -1. Java 21 (Android Studio JDK) configured in `gradle.properties`: - - ``` - org.gradle.java.home=/home/greg/.local/share/android-studio/jbr - ``` +1. Java 21. The version is pinned by `mise.toml`, not by the build scripts — + there is no `org.gradle.java.home` in `gradle.properties`. Without mise, put + a Java 21 JDK on `JAVA_HOME`. -2. Android SDK with API 36 at `~/Android/Sdk` +2. Android SDK with the platform and build-tools matching `compileSdk` in + `gradle/libs.versions.toml` 3. `local.properties` file (gitignored): ```properties - sdk.dir=/home/greg/Android/Sdk + sdk.dir=/path/to/your/Android/Sdk ``` **Java Version Issues:** -- The project requires Java 17+ (set to use Java 21 from Android Studio) -- If you see "25" error, Java 25 is being used instead -- Fix by setting `org.gradle.java.home` in `gradle.properties` +- The project requires Java 17+; `mise.toml` pins Java 21 +- If Gradle picks up a different JDK, check `mise current` and `JAVA_HOME` ## Common Issues @@ -266,11 +262,6 @@ mise run setup # Accepts licenses, installs platform packages, creates loca ~/Android/Sdk/cmdline-tools/latest/bin/sdkmanager --licenses ``` -**"Resource mipmap/ic_launcher not found"** - -- Sample app has no launcher icons (intentional for simplicity) -- Build works for `assembleDebug`, may fail on `assemble` (release variant) - **Detekt/ktlint failures** - Skip with: `./gradlew build -x detekt -x ktlintCheck` @@ -278,19 +269,22 @@ mise run setup # Accepts licenses, installs platform packages, creates loca ### Release Build MinifyEnabled -The sample app has `isMinifyEnabled = true` for release builds, which may cause -R8 issues. For development: +The sample app has `isMinifyEnabled = true` for release builds, so +`:sample:assembleRelease` is the only thing that runs R8 over the SDK's classes. +CI runs it on every pull request and on pushes to `main`, so it is expected to +pass; if it starts failing, treat that as a real problem rather than an expected +quirk of the sample. -```bash -# Build debug variant instead -./gradlew :sample:assembleDebug -``` +Note what a green run does and does not prove. It shows R8 completed, not that +`consumer-rules.pro` still keeps everything kotlinx.serialization needs at +runtime — that would fail as a `SerializationException` inside a consumer app, +not as a build failure. AGP also wires `lintVitalRelease` into this task, so a +failure is not necessarily R8's. ## Testing Strategy - **Unit tests** in `device-sdk/src/test/` use JUnit 5, MockK, and Robolectric - **Android instrumented tests** in `device-sdk/src/androidTest/` -- Test coverage with JaCoCo When adding features, write unit tests that: @@ -307,7 +301,7 @@ Uses Gradle version catalog in `gradle/libs.versions.toml`: - `[plugins]` - Gradle plugins - `[bundles]` - Grouped dependencies (e.g., `ktor`, `testing`) -Access in build files: `libs.ktor.client.core`, `libs.plugins.kotlin.android` +Access in build files: `libs.ktor.client.core`, `libs.plugins.android.library` ## Maven Publishing Configuration diff --git a/README.dev.md b/README.dev.md index a74d11f..a81b746 100644 --- a/README.dev.md +++ b/README.dev.md @@ -146,3 +146,28 @@ Review the versions from the dependency update check. If you want to update: 5. Merge If you did this in the middle of releasing, start the release process over. + +## Upgrading Gradle + +`gradle/wrapper/gradle-wrapper.properties` pins `distributionSha256Sum`, so a +plain `./gradlew wrapper --gradle-version=X` fails on purpose rather than +silently dropping the checksum. Pass the new one instead: + +```bash +# Checksum for the -bin distribution, from https://gradle.org/release-checksums/ +# or https://services.gradle.org/distributions/gradle-X-bin.zip.sha256 +# First pass: rewrites gradle-wrapper.properties +./gradlew wrapper --gradle-version=X --gradle-distribution-sha256-sum= + +# Second pass: regenerates gradlew, gradlew.bat and gradle-wrapper.jar using the +# new version's own templates +./gradlew wrapper --gradle-version=X --gradle-distribution-sha256-sum= +``` + +Do not delete the checksum line to get past the failure. `retries` and +`networkTimeout` come from the `Wrapper` task configuration in the root +`build.gradle.kts`, so regeneration preserves them; only the checksum needs the +flag. + +Note that the Android Gradle plugin constrains which Gradle versions work: AGP 9 +requires Gradle 9.6 or later, and AGP 8.x cannot run on Gradle 9.6 at all. diff --git a/README.md b/README.md index 89a343e..d50534b 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,9 @@ Android SDK for collecting and reporting device data to MaxMind. ## Requirements -- Android API 27+ (Android 8.1+) +- Android API 27+ (Android 8.1+) on the device +- Your app must compile against `compileSdk` 30 or later, from 0.4.0 onwards + (the AAR declares `minCompileSdk = 30`) - A recent stable version of Kotlin - AndroidX libraries @@ -189,7 +191,7 @@ To run the sample app: ### Generate Documentation ```bash -./gradlew :device-sdk:dokkaHtml +./gradlew :device-sdk:dokkaGenerate ``` Documentation will be generated in `device-sdk/build/dokka/`. diff --git a/SETUP.md b/SETUP.md index 7283b35..6bddd2a 100644 --- a/SETUP.md +++ b/SETUP.md @@ -93,26 +93,25 @@ Replace `/path/to/your/Android/Sdk` with your actual SDK location: ./gradlew :sample:installDebug # Generate documentation -./gradlew dokkaHtml +./gradlew :device-sdk:dokkaGenerate ``` ## Publishing to Maven Central -The SDK is configured for Maven Central publishing: +Releases are cut with `./dev-bin/release.sh`. See [README.dev.md](README.dev.md) +for the full process, including Central Portal credentials and GPG setup. + +The underlying task, if you need it directly: ```bash -./gradlew :device-sdk:publishReleasePublicationToMavenCentralRepository +./gradlew :device-sdk:publishAndReleaseToMavenCentral ``` -Required credentials (set in `local.properties` or environment variables): - -```properties -signing.keyId=YOUR_KEY_ID -signing.password=YOUR_KEY_PASSWORD -signing.secretKeyRingFile=/path/to/secring.gpg -mavenCentralUsername=YOUR_USERNAME -mavenCentralPassword=YOUR_PASSWORD -``` +Credentials come from `~/.m2/settings.xml` (server id `central`), or +`mavenCentralUsername` / `mavenCentralPassword` as Gradle properties or +`ORG_GRADLE_PROJECT_*` environment variables. Signing uses the system `gpg` +command via `signing { useGpgCmd() }`, so `signing.keyId` and +`signing.secretKeyRingFile` are not used. ## Environment Variables @@ -139,12 +138,15 @@ $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses ### Wrong Java Version +The Java version is pinned in `mise.toml`. Check what is actually active: + ```bash -# Use Android Studio's JDK -export JAVA_HOME=~/.local/share/android-studio/jbr -./gradlew build +mise current +java -version ``` +Without mise, put a JDK matching `mise.toml` on `JAVA_HOME`. + ### SDK Not Found Ensure `local.properties` exists with correct SDK path: diff --git a/build.gradle.kts b/build.gradle.kts index ba265be..8dafdc4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,6 @@ plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false - alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.serialization) apply false alias(libs.plugins.dokka) apply false alias(libs.plugins.detekt) apply false @@ -18,3 +17,15 @@ allprojects { tasks.register("clean", Delete::class) { delete(rootProject.layout.buildDirectory) } + +// gradle-wrapper.properties is generated, so any hand edit there is lost the next +// time someone runs `./gradlew wrapper`. Declaring the values here means a +// regeneration reproduces them. distributionSha256Sum is deliberately not set +// here: it changes with every Gradle version, and Gradle already refuses to +// regenerate the wrapper for a new version while it is present unless +// --gradle-distribution-sha256-sum is passed. See README.dev.md. +tasks.withType().configureEach { + networkTimeout = 10000 + retries = 2 + retryBackOffMs = 500 +} diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index 11ca3d7..235c544 100644 --- a/device-sdk/build.gradle.kts +++ b/device-sdk/build.gradle.kts @@ -2,7 +2,6 @@ import java.net.URI plugins { alias(libs.plugins.android.library) - alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.serialization) alias(libs.plugins.dokka) alias(libs.plugins.detekt) @@ -29,6 +28,28 @@ android { testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles("consumer-rules.pro") + // The lowest compileSdk consumers can build against. + // InstallationInfoHelper references android.content.pm.InstallSourceInfo + // (API 30), so R8 reports it as a missing class for consumers minifying + // below that, and declaring the floor turns that into a clear Gradle + // error. Setting it explicitly also pins the value rather than + // inheriting whatever the Android Gradle plugin defaults to. + // + // A narrower fix exists: -dontwarn android.content.pm.InstallSourceInfo + // in consumer-rules.pro would silence R8 without declaring any floor, + // since the call is SDK_INT guarded and InstallationInfoHelper is + // internal, so consumer compilation never resolves the type. The floor + // was chosen deliberately anyway: a compileSdk below 30 also cannot + // compile Java 9+ source, and Play's targetSdk policy already requires + // far higher, so the set of consumers this excludes cannot ship. A clear + // Gradle error is worth more to them than a suppressed warning. + // + // If a collector ever references an android.* type newer than API 30, + // this value has to be raised to match; nothing verifies that for us. + aarMetadata { + minCompileSdk = 30 + } + // Build config fields for SDK metadata buildConfigField("String", "SDK_VERSION", "\"${project.version}\"") buildConfigField("String", "SDK_NAME", "\"MaxMind Device SDK\"") @@ -64,6 +85,23 @@ kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + // Pins the published ABI -- do not remove. The module name reaches the + // artifact two ways: it names the META-INF/.kotlin_module file, and + // it is mangled into the JVM names of internal members, which also show + // up in the kotlin.Metadata d2 array of every class that references them. + // The consumer-visible public API is byte-for-byte unaffected, so this is + // about keeping the artifact's internal symbols stable rather than about + // consumer source compatibility. "device-sdk_release" is the name 0.3.1 + // and earlier published; AGP 9's built-in Kotlin would use the project + // name instead. The api-compat workflow asserts the .kotlin_module name + // directly, so deleting this line fails CI. + // + // Setting it in the shared compilerOptions block gives every compilation + // the same name instead of AGP 8's per-variant names. That is harmless + // (.kotlin_module files are stripped from APKs) and means the unit tests + // exercise the same mangled names that ship in the release AAR. + moduleName.set("device-sdk_release") + // Enable explicit API mode for better library API design freeCompilerArgs.addAll( "-Xexplicit-api=strict", @@ -173,39 +211,47 @@ signing { val baselineVersion = "0.3.1" // Download baseline AAR directly from Maven Central to avoid local project resolution -val downloadBaselineAar by tasks.registering { - val outputFile = layout.buildDirectory.file("japicmp/baseline.aar") - outputs.file(outputFile) - doLast { - val url = "https://repo1.maven.org/maven2/com/maxmind/device/device-sdk/$baselineVersion/device-sdk-$baselineVersion.aar" - val destFile = outputFile.get().asFile - destFile.parentFile.mkdirs() - URI(url).toURL().openStream().use { input -> - destFile.outputStream().use { output -> - input.copyTo(output) +val downloadBaselineAar = + tasks.register("downloadBaselineAar") { + val outputFile = layout.buildDirectory.file("japicmp/baseline.aar") + outputs.file(outputFile) + doLast { + val url = "https://repo1.maven.org/maven2/com/maxmind/device/device-sdk/$baselineVersion/device-sdk-$baselineVersion.aar" + val destFile = outputFile.get().asFile + destFile.parentFile.mkdirs() + // Bounded: an unbounded read here can hang the api-compat job until + // GitHub's six-hour job limit rather than failing. + val connection = URI(url).toURL().openConnection() + connection.connectTimeout = 30_000 + connection.readTimeout = 60_000 + connection.getInputStream().use { input -> + destFile.outputStream().use { output -> + input.copyTo(output) + } } + logger.lifecycle("Downloaded baseline AAR from $url") } - logger.lifecycle("Downloaded baseline AAR from $url") } -} // Extract classes.jar from baseline AAR for comparison -val extractBaselineClasses by tasks.registering(Copy::class) { - dependsOn(downloadBaselineAar) - from(zipTree(layout.buildDirectory.file("japicmp/baseline.aar"))) { - include("classes.jar") +val extractBaselineClasses = + tasks.register("extractBaselineClasses") { + dependsOn(downloadBaselineAar) + from(zipTree(layout.buildDirectory.file("japicmp/baseline.aar"))) { + include("classes.jar") + } + into(layout.buildDirectory.dir("japicmp/baseline")) } - into(layout.buildDirectory.dir("japicmp/baseline")) -} // Extract classes.jar from current AAR for comparison -val extractCurrentClasses by tasks.registering(Copy::class) { - dependsOn("bundleReleaseAar") - from(zipTree(layout.buildDirectory.file("outputs/aar/device-sdk-release.aar"))) { - include("classes.jar") +val extractCurrentClasses = + tasks.register("extractCurrentClasses") { + dependsOn("bundleReleaseAar") + from(zipTree(layout.buildDirectory.file("outputs/aar/device-sdk-release.aar"))) { + include("classes.jar") + } + into(layout.buildDirectory.dir("japicmp/current")) } - into(layout.buildDirectory.dir("japicmp/current")) -} tasks.register("japicmp") { dependsOn(extractBaselineClasses, extractCurrentClasses) diff --git a/gradle.properties b/gradle.properties index debd080..2f53702 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,9 +18,14 @@ kotlin.incremental=true kotlin.incremental.js=true # Build features -android.defaults.buildfeatures.buildconfig=false -android.defaults.buildfeatures.aidl=false -android.defaults.buildfeatures.renderscript=false +# The buildconfig, aidl, and renderscript buildFeatures properties were removed +# in AGP 9, so they are no longer set here. The features themselves default to +# false; modules that need buildConfig enable it in their own buildFeatures +# block, and both of ours do. +# +# The two below are still read by AGP 9, but only one is here to stay: shaders is +# stable, while resvalues is deprecated for removal in AGP 10. Both features +# already default to false. android.defaults.buildfeatures.resvalues=false android.defaults.buildfeatures.shaders=false diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 6b78982..72f3b5b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -10,7 +10,7 @@ coroutines = "1.11.0" serialization = "1.11.0" # Android -androidGradlePlugin = "8.13.1" +androidGradlePlugin = "9.3.1" androidxAppCompat = "1.7.1" androidxLifecycle = "2.11.0" @@ -79,7 +79,6 @@ robolectric = { module = "org.robolectric:robolectric", version.ref = "robolectr [plugins] android-application = { id = "com.android.application", version.ref = "androidGradlePlugin" } android-library = { id = "com.android.library", version.ref = "androidGradlePlugin" } -kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" } kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index d64cd49..b1b8ef5 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37f78a6..94aa4a6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,10 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-bin.zip +distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 +retries=2 +retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index e174624..249efbb 100755 --- a/gradlew +++ b/gradlew @@ -1,7 +1,7 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright © 2015 the original authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -15,10 +15,12 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # -# Gradle start up script for POSIX generated by Gradle. +# gradlew start up script for POSIX generated by Gradle. # # Important for running: # @@ -27,7 +29,7 @@ # bash, then to run this script, type that shell name before the whole # command line, like: # -# ksh Gradle +# ksh gradlew # # Busybox and similar reduced shells will NOT work, because this script # requires all of these POSIX shell features: @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/3d91ce3b8caaf77ad09f381f43615b715b53f72c/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,7 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -111,7 +114,6 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. @@ -144,7 +146,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +154,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -169,7 +171,6 @@ fi # For Cygwin or MSYS, switch paths to Windows format before running java if "$cygwin" || "$msys" ; then APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) JAVACMD=$( cygpath --unix "$JAVACMD" ) @@ -202,15 +203,14 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..8508ef6 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,92 +1,82 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem gradlew startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables, and ensure extensions are enabled +setlocal EnableExtensions + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +"%COMSPEC%" /c exit 1 + +:execute +@rem Setup the command line + + + +@rem Execute gradlew +@rem endlocal doesn't take effect until after the line is parsed and variables are expanded +@rem which allows us to clear the local environment before executing the java command +endlocal & "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* & call :exitWithErrorLevel + +:exitWithErrorLevel +@rem Use "%COMSPEC%" /c exit to allow operators to work properly in scripts +"%COMSPEC%" /c exit %ERRORLEVEL% diff --git a/sample/build.gradle.kts b/sample/build.gradle.kts index 7ad9a65..178a666 100644 --- a/sample/build.gradle.kts +++ b/sample/build.gradle.kts @@ -2,7 +2,6 @@ import java.util.Properties plugins { alias(libs.plugins.android.application) - alias(libs.plugins.kotlin.android) alias(libs.plugins.detekt) alias(libs.plugins.ktlint) }