The Gradle 19,597 Wrapper pins a project to one Gradle version with four committed files: gradlew, gradlew.bat, a 46 KB gradle-wrapper.jar launcher and gradle-wrapper.properties. The first run downloads that distribution into ~/.gradle/wrapper/dists, so every machine builds alike. BookNest's wrapper was created once with a system Gradle, gradle wrapper --gradle-version 9.7.1; upgrades run ./gradlew wrapper --gradle-version <new>.
Its gradle-wrapper.properties names the distribution in one line, distributionUrl=https\://services.gradle.org/distributions/gradle-9.7.1-bin.zip, and a retries setting worth raising on a flaky network. ./gradlew --version reports the Gradle and JDK that really run (Gradle 9.7.1 on JDK 17.0.20.1 here) plus Kotlin: 2.4.0, the Kotlin Gradle embeds for your .gradle.kts scripts, not the 2.4.20 compiler that builds the app. Now build the debug APK:
./gradlew assembleDebug> Task :app:preBuild UP-TO-DATE ... > Task :app:compileDebugKotlin ... > Task :app:assembleDebug BUILD SUCCESSFUL in 4m 3s 36 actionable tasks: 36 executed
That cold build downloaded Compose 234 and the Kotlin compiler; run unchanged, all 36 tasks report UP-TO-DATE in 3 seconds, because Gradle compares each task's inputs and outputs with its last run. The APK lands in app/build/outputs/apk/debug/, signed with ~/.android/debug.keystore. Other everyday tasks are installDebug, test, connectedAndroidTest (Testing), lint, bundleRelease (Building an Android App Bundle) and clean.