Fix Android SDK Manager failures behind corporate proxies

Summary

Building Android apps in CI behind a corporate proxy often fails because the sdkmanager tool does not honor the proxy settings that work for curl or Gradle. The root cause is a mismatch between the authentication method required by the corporate proxy (NTLM or Basic with special characters) and the way sdkmanager parses proxy credentials. The result is the “Failed to download any source lists” and the 3 % fetch stall.

Root Cause

  • sdkmanager uses Java’s built‑in HttpURLConnection which, by default, doesn’t support NTLM and strips special characters from passwords.
  • The tool reads proxy config only from ~/.android/repositories.cfg or system properties; environment variables (http_proxy, https_proxy) are ignored.
  • When the password contains characters like @, : or $, they are either interpreted as delimiters or URL‑encoded incorrectly, causing authentication to fail silently.

Why This Happens in Real Systems

  • Corporate networks often enforce a man‑in‑the‑middle proxy that requires NTLM or Kerberos authentication.
  • CI runners are usually headless containers that lack the native Windows libraries NTLM depends on.
  • Developers tend to copy‑paste proxy settings from curl or Gradle, assuming they work universally, but sdkmanager has its own parsing rules.

Real-World Impact

  • Build pipelines stall at the SDK download stage, wasting compute minutes and increasing CI costs.
  • Failed releases because the required build tools or platform packages never arrive.
  • Debugging fatigue as engineers chase environment variables that look correct but are ignored by sdkmanager.

Example or Code (if necessary and relevant)

# Set up a local Nexus proxy for Google repositories
cat > ~/.android/repositories.cfg <<EOF
[repositories]
url=https://nexus.company.com/repository/google/
username=${PROXY_USERNAME}
password=${PROXY_PASSWORD}
EOF

How Senior Engineers Fix It

  • Use a Nexus/Artifactory “Google Repository” proxy and point sdkmanager at it via repositories.cfg (as shown above).
  • Escape special characters in passwords by surrounding the whole value in single quotes and using URL‑encoding only for the password part:
    export SDKMANAGER_OPTS="-Dhttps.proxyHost=${PROXY_ADDRESS} -Dhttps.proxyPort=${PROXY_PORT} -Dhttps.proxyUser=${PROXY_USERNAME} -Dhttps.proxyPassword=$(printf '%s' "${PROXY_PASSWORD}" | jq -s -R -r @uri)"
  • Force sdkmanager to use Basic auth by adding:
    export JAVA_TOOL_OPTIONS="-Djdk.http.auth.tunneling.disabledSchemes= -Djdk.http.auth.proxying.disabledSchemes= -Dhttp.auth.preference=basic"
  • Wrap the SDK download in a retry script that falls back to the Nexus mirror if the direct download fails.
  • Cache the SDK in the CI runner’s Docker image or in a shared volume, eliminating the need for proxy auth during each run.

Why Juniors Miss It

  • They assume environment variables are universal, overlooking that sdkmanager ignores them.
  • They often don’t check the password for special characters or test the exact string that the tool receives.
  • They lack experience with NTLM‑only proxies and therefore don’t know to switch to a repository mirror or to set repositories.cfg.
  • Junior engineers may try to fix the symptom (adding more systemProp lines) instead of understanding the tool’s configuration entry points.

Leave a Comment