From 5d7cfba62d95dc05d682c1e3519ff0619feb2d49 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 21:00:20 +0000 Subject: [PATCH 01/15] Declare a minCompileSdk of 30 in the AAR metadata InstallationInfoHelper references android.content.pm.InstallSourceInfo, which was added in API 30. A runtime SDK_INT guard keeps that safe at execution time, but it does not help R8: a consumer minifying against compileSdk 29 or lower fails with "Missing class android.content.pm.InstallSourceInfo". Declaring the floor turns that confusing R8 failure into a clear Gradle error. Verified by building a consumer app against every platform from 27 to 36: compileSdk 30 and above succeed for both debug and minified release builds, while 29 and below fail. Consumers compiling Java 9+ source already needed compileSdk 30, so this only makes an existing requirement explicit rather than adding one. Declaring the value explicitly also keeps AGP from defaulting it to our own compileSdk, which would otherwise force consumers up to 36. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 12 ++++++++++++ README.md | 1 + device-sdk/build.gradle.kts | 10 ++++++++++ 3 files changed, 23 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d19b2ab..0245d1e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # 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. + ## 0.3.1 (2026-07-24) - Removed the unused `androidx.lifecycle:lifecycle-runtime-ktx` dependency. In diff --git a/README.md b/README.md index 89a343e..5b3b1e2 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Android SDK for collecting and reporting device data to MaxMind. ## Requirements - Android API 27+ (Android 8.1+) +- `compileSdk` 30+ - A recent stable version of Kotlin - AndroidX libraries diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index 11ca3d7..3826348 100644 --- a/device-sdk/build.gradle.kts +++ b/device-sdk/build.gradle.kts @@ -29,6 +29,16 @@ 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. + aarMetadata { + minCompileSdk = 30 + } + // Build config fields for SDK metadata buildConfigField("String", "SDK_VERSION", "\"${project.version}\"") buildConfigField("String", "SDK_NAME", "\"MaxMind Device SDK\"") From 4461a1b62066079f88520c2e6eb1adf652e6851d Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 21:00:38 +0000 Subject: [PATCH 02/15] Upgrade to Gradle 9.6.1 and Android Gradle plugin 9.3.1 Gradle 9.6.0 removed several internal Problems API classes, including org.gradle.api.problems.internal.InternalProblems, which AGP 8.x binds to. AGP 8.13.1 therefore fails at plugin application on Gradle 9.6, so the two upgrades have to happen together. AGP 9 ships built-in Kotlin support and rejects the separate org.jetbrains.kotlin.android plugin, so that plugin is removed from both modules, from the root build file, and from the version catalog. The kotlin version reference is still used by kotlin-stdlib and the serialization plugin. The buildconfig, aidl, and renderscript buildFeatures properties were removed in AGP 9 and now warn that they have no effect. Both modules already enable buildConfig explicitly in their own buildFeatures blocks. The Kotlin module name is pinned to its AGP 8 value so the published ABI does not change. See the comment in device-sdk/build.gradle.kts. One behavior change to note: AGP 9 no longer registers testReleaseUnitTest, so ./gradlew :device-sdk:test now runs the 164 unit tests once against the debug variant instead of twice. All of them pass, as do detekt, ktlintCheck, japicmp, dokkaGenerate, and both sample app variants. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 4 + CLAUDE.md | 2 +- build.gradle.kts | 1 - device-sdk/build.gradle.kts | 14 +- gradle.properties | 9 +- gradle/libs.versions.toml | 3 +- gradle/wrapper/gradle-wrapper.jar | Bin 43462 -> 48462 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 24 ++-- gradlew.bat | 174 +++++++++++------------ sample/build.gradle.kts | 1 - 11 files changed, 122 insertions(+), 114 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0245d1e..8734e4e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ 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. +- 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) diff --git a/CLAUDE.md b/CLAUDE.md index 455b602..608310f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -307,7 +307,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/build.gradle.kts b/build.gradle.kts index ba265be..0006e79 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 diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index 3826348..23b557e 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) @@ -74,6 +73,19 @@ kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + // Pins the published ABI -- do not remove. The Kotlin module name is + // baked into kotlin.Metadata and into the mangled JVM names of internal + // members, so changing it rewrites the ABI of every class without any + // source change. "device-sdk_release" is the name 0.3.1 and earlier + // published; AGP 9's built-in Kotlin would otherwise use the project + // name. japicmp enforces this, so deleting the line fails api-compat. + // + // 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", diff --git a/gradle.properties b/gradle.properties index debd080..a72ae25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -18,9 +18,12 @@ 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 properties below are still read by AGP 9. 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 d64cd4917707c1f8861d8cb53dd15194d4248596..b1b8ef56b44f16b14dc800fa8103a6d89abb526f 100644 GIT binary patch delta 39897 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

Igj3NXa_|8<`c7r$X{#UWi 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[sex+d!zoXF=a?l-EdR8AUn8#-&A&o?v{ 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

yb%-OYcg6{P)b3;TV;9l88> zH7}mIwVJI>bGwUSXd1>bE7+mmCfKsNAfs{*q1f=$vJWmoDyVo4@x5=l%f2_Eq_{ z{BA6Js?P81xnJ+Xu|K?JgY)GVk*>Fsr|fExbxKT|W$*%csmL8}?)re2w_jwsE`7CN zdPumP^?|RoN!Cfca|6w7KV${y>(%{QC4POM?n_UHOT0=##V`Jg9k>(0B!2eaU70Mt zR_Bj~Kk^qU%DtC5{3lRH=IEn9ovj}pRK|3*D1BUMf2j5N#|^E=>ixJAf5l`cF5W+t zE&7nVj!oLav-`W<{Ked=|I9Uc#VNmXqrm11&+BKkv2%B~|2=<6BT!*VkaYd(wl9gW@ou&?~8$?-q>F2_DbRq&+0i&=i9=| zdF(fiTw-3{@Wxg4o$^k@66Wr|;<`1Z;`=82S1JzNrmR#H6|rl1Sd0Ao6(8e!b~+jU zH$OY&u!P=SMU}(zzr0t~{`$rC{Gh@7qW+yD1 z>Cus2cGvZ8(shp?dRd2+PwOw3=9{*7@~X_qg7bXZJaR2t55Ktr99pgi)i>(|ZaoMF zUV(X(XY%^>k({|3?Q9)@3!d#K3vO_d@z#A`qXg_^6#%gz1MmbGIM~fMS#XogMhG zY)}+k69p@36H}S&uvtI``QA=j6oqAyK!p)9@Jkkf)}fkoNC9k;tPyT2 zH7bK8`Zu#pR@|&F1HK6j=5)0^cRA1fKfSYEeB?@*l_yQ)N ziRXYO8ljjNrVUoSUq=e85Pl62(DC*t3e$AK3NP!agB2pK_dpMMe*>UGCE)c%{9uKM zv-;5$#+puU-0CO;I$}N;=(aULtb=0ZS4*G*rAgaVW#DISV?^O<>&cGW{AA!qHv>Ir zhhm7B{p9ZLkuu;zgn>550Tt+@DDZWhyl|)JWYHa_GVtS4fz~*pC~|TJD~j96F}Zn% zy$s@zNCpNI6orr7;0k~5Fp>eCUj#Y6h=D;7MPaTNRH3>I{2U#i`%t4&I|Qsq!C4a= zmhfX&fS%ArF-;^4sL(?Ov9W-GK?_AeU<6Qs^kjuy+>sXmHasH+)(LC#1^~+; yR9`KhG /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) } From eb8a550cca6fb2d934e279fda3764c7a060b7fbd Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:13:05 +0000 Subject: [PATCH 03/15] Register the japicmp pipeline tasks without the deprecated delegate Gradle 9.6 deprecated the `val name by tasks.registering { }` property delegate syntax, scheduled for removal in Gradle 10. All three uses were in the japicmp pipeline, which is the only automated guard on the Kotlin module name pin, so it is the last thing that should break on a future Gradle upgrade. Switched to the `tasks.register(...)` form already used by the japicmp task itself just below. TaskProvider semantics are unchanged, so the existing dependsOn references still work. This does not silence the build's Gradle 10 warning entirely: detekt 1.23.8 also calls the deprecated ReportingExtension.file(String) from DetektPlugin.apply, which we cannot fix from here. Co-Authored-By: Claude Opus 5 (1M context) --- device-sdk/build.gradle.kts | 51 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index 23b557e..e481775 100644 --- a/device-sdk/build.gradle.kts +++ b/device-sdk/build.gradle.kts @@ -195,39 +195,42 @@ 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() + URI(url).toURL().openStream().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) From ebfddbe0edf9accd6f96a184fa94e2548f09abd5 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:15:10 +0000 Subject: [PATCH 04/15] Retry the Gradle distribution download twice Gradle 9.6.1's wrapper task writes retries and retryBackOffMs into gradle-wrapper.properties, and its default is retries=0. Gradle 9.3.1's wrapper had no retry support at all, so the upgrade did not change behavior, it only made the setting visible. Set retries=2 so a transient failure fetching the distribution retries instead of failing the job outright. The 500ms backoff default is kept. Co-Authored-By: Claude Opus 5 (1M context) --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index a9db115..bf86364 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -2,7 +2,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 -retries=0 +retries=2 retryBackOffMs=500 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME From f8c68d4b1bbcb3172758d28c71e1f8f65acb7acf Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:15:27 +0000 Subject: [PATCH 05/15] Run R8 and compile instrumented tests in CI Two verification gaps that the minCompileSdk work made pointed. R8 ran in no CI job. ci.yml built only :sample:assembleDebug, and both debug variants set isMinifyEnabled = false, as does the SDK's own release variant. The AAR's minCompileSdk floor is justified entirely by an R8 missing-class failure, so the one code path that justifies it had no coverage. :sample:assembleRelease closes that. The androidTest sources were never even compiled by CI, and a toolchain upgrade is the likeliest thing to break them. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3fb678..df95bc7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,19 @@ jobs: - name: Build sample app run: ./gradlew :sample:assembleDebug + # The debug variants both set isMinifyEnabled = 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. + - name: Build minified sample app + run: ./gradlew :sample:assembleRelease + + # Nothing else compiles the androidTest sources, and a toolchain upgrade is + # the likeliest thing to break them. + - name: Compile instrumented tests + run: ./gradlew :device-sdk:assembleDebugAndroidTest + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: From e8acd1ed329582210c71fd651e97589bc3385432 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:16:10 +0000 Subject: [PATCH 06/15] Assert the AAR's consumer metadata in the api-compat workflow japicmp compares classes.jar only, so the parts of the AAR that decide who can consume the library had no automated guard: minCompileSdk, minAndroidGradlePluginVersion, and the manifest's minSdkVersion. That is precisely the regression class worth guarding. AGP 9 defaults minCompileSdk to the library's own compileSdk, so a future compileSdk bump would silently raise the consumer floor to match, which is the breakage 0.3.1 removed for GitHub #63. Pinning the expected values in CI means changing them takes a deliberate edit here as well. Verified the check fails as intended: building with minCompileSdk 29 fails the assertion, and restoring 30 passes it. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/api-compat.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/api-compat.yml b/.github/workflows/api-compat.yml index cd8464d..42cbe32 100644 --- a/.github/workflows/api-compat.yml +++ b/.github/workflows/api-compat.yml @@ -24,3 +24,32 @@ jobs: - name: Check API Compatibility run: ./gradlew :device-sdk:japicmp + + # japicmp only compares classes.jar, so nothing guards the parts of the AAR + # that decide who can consume it. AGP 9 defaults minCompileSdk to the + # library's own compileSdk, which would silently raise the floor to 36 on a + # future compileSdk bump. These values are deliberate, so a change should + # have to be made here too. + - name: Check AAR consumer metadata + run: | + set -euo pipefail + aar=device-sdk/build/outputs/aar/device-sdk-release.aar + metadata=$(unzip -p "$aar" META-INF/com/android/build/gradle/aar-metadata.properties) + echo "$metadata" + # aarFormatVersion and aarMetadataVersion matter as much as the floors: + # bumping either stops older AGP versions from reading the AAR at all. + for expected in \ + minCompileSdk=30 \ + minAndroidGradlePluginVersion=1.0.0 \ + aarFormatVersion=1.0 \ + aarMetadataVersion=1.0; do + if ! grep -qxF "$expected" <<<"$metadata"; then + echo "::error::expected $expected in the AAR's aar-metadata.properties" + exit 1 + fi + done + manifest=$(unzip -p "$aar" AndroidManifest.xml) + if ! grep -q 'android:minSdkVersion="27"' <<<"$manifest"; then + echo "::error::expected minSdkVersion 27 in the AAR manifest" + exit 1 + fi From 80102ba49cbcfa350599dbb8391b1dce250e9ad4 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:16:48 +0000 Subject: [PATCH 07/15] Fix stale dokka and JaCoCo references in the docs Under Dokka 2 the V1 tasks are disabled: `:device-sdk:tasks --all` lists dokkaHtml as "[V1 tasks disabled]", so every documented invocation of it fails. The working task is dokkaGenerate. Fixed in CLAUDE.md, README.md and SETUP.md, and the SETUP.md one is now module-qualified like the others. JaCoCo appears in no build file: there is no plugin, no jacocoTestReport task, and no coverage measurement of any kind. Removed the command and the "Test coverage with JaCoCo" claim from CLAUDE.md rather than leaving instructions that cannot work. Both are pre-existing rather than introduced by the toolchain upgrade. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 19 ++++++------------- README.md | 2 +- SETUP.md | 2 +- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 608310f..e6fdff8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,9 +51,6 @@ Follow Kotlin conventions (kotlinlang.org/docs/coding-conventions.html): # 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 +63,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/ ``` @@ -269,7 +266,6 @@ mise run setup # Accepts licenses, installs platform packages, creates loca **"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** @@ -278,19 +274,16 @@ 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: - -```bash -# Build debug variant instead -./gradlew :sample:assembleDebug -``` +The sample app has `isMinifyEnabled = true` for release builds, so +`:sample:assembleRelease` is what exercises R8 against the SDK and its consumer +ProGuard rules. CI runs it on every push, so it is expected to pass; if it +starts failing, treat that as a real R8 or keep-rule problem rather than an +expected quirk of the sample. ## 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: diff --git a/README.md b/README.md index 5b3b1e2..4ea3643 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,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..006ef01 100644 --- a/SETUP.md +++ b/SETUP.md @@ -93,7 +93,7 @@ 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 From 51f9dbc3ed9dd866bf687feaad679fa64ab102a7 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 22:29:38 +0000 Subject: [PATCH 08/15] Pin the Gradle distribution checksum validateDistributionUrl only checks that the distribution URL looks like an official Gradle host; it does not verify the bytes that come back. distributionSha256Sum makes the wrapper reject a corrupted or tampered distribution before executing it. The value is the published checksum from https://services.gradle.org/distributions/gradle-9.6.1-bin.zip.sha256. Verified both directions: a fresh download into an empty GRADLE_USER_HOME validates and runs, and substituting a wrong hash fails with "Verification of Gradle distribution failed!", so the check is active rather than silently ignored. Note for future wrapper upgrades: this value has to be updated alongside distributionUrl or the build will refuse to start. Co-Authored-By: Claude Opus 5 (1M context) --- gradle/wrapper/gradle-wrapper.properties | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index bf86364..33e6de9 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip +distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 networkTimeout=10000 retries=2 retryBackOffMs=500 From d260d8e35483270342c13238a262b6bc03e6619f Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 23:57:06 +0000 Subject: [PATCH 09/15] Harden the AAR consumer-metadata check The check asserted that four keys were present and constrained nothing else, which leaves the hole it was written to close. AGP writes up to nine keys and derives minCompileSdk, minCompileSdkExtension and minCompileMinorSdk from the library's own compileSdk, so a compileSdk bump to something like "36.1" or an SDK-extension target could raise the consumer floor while all four greps still passed. The whole file is now compared against an expected set, so any added or changed key has to be acknowledged here. Three other gaps in the same step: - It consumed an AAR it did not build. The artifact existed only because :device-sdk:japicmp pulls in bundleReleaseAar through its own task graph, and the step was skipped whenever japicmp failed, including for unrelated reasons like the baseline download being unavailable. It now builds the AAR itself and runs unless the job is cancelled. - Nothing witnessed the pinned Kotlin module name directly. japicmp only catches a change to it while DeviceTracker still has internal members whose mangled names reach the ABI; making those private would remove the guard with no failing check. The step now asserts META-INF/device-sdk_release.kotlin_module inside classes.jar. - Nothing checked that consumer ProGuard rules ship at all, so proguard.txt is asserted present and non-empty. The manifest branch now prints the manifest before failing, matching the properties branch. Verified all four failure modes: a changed value, an unexpected extra key, a removed moduleName pin (which produces META-INF/device-sdk.kotlin_module), and the passing baseline. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/api-compat.yml | 68 ++++++++++++++++++++++++-------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/.github/workflows/api-compat.yml b/.github/workflows/api-compat.yml index 42cbe32..30c3644 100644 --- a/.github/workflows/api-compat.yml +++ b/.github/workflows/api-compat.yml @@ -25,31 +25,65 @@ jobs: - name: Check API Compatibility run: ./gradlew :device-sdk:japicmp - # japicmp only compares classes.jar, so nothing guards the parts of the AAR - # that decide who can consume it. AGP 9 defaults minCompileSdk to the - # library's own compileSdk, which would silently raise the floor to 36 on a - # future compileSdk bump. These values are deliberate, so a change should - # have to be made here too. + # 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" - # aarFormatVersion and aarMetadataVersion matter as much as the floors: - # bumping either stops older AGP versions from reading the AAR at all. - for expected in \ - minCompileSdk=30 \ - minAndroidGradlePluginVersion=1.0.0 \ - aarFormatVersion=1.0 \ - aarMetadataVersion=1.0; do - if ! grep -qxF "$expected" <<<"$metadata"; then - echo "::error::expected $expected in the AAR's aar-metadata.properties" - exit 1 - fi - done + 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 From f6457e2225ac55bfa01855680c3178d82c5772ff Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 23:57:58 +0000 Subject: [PATCH 10/15] Correct comments this branch got wrong Four inaccuracies, all in comments added or rewritten on this branch. ci.yml claimed "the debug variants both set isMinifyEnabled = false". device-sdk has no debug block at all; the only two explicit settings are device-sdk's release block and sample's debug block. The conclusion was right but someone grepping for a debug setting would not find one. Also noted that AGP wires lintVitalRelease into the release assemble, so a failure there is not necessarily an R8 problem. The moduleName comment said the name is "baked into kotlin.Metadata" and that changing it "rewrites the ABI of every class". Both overstate it: the name reaches the artifact as the .kotlin_module file name and through mangled internal member names, and the consumer-visible public API is byte-for-byte unaffected. A maintainer weighing whether to keep the line would have been reasoning from an implied consumer breakage that does not occur. It now also points at the .kotlin_module assertion rather than japicmp, which only guards it incidentally. gradle.properties said the remaining two properties are "still read by AGP 9", which is true but flattens them: shaders is stable, resvalues is deprecated for removal in AGP 10. The aarMetadata comment now records why the hard floor was chosen over -dontwarn in consumer-rules.pro, so the trade-off reads as a decision, and notes that raising the floor is manual if a collector ever references a newer android.* type. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 14 +++++++++----- device-sdk/build.gradle.kts | 28 ++++++++++++++++++++++------ gradle.properties | 4 +++- 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index df95bc7..5c16cac 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,11 +39,15 @@ jobs: - name: Build sample app run: ./gradlew :sample:assembleDebug - # The debug variants both set isMinifyEnabled = 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. + # 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 run: ./gradlew :sample:assembleRelease diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index e481775..ee28ffb 100644 --- a/device-sdk/build.gradle.kts +++ b/device-sdk/build.gradle.kts @@ -34,6 +34,18 @@ android { // 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 } @@ -73,12 +85,16 @@ kotlin { compilerOptions { jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) - // Pins the published ABI -- do not remove. The Kotlin module name is - // baked into kotlin.Metadata and into the mangled JVM names of internal - // members, so changing it rewrites the ABI of every class without any - // source change. "device-sdk_release" is the name 0.3.1 and earlier - // published; AGP 9's built-in Kotlin would otherwise use the project - // name. japicmp enforces this, so deleting the line fails api-compat. + // 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 diff --git a/gradle.properties b/gradle.properties index a72ae25..2f53702 100644 --- a/gradle.properties +++ b/gradle.properties @@ -23,7 +23,9 @@ kotlin.incremental.js=true # false; modules that need buildConfig enable it in their own buildFeatures # block, and both of ours do. # -# The two properties below are still read by AGP 9. +# 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 From ed1ab49c39ff3a1354552fe1b7cf45f6ece88784 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 23:58:19 +0000 Subject: [PATCH 11/15] Tell consumers how to respond to the minCompileSdk floor The entry described the new requirement but not the remedy, and did not distinguish the consumer's compileSdk from device support, which readers routinely conflate. Adds both. Not marked "**Breaking:**" despite the 0.2.0 convention: a consumer has to build against compileSdk 29 or lower, pin Java 8 source compatibility and minify to be affected at all, and Play's targetSdk policy means such an app cannot ship an update regardless. Labelling it would imply action for the overwhelming majority who need none. This also corrects 5d7cfba's commit message, which claimed the floor "only makes an existing requirement explicit rather than adding one" and cited compileSdk 29 and below failing in debug builds too. That is wrong: a Java 8 consumer that does not minify builds fine at 27, 28 and 29, so for them the floor is genuinely new. The earlier evidence came from a test consumer configured with Java 17 source compatibility, which hits AGP's separate Java 9 rule at the same threshold and masked the difference. The CHANGELOG is the accurate record; the commit message is not being rewritten because those commits have already been reviewed. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8734e4e..778656e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,10 @@ 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. + 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 From 50e3749a0d4256f9cfde892cc27a94c631d2159f Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Fri, 24 Jul 2026 23:59:54 +0000 Subject: [PATCH 12/15] Keep the wrapper settings across regeneration retries=2 and distributionSha256Sum are hand edits to a generated file, with no Wrapper task configuration anywhere and no upgrade runbook. The checksum is safe by accident: Gradle refuses to regenerate the wrapper for a new version while it is set unless --gradle-distribution-sha256-sum is passed. retries was not safe at all. Confirmed both directions by regenerating the wrapper. Without a Wrapper task configuration, `./gradlew wrapper --gradle-version 9.6.1` silently rewrote retries=2 back to retries=0. With the configuration added to the root build file, regeneration reproduces the file byte for byte. 4461a1b on this branch is where the original loss happened: regenerating for the 9.6.1 upgrade is what emitted retries=0 in the first place. Also moved distributionSha256Sum above distributionUrl. Gradle writes these keys alphabetically, so the previous position would have produced an unrelated reorder hunk on the next regeneration. README.dev.md gains an "Upgrading Gradle" section, because the failure a maintainer hits is a checksum GradleException with no repo-side guidance, and the tempting fix is to delete the line that is protecting them. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- README.dev.md | 25 ++++++++++++++++++++++++ build.gradle.kts | 12 ++++++++++++ gradle/wrapper/gradle-wrapper.properties | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) 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/build.gradle.kts b/build.gradle.kts index 0006e79..8dafdc4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -17,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/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 33e6de9..94aa4a6 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip distributionSha256Sum=9c0f7faeeb306cb14e4279a3e084ca6b596894089a0638e68a07c945a32c9e14 +distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip networkTimeout=10000 retries=2 retryBackOffMs=500 From 75d21ab32cdddd535a9a1e2c7b9309269c197925 Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Sat, 25 Jul 2026 00:00:29 +0000 Subject: [PATCH 13/15] Stop CI steps from masking each other The two steps added in b259f44 close independent verification gaps, but ran serially with no condition, so an R8 failure meant never learning whether the androidTest sources still compile. On a toolchain upgrade, which is what those steps are for, that turns one red run into several. Both now run unless the job is cancelled, and the cheap androidTest compile goes first. The artifact upload collected only test reports, so when the R8 step fails the files that explain it -- missing_rules.txt, configuration.txt, mapping.txt and any lint report -- were discarded with the runner, leaving whatever R8 truncated into the console log. Missing-class errors in particular print long reference lists. Also set validate-wrappers explicitly on setup-gradle. It defaults to true, but this branch replaces gradle-wrapper.jar and the only integrity check for that was an invisible default that an action upgrade could change without a diff. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c16cac..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,6 +43,12 @@ 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 @@ -49,15 +59,17 @@ jobs: # 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 - # Nothing else compiles the androidTest sources, and a toolchain upgrade is - # the likeliest thing to break them. - - name: Compile instrumented tests - run: ./gradlew :device-sdk:assembleDebugAndroidTest - - 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/ From 04ebfc3303fdb9c5e62d5994175f9d647254d2af Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Sat, 25 Jul 2026 00:00:50 +0000 Subject: [PATCH 14/15] Bound the japicmp baseline download The baseline fetch used URI(url).toURL().openStream() with no timeouts, so a stalled connection to Maven Central hangs the api-compat job until GitHub's six-hour limit instead of failing. Adds a 30s connect and 60s read timeout. Not pinning a checksum for the baseline: it is a different artifact every release, so dev-bin/release.sh would have to maintain the expected value, and the bytes are fetched over HTTPS from Maven Central and only feed a CI-side comparison. Resolving the baseline through a real Gradle configuration so that dependency verification covers it would be the better fix if this is worth hardening further. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- device-sdk/build.gradle.kts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/device-sdk/build.gradle.kts b/device-sdk/build.gradle.kts index ee28ffb..235c544 100644 --- a/device-sdk/build.gradle.kts +++ b/device-sdk/build.gradle.kts @@ -219,7 +219,12 @@ val downloadBaselineAar = 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 -> + // 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) } From 40d7e8af013b729e49877648358931289380111b Mon Sep 17 00:00:00 2001 From: Gregory Oschwald Date: Sat, 25 Jul 2026 00:02:02 +0000 Subject: [PATCH 15/15] Fix documentation that describes things that are not true All pre-existing, none introduced by the upgrade, but CLAUDE.md is the file agents read first so wrong instructions there are expensive. CLAUDE.md: - The manual setup told developers to set org.gradle.java.home in gradle.properties. That key is not there and never has been; the JDK is pinned by mise.toml. The surrounding paths were another developer's home directory. - The "Resource mipmap/ic_launcher not found" common issue describes an error no build can produce: nothing references @mipmap/ic_launcher and the sample manifest has no android:icon. Removed rather than half-fixed. - "CI runs it on every push" was wrong: ci.yml is push to main plus pull request, so a feature-branch push with no PR runs nothing. Someone relying on that would believe R8 had been exercised when it had not. - Tempered the claim that assembleRelease "exercises R8 against the SDK and its consumer ProGuard rules": a green run proves R8 completed, not that the keep rules still preserve what kotlinx.serialization needs, which fails at runtime in consumer apps rather than at build time. - Noted that AGP 9 runs :device-sdk:test once rather than twice, which was previously recorded only in a commit message. - "Build debug variants (skips minification issues)" contradicted the Release Build MinifyEnabled section 240 lines below. SETUP.md documented :device-sdk:publishReleasePublicationToMavenCentral- Repository, which does not exist for the Vanniktech plugin, plus signing.keyId / secretKeyRingFile properties that are never read because signing uses useGpgCmd(). Points at README.dev.md and the real task. README.md's new compileSdk bullet sat directly under "Android API 27+" with no subject change, inviting the reading that support for API 27-29 devices was dropped. It was not. Reported by horgh. Co-Authored-By: Claude Opus 5 (1M context) --- CLAUDE.md | 41 +++++++++++++++++++++-------------------- README.md | 5 +++-- SETUP.md | 30 ++++++++++++++++-------------- 3 files changed, 40 insertions(+), 36 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e6fdff8..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,7 +46,8 @@ 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 @@ -234,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`: +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`. - ``` - org.gradle.java.home=/home/greg/.local/share/android-studio/jbr - ``` - -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 @@ -263,10 +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) - **Detekt/ktlint failures** - Skip with: `./gradlew build -x detekt -x ktlintCheck` @@ -275,10 +270,16 @@ mise run setup # Accepts licenses, installs platform packages, creates loca ### Release Build MinifyEnabled The sample app has `isMinifyEnabled = true` for release builds, so -`:sample:assembleRelease` is what exercises R8 against the SDK and its consumer -ProGuard rules. CI runs it on every push, so it is expected to pass; if it -starts failing, treat that as a real R8 or keep-rule problem rather than an -expected quirk of the sample. +`: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. + +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 diff --git a/README.md b/README.md index 4ea3643..d50534b 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,9 @@ Android SDK for collecting and reporting device data to MaxMind. ## Requirements -- Android API 27+ (Android 8.1+) -- `compileSdk` 30+ +- 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 diff --git a/SETUP.md b/SETUP.md index 006ef01..6bddd2a 100644 --- a/SETUP.md +++ b/SETUP.md @@ -98,21 +98,20 @@ Replace `/path/to/your/Android/Sdk` with your actual SDK location: ## 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: