Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tfonteyn/NeverTooManyBooks/llms.txt

Use this file to discover all available pages before exploring further.

NeverTooManyBooks is a standard Android Gradle project. A clean debug build requires no special credentials or keys — just a working Android development environment. Release builds require an external signing configuration loaded from a properties file outside the repository root, so signing secrets are never committed to version control.
1
Install Prerequisites
2
Ensure the following tools are available on your machine before cloning:
3
  • Android Studio — use the latest stable release. The BUILDING file notes to use whichever latest or non-broken version works; there is no minimum pinned version in the repo.
  • JDK 17 or later — the Gradle Java toolchain reads the required version from the version catalog (libs.versions.javaToolchain). Gradle will automatically provision the correct JDK via toolchain resolution if it is not already installed, but having JDK 17+ available locally avoids a download on first build.
  • Android SDK — install via Android Studio’s SDK Manager. The project uses:
    • minSdk: API 26 (Android 8.0 Oreo)
    • compileSdk / targetSdk: API 36 (latest stable at time of writing)
    • Install both the platform package and the Build Tools for each SDK level you need.
  • 4
    The commit hash of HEAD is captured at build time and embedded in BuildConfig.GIT_HASH via:
    def buildingFromCommitHash = providers.exec {
        commandLine 'git', 'rev-parse', '--short=12', 'HEAD'
    }.standardOutput.asText.get().strip()
    
    This means every APK carries a 12-character git hash for traceability. Make sure git is on your PATH before building.
    5
    Clone the Repository
    6
    git clone https://github.com/tfonteyn/NeverTooManyBooks.git
    cd NeverTooManyBooks
    
    7
    Open in Android Studio
    8
  • Launch Android Studio.
  • Select File → Open (or Open from the Welcome screen).
  • Navigate to the cloned folder and click OK.
  • Android Studio will detect the Gradle project and sync automatically. Allow the initial sync to finish — it will download all declared dependencies.
  • 9
    Select a Build Variant
    10
    Open the Build Variants panel (bottom-left in Android Studio, or View → Tool Windows → Build Variants) and choose:
    11
    debug
    Recommended for development. No signing configuration is required. The application ID gains a .debug suffix (com.hardbacknutter.nevertoomanybooks.debug), so a debug build can be installed alongside a release build.
    ./gradlew assembleDebug
    
    The output APK is named NeverTooManyBooks-<versionName>-debug.apk and located in app/build/outputs/apk/debug/.
    beta
    Initialised from the release config with a -beta version name suffix. Requires the same signing configuration as release. Used for public beta distributions.
    ./gradlew assembleBeta
    
    release
    Requires a signing configuration (see the next step). Enables minification (minifyEnabled = true) and resource shrinking (shrinkResources = true) via ProGuard/R8.
    ./gradlew assembleRelease
    
    12
    Configure Release Signing (Release Builds Only)
    13
    Without a valid signing configuration, assembleRelease will print "Keystore properties file not found. No signing configuration will be applied." and produce an unsigned APK that cannot be installed on a device. Always configure signing before distributing a release build.
    14
    Signing credentials are kept entirely outside the repository. The lookup chain is:
    15
    Step 1. Add the path to your properties file in $HOME/.gradle/gradle.properties:
    16
    NeverTooManyBooks.properties=/path/to/NeverTooManyBooks.properties
    
    17
    Step 2. Create the referenced properties file with your keystore details:
    18
    sign.storeFile=/path/to/keystore.jks
    sign.storePassword=MyStorePassword
    sign.keyAlias=MyKeyAlias
    sign.keyPassword=MyKeyPassword
    
    19
    Gradle reads these values in app/build.gradle via:
    20
    signingConfigs {
        release {
            if (!keystoreProperties.isEmpty()) {
                storeFile     = file(keystoreProperties["sign.storeFile"])
                storePassword = keystoreProperties["sign.storePassword"]
                keyAlias      = keystoreProperties["sign.keyAlias"]
                keyPassword   = keystoreProperties["sign.keyPassword"]
            }
        }
    }
    
    21
    Run Unit Tests
    22
    JUnit 5 is used for unit tests (via the mannodermaus Gradle plugin):
    23
    # Run all unit tests (JVM)
    ./gradlew test
    
    # Run unit tests for a specific module
    ./gradlew :app:testDebugUnitTest
    
    24
    Test XML reports are written to <module>/build/reports/tests/; HTML reports are disabled by default (configured in the root build.gradle).
    25
    Run Instrumented Tests
    26
    Instrumented tests require a connected Android device or running emulator:
    27
    ./gradlew connectedAndroidTest
    
    28
    The test runner is androidx.test.runner.AndroidJUnitRunner with the JUnit 5 AndroidJUnit5Builder configured via testInstrumentationRunnerArguments.
    29
    Run Code Style Checks
    30
    A checkstyle.xml configuration is provided in the repository. Run the check with:
    31
    ./gradlew checkstyle
    
    32
    Fix any reported violations before submitting a pull request. The lint task is also available, though abortOnError is set to false to allow command-line CI builds to complete even with warnings:
    33
    ./gradlew lint
    

    Code Tags

    The codebase uses a consistent set of inline comment tags (always followed by a colon) to annotate work items at the point of the relevant code:
    TagMeaning
    URGENT:Not a show-stopper, but really needs attention soon
    TEST:Work done and minimally tested; full testing not yet complete
    RELEASE:Must be checked before any public release
    NEWTHINGS:Notes on how to wire in new functionality of a given type
    FIXME:A workaround is present or the situation is acceptable, but needs a proper fix
    TODO:Needs work — time permitting
    ENHANCE:An improvement worth making — time permitting
    Use your IDE’s TODO tool window (in Android Studio: View → Tool Windows → TODO) with a custom filter pattern to find all project-specific tags at once. Set the pattern to \b(URGENT|TEST|RELEASE|NEWTHINGS|FIXME|TODO|ENHANCE):\b.

    Gradle Performance Tuning

    The gradle.properties file enables several Gradle performance features that speed up incremental builds:
    org.gradle.jvmargs=-Xmx4g -Dfile.encoding=UTF-8
    org.gradle.caching=true
    org.gradle.configuration-cache=true
    org.gradle.configureondemand=true
    org.gradle.parallel=true
    org.gradle.vfs.watch=true
    
    If you encounter configuration-cache failures during development (e.g., after changing build scripts), run ./gradlew --no-configuration-cache <task> to bypass the cache for that invocation.

    Build docs developers (and LLMs) love