2# Build the release APK inside a pinned Docker image for byte-for-byte
3# reproducibility. SOURCE_DATE_EPOCH is derived from the HEAD commit so the
4# same git revision always produces the same archive timestamps.
7# scripts/reproducible-build.sh [gradle-task]
9# Default task: :TMessagesProj_App:assembleAfatRelease
10# Output: TMessagesProj_App/build/outputs/apk/...
14REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
17GRADLE_TASK="${1:-:TMessagesProj_App:assembleAfatRelease}"
18IMAGE_TAG="${IMAGE_TAG:-telegramandroid-reproducible:latest}"
20if [ -z "${SOURCE_DATE_EPOCH:-}" ]; then
21 SOURCE_DATE_EPOCH="$(git log -1 --format=%ct HEAD)"
23export SOURCE_DATE_EPOCH
25echo "==> SOURCE_DATE_EPOCH = ${SOURCE_DATE_EPOCH} ($(date -u -r "${SOURCE_DATE_EPOCH}" '+%Y-%m-%d %H:%M:%S UTC' 2>/dev/null || date -u -d "@${SOURCE_DATE_EPOCH}"))"
26echo "==> Gradle task = ${GRADLE_TASK}"
27echo "==> Docker image = ${IMAGE_TAG}"
29echo "==> Building Docker image..."
30docker build -t "${IMAGE_TAG}" -f docker/Dockerfile docker/
32echo "==> Running Gradle build inside container..."
34 -v "${REPO_ROOT}:/project" \
36 -e SOURCE_DATE_EPOCH \
37 -e GRADLE_OPTS="-Dorg.gradle.daemon=false -Duser.timezone=UTC" \
41 # Prebuild the native dependencies that are not part of the gradle
42 # externalNativeBuild graph.
44 export NDK=\${ANDROID_NDK_HOME}
45 export NINJA_PATH=/usr/bin/ninja
46 ./ffmpeg/build_ffmpeg_libvpx_dav1d_android_ndk27_merged.sh
50 ./gradlew --no-daemon --init-script reproducible.gradle ${GRADLE_TASK}
53echo "==> Build artifacts:"
54find TMessagesProj_App/build/outputs/apk -name '*.apk' -print 2>/dev/null | while read -r apk; do
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list