-
Install necessary software
sudo apt install cmake golang gperf meson nasm ninja-build pkg-config rustup sdkmanager wget yasmrustup default stable && rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-androidsudo apt install google-android-platform-36-installer google-android-build-tools-36.0.0-installer google-android-ndk-r27c-installer openjdk-21-jdk-headless
-
Don't forget to include the submodules when you clone:
git clone --recursive https://github.com/forkgram/TelegramAndroid.git
-
Build the native dependencies (BoringSSL, OpenH264, Opus, libvpx, dav1d, FFmpeg, tlottie and TDLib):
- Go to the
TMessagesProj/jnifolder and execute the following (define the paths to your NDK and SDK):
export ANDROID_NDK_HOME=/usr/lib/android-sdk/ndk/27.2.12479018 export ANDROID_SDK_ROOT=/usr/lib/android-sdk export ABIS="arm64-v8a armeabi-v7a" sudo sdkmanager "cmake;3.22.1" "ndk;27.2.12479018" --sdk_root /usr/lib/android-sdk ./prebuild/build_all.shThe archives land in
TMessagesProj/jni/prebuild/lib/<abi>/; dropABISto build all four.Gradle runs the same steps automatically through
TMessagesProj/jni/prepare.py. - Go to the
-
If you want to publish a modified version of Telegram:
- You should get your own API key here: https://core.telegram.org/api/obtaining_api_id and edit a file called
gradle.propertiesin the source root directory. The contents should look like this:APP_ID = 12345 APP_HASH = aaaaaaaabbbbbbccccccfffffff001122 - Do not use the name Telegram and the standard logo (white paper plane in a blue circle) for your app — or make sure your users understand that it is unofficial
- Take good care of your users' data and privacy
- Please remember to publish your code too in order to comply with the licenses
- You should get your own API key here: https://core.telegram.org/api/obtaining_api_id and edit a file called
The project can be built with Android Studio or from the command line with gradle:
./gradlew assembleAfatRelease
The repository ships a pinned Docker image and a build script that produce byte-for-byte identical APKs across machines, given the same git revision and signing key.
Pinned in docker/Dockerfile:
- Ubuntu 22.04, JDK 17, UTC timezone,
C.UTF-8locale - Android command-line tools
11076708 - SDK platform 36, Build Tools 36.0.0
- NDK
27.2.12479018(native dependency scripts and gradleexternalNativeBuild) - CMake
3.22.1
scripts/reproducible-build.sh
SOURCE_DATE_EPOCH is taken from git log -1 --format=%ct HEAD, then exported
into the container. The script applies reproducible.gradle
as an init script, which forces preserveFileTimestamps = false and
reproducibleFileOrder = true on every archive task (AGP 8 already does this
for APKs and AABs; the init script covers custom Zip/Jar tasks).
To build a non-default target:
scripts/reproducible-build.sh :TMessagesProj_App:bundleBundleAfatRelease
scripts/verify-apk.sh path/to/published.apk \
TMessagesProj_App/build/outputs/apk/afat/release/app.apk
The script delegates to apkdiff.py which ignores the v1 signature
block (META-INF/MANIFEST.MF, META-INF/CERT.RSA, META-INF/CERT.SF) since
those depend on the signing key, not on the source.
- Build host OS leaks into the APK.
Utilities.parseIntbranches onBuildConfig.BUILD_HOST_IS_WINDOWS, which is set at build time. The reproducible image is Linux, so the canonical value is alwaysfalse. Builds run directly on Windows will diverge. - Signing key. Two builds signed with different keys will differ in the
signature blocks. Use
scripts/verify-apk.shto compare ignoring those entries, or sign the rebuilt APK with the same key before comparing. - NDK / AGP upgrades. Bumping
ndkVersion,buildToolsVersion, or the AGP/Kotlin plugin versions invalidates the reproducibility baseline. Update the Docker image in the same commit and rebuild the reference APK.