Tencent/matrix · error · GradleException

need sign apk but apksigner not found!

Error message

need sign apk but apksigner not found!

What it means

When `removeUnusedResources` is configured to re-sign the processed APK (`needSign = true`), the task must run apksigner to sign the rebuilt APK. This error is thrown when the configured `apksigner` value is null or empty, meaning no signer tool path was provided at all. It is a fail-fast configuration check performed before any work is done.

Solutions

  1. Set `apksigner` in the matrix removeUnusedResources extension to the full path of the apksigner binary, e.g. `$ANDROID_HOME/build-tools/34.0.0/apksigner`.
  2. Verify build-tools are installed via the SDK manager and use that version's path.
  3. If signing is handled elsewhere, disable it by setting `needSign = false` so the check is skipped.

Example fix

// before
matrix {
  removeUnusedResources {
    needSign = true
  }
}

// after
matrix {
  removeUnusedResources {
    needSign = true
    apksigner = "/opt/android-sdk/build-tools/34.0.0/apksigner"
  }
}
Defensive patterns

Strategy: validation

Validate before calling

def apksigner = "/opt/android-sdk/build-tools/34.0.0/apksigner"
assert apksigner?.trim() : 'apksigner path must be set when needSign=true'
matrix { removeUnusedResources { needSign = true; apksigner = apksigner } }

Type guard

def hasApksigner = { String p -> p != null && !p.trim().isEmpty() }

Try / catch

try { matrixRemoveUnusedResources() } catch (GradleException e) { if (e.message.contains('apksigner not found')) { ... configure apksigner ... } else throw e }

Prevention

When it happens

Trigger: `needSign` is true but the extension's `apksigner` property was never set (empty/null) when `removeUnusedResources` runs via `removeResources`.

Common situations: Enabling signing in matrixTrace/matrix config without pointing `apksigner` at `<Android SDK>/build-tools/<version>/apksigner`; using defaults on a machine without Android build-tools; copying sample config that omits the field.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


AI-assisted analysis of Tencent/matrix@3b8293bd65 (2026-09-08). Data as JSON: /api/errors/25ed4a3975e3b627. Report an issue: GitHub.

Appendix: source

Thrown at matrix/matrix-android/matrix-gradle-plugin/src/main/kotlin/com/tencent/matrix/plugin/task/RemoveUnusedResourcesTask.kt:128

                val index = typeName.indexOf('-')
                if (index >= 0) {
                    typeName = typeName.substring(0, index)
                }
                resourceName = "R.$typeName.$resName"
            }
        }
        return resourceName
    }

    private fun removeUnusedResources(
            originalApk: String,
            rTxtFile: String,
            signingConfig: SigningConfig?) {

        // Check configurations
        if (needSign) {
            if (Util.isNullOrNil(apksigner)) {
                throw GradleException("need sign apk but apksigner not found!");
            } else if (!File(apksigner).exists()) {
                throw GradleException("need sign apk but apksigner $apksigner was not exist!");
            } else if (signingConfig == null) {
                throw GradleException("need sign apk but signingConfig not found!");
            }
        }

        var zipOutputStream: ZipOutputStream? = null

        try {
            try {
                val inputFile = File(originalApk)

                for (res in ignoreRes) {
                    ignoreResources.add(Util.globToRegexp(res))
                }

                val iterator = unusedResources.iterator()

View on GitHub (pinned to 3b8293bd65)