ZaStoGram/TMessagesProj/build.gradle
loop-uh a8e12dd75a Proxy lifecycle ownership, plugin infra, editable forwarding
Implement proxy lifecycle ownership model distinguishing visible from health-only events based on socket role and origin; add configGeneration for FakeTLS budget state independent of activation lifecycle; introduce resume grace period masking for stale phases during app foreground transitions.

Centralize proxy link parsing into ProxyLinkHelper with clipboard extraction; add clipboard proxy alert on app resume.

Expand plugin infrastructure with text formatting, structured settings, Android/client utilities, and UI bridge for settings screens.

Introduce EditableForwardDraft for caption editing and album/separate-post grouping modes in message forwarding.

Add video frame capture feature for PhotoViewer and PeerStoriesView with gallery save support.

Increase socket role tracking through proxy connection event pipeline for distinguishing control/media/background traffic in diagnostics.

Update proxy check guards and runtime log verifiers to enforce lifecycle ownership boundaries and new architectural constraints.
2026-07-04 17:38:27 +03:00

328 lines
15 KiB
Groovy

import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform
apply plugin: 'com.android.library'
// ZaStoGram plugin engine: embed CPython so .plugin scripts (exteraGram-compatible)
// can run. Chaquopy may be applied to exactly one module per app; TMessagesProj is the
// shared library, so every app flavor (Standalone/App/Huawei/...) inherits plugin support.
apply plugin: 'com.chaquo.python'
repositories {
mavenCentral()
google()
}
configurations {
compile.exclude module: 'support-v4'
}
configurations.all {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'androidx.recyclerview', module: 'recyclerview'
}
dependencies {
implementation 'androidx.core:core:1.16.0'
implementation 'androidx.webkit:webkit:1.14.0'
implementation 'androidx.palette:palette:1.0.0'
implementation 'androidx.exifinterface:exifinterface:1.3.6'
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0'
implementation "androidx.sharetarget:sharetarget:1.2.0"
implementation 'androidx.interpolator:interpolator:1.0.0'
implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.google.android.gms:play-services-cast-framework:21.4.0'
implementation "androidx.mediarouter:mediarouter:1.7.0"
implementation 'androidx.car.app:app:1.4.0'
implementation 'androidx.car.app:app-projected:1.4.0'
implementation 'org.nanohttpd:nanohttpd:2.3.1'
compileOnly 'org.checkerframework:checker-qual:2.5.2'
compileOnly 'org.checkerframework:checker-compat-qual:2.5.0'
implementation 'com.google.firebase:firebase-messaging:22.0.0'
implementation 'com.google.firebase:firebase-config:21.0.1'
implementation 'com.google.firebase:firebase-datatransport:18.1.0'
implementation 'com.google.firebase:firebase-appindexing:20.0.0'
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation 'com.google.android.gms:play-services-auth:20.4.0'
implementation 'com.google.android.gms:play-services-vision:20.1.3'
implementation 'com.google.android.gms:play-services-wearable:18.0.0'
implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-wallet:19.1.0'
implementation 'com.googlecode.mp4parser:isoparser:1.0.6'
implementation 'com.stripe:stripe-android:2.0.2'
implementation 'com.google.mlkit:language-id:17.0.6'
implementation 'com.android.billingclient:billing:7.1.1'
implementation 'com.google.code.gson:gson:2.11.0'
implementation 'com.google.guava:guava:31.1-android'
implementation 'com.google.android.play:integrity:1.3.0'
implementation 'com.google.android.gms:play-services-safetynet:18.0.1'
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
implementation 'com.google.android.gms:play-services-mlkit-image-labeling:16.0.8'
implementation "androidx.credentials:credentials:1.6.0-alpha04"
implementation "androidx.credentials:credentials-play-services-auth:1.6.0-alpha04"
implementation "io.noties.markwon:core:4.6.2"
implementation "io.noties.markwon:ext-strikethrough:4.6.2"
implementation "io.noties.markwon:ext-tables:4.6.2"
implementation "io.noties.markwon:html:4.6.2"
implementation "io.noties.markwon:inline-parser:4.6.2"
implementation "io.noties.markwon:ext-latex:4.6.2"
// implementation 'com.google.mlkit:translate:17.0.3'
constraints {
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") {
because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
}
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") {
because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
}
}
implementation 'com.google.android.recaptcha:recaptcha:18.7.1'
// ZaStoGram plugin engine: Pine — dynamic ART method hooking (Xposed-compatible API).
// Supports Android 4.4(ART)-15 on arm64/armv7. The :xposed module exposes
// XC_MethodHook (before/afterHookedMethod + MethodHookParam) used by the bridge.
implementation 'top.canyie.pine:core:0.3.0'
// NOTE: the :xposed compat module's latest published version is 0.2.0 (there is no 0.3.0).
// 0.2.0 declares no dependency on :core, so it coexists with core:0.3.0. If runtime ART
// hooking ever misbehaves from version skew, pin core down to 0.2.9 to match.
implementation 'top.canyie.pine:xposed:0.2.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
}
def isWindows = String.valueOf(DefaultNativePlatform.currentOperatingSystem.toFamilyName() == OperatingSystemFamily.WINDOWS)
def zastoAllNativeAbis = ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
def zastoRequestedAbiFilter = (project.findProperty("zastoAbiFilter") ?: System.getenv("ZASTO_ABI_FILTER"))?.toString()?.trim()
if (zastoRequestedAbiFilter && !zastoAllNativeAbis.contains(zastoRequestedAbiFilter)) {
throw new GradleException("Unsupported zastoAbiFilter '${zastoRequestedAbiFilter}'. Expected one of: ${zastoAllNativeAbis.join(', ')}")
}
android {
compileSdkVersion 35
buildToolsVersion '35.0.0'
ndkVersion "27.2.12479018"
sourceSets.main.jniLibs.srcDirs = ['./jni/']
externalNativeBuild {
cmake {
path 'jni/CMakeLists.txt'
}
}
lintOptions {
disable 'MissingTranslation'
disable 'ExtraTranslation'
disable 'BlockedPrivateApi'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
coreLibraryDesugaringEnabled true
}
defaultConfig {
minSdkVersion 24 // ZaStoGram: Chaquopy (plugin engine) requires minSdk >= 24
targetSdkVersion 35
vectorDrawables.generatedDensities = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi']
multiDexEnabled true
// ZaStoGram: CI matrix jobs pass one ABI so the library module does not rebuild
// all native outputs before packaging a single-ABI APK. Without the property, keep
// the universal fallback for local builds and afat.
ndk {
abiFilters(*(zastoRequestedAbiFilter ? [zastoRequestedAbiFilter] : zastoAllNativeAbis))
}
externalNativeBuild {
cmake {
version '3.10.2'
def cmakeArgs = ['-DANDROID_STL=c++_static', '-DANDROID_PLATFORM=android-21'] //, '-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON'
// CI speedup: route NDK compiles through ccache so unchanged native sources
// (webrtc/openh264/ffmpeg/boringssl) reuse cached object files across runs.
// Enabled only when USE_CCACHE=1 (GitHub Actions); local builds are unaffected.
if (System.getenv('USE_CCACHE') == '1') {
cmakeArgs << '-DCMAKE_C_COMPILER_LAUNCHER=ccache' << '-DCMAKE_CXX_COMPILER_LAUNCHER=ccache'
}
arguments(*cmakeArgs)
}
}
}
buildTypes {
debug {
jniDebuggable true
minifyEnabled false
shrinkResources false
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro', '../TMessagesProj/proguard-rules-beta.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"\""
buildConfigField "String", "BETA_URL", "\"" + getProps("BETA_PRIVATE_URL") + "\""
buildConfigField "boolean", "DEBUG_VERSION", "true"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "0"
}
HA_private {
jniDebuggable false
minifyEnabled true
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro', '../TMessagesProj/proguard-rules-beta.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_PRIVATE") + "\""
buildConfigField "String", "BETA_URL", "\"" + getProps("BETA_PRIVATE_URL") + "\""
buildConfigField "boolean", "DEBUG_VERSION", "true"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "1"
}
HA_public {
jniDebuggable false
minifyEnabled true
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro', '../TMessagesProj/proguard-rules-beta.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_PUBLIC") + "\""
buildConfigField "String", "BETA_URL", "\"" + getProps("BETA_PUBLIC_URL") + "\""
buildConfigField "boolean", "DEBUG_VERSION", "true"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "4"
}
HA_hardcore {
jniDebuggable false
minifyEnabled true
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro', '../TMessagesProj/proguard-rules-beta.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"" + getProps("APP_CENTER_HASH_HARDCORE") + "\""
buildConfigField "String", "BETA_URL", "\"" + getProps("BETA_HARDCORE_URL") + "\""
buildConfigField "boolean", "DEBUG_VERSION", "true"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "true"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "5"
}
standalone {
jniDebuggable false
// The standalone app module runs final R8 with this module's proguard rules.
// Running R8 here first only makes CI do an extra minify pass before the APK pass.
minifyEnabled false
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"\""
buildConfigField "String", "BETA_URL", "\"\""
buildConfigField "boolean", "DEBUG_VERSION", "false"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "6"
}
release {
jniDebuggable false
minifyEnabled true
shrinkResources false
multiDexEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), '../TMessagesProj/proguard-rules.pro'
ndk.debugSymbolLevel = 'FULL'
buildConfigField "String", "BUILD_VERSION_STRING", "\"" + APP_VERSION_NAME + "\""
buildConfigField "String", "APP_CENTER_HASH", "\"\""
buildConfigField "String", "BETA_URL", "\"\""
buildConfigField "boolean", "DEBUG_VERSION", "false"
buildConfigField "boolean", "DEBUG_PRIVATE_VERSION", "false"
buildConfigField "boolean", "BUNDLE", "false"
buildConfigField "boolean", "BUILD_HOST_IS_WINDOWS", isWindows
buildConfigField "int", "VERSION_NUM", "7"
}
}
namespace 'org.telegram.messenger'
}
// ZaStoGram plugin engine — Python runtime configuration.
// Host API modules live in src/main/python (base_plugin, client_utils, ui.*, ...).
// User .plugin scripts are loaded at runtime from the data dir, not bundled here.
chaquopy {
defaultConfig {
version "3.11" // matches exteraGram (Chaquopy 16, CPython 3.11)
// The build machine needs a CPython 3.11 on PATH. If Android Studio can't find
// it (common on Windows), uncomment and point at it explicitly:
// buildPython "C:/Users/<you>/AppData/Local/Programs/Python/Python311/python.exe"
pyc {
src false // ship readable .py so plugin tracebacks map to real lines
}
pip {
// Common third-party libs community plugins expect at runtime. Chaquopy can only
// install these at BUILD time (there is no runtime pip), so they must be declared
// here once and shipped in the APK — mirrors what exteraGram bundles.
install "beautifulsoup4" // common HTML parsing helper used by plugin libraries
install "debugpy" // debugger backend listed by exteraGram for plugin development
install "lxml" // XML/HTML parser bundled by exteraGram
install "packaging" // version parsing for shared plugin libraries such as ZwyLib
install "Pillow" // exposes PIL for image-processing plugins
install "PyYAML" // YAML parser bundled by exteraGram
install "pyfiglet" // ASCIIGenerator and ASCII art plugins
install "requests" // th3_proxy_tools (country flags via ip-api, URL import) + many others
}
}
}
def getProps(String propName) {
def propsFile = rootProject.file('local.properties')
if (propsFile.exists()) {
def props = new Properties()
props.load(new FileInputStream(propsFile))
return props[propName]
} else {
return "";
}
}
apply plugin: 'com.google.gms.google-services'
task checkVisibility {
doFirst {
def isPrivateBuild = project.gradle.startParameter.taskNames.find {
it.contains("HA_private") || it.contains("HA_hardcore") || it.contains("Debug") || it.contains("Release")
}
def isPublicAllowed = !project.hasProperty("IS_PRIVATE") || !project.property("IS_PRIVATE").toBoolean()
if (!isPrivateBuild && !isPublicAllowed) {
throw new GradleException("Building public version of private code!")
}
}
doLast {
if (project.gradle.startParameter.taskNames.find { it.contains("HA_public") }) {
def privateBuild = file("${projectDir}_AppHockeyApp/afat/HA_private/Telegram-Beta.apk")
if (privateBuild.exists()) {
privateBuild.delete()
}
}
}
}
preBuild.dependsOn checkVisibility