aboutsummaryrefslogtreecommitdiff
path: root/app/build.gradle
blob: d16a8d50f7c51d2f5f1ad5010d18df11cdff7b8e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
plugins {
    id 'com.android.application'
}

android {
    namespace 'invalid.lena.scrcpy'
    compileSdk 35
    // Pin build-tools explicitly so the aapt2/zipalign/d8 toolchain is
    // fixed and builds stay reproducible, not whatever AGP defaults to.
    // 35.0.0 is the compileSdk's.
    buildToolsVersion '35.0.0'

    defaultConfig {
        // The published package id. Immutable across releases.
        applicationId 'invalid.lena.scrcpy'
        minSdk 31
        targetSdk 35
        versionCode 1
        versionName '0.1'
    }

    // AGP otherwise embeds a Google-signed dependency-metadata blob in the
    // APK that is not byte-reproducible. Strip it so the build stays
    // deterministic. This is the single most common reproducible-build
    // breaker on AGP.
    dependenciesInfo {
        includeInApk    false
        includeInBundle false
    }

    // Release signing pulls credentials from the environment. Set all
    // four of KEYSTORE_PATH / KEYSTORE_PASS / KEY_ALIAS / KEY_PASS and
    // assembleRelease produces a signed APK. With any of them missing
    // the release build is unsigned (Gradle's default).
    signingConfigs {
        release {
            def ksPath = System.getenv('KEYSTORE_PATH')
            def ksPass = System.getenv('KEYSTORE_PASS')
            def kAlias = System.getenv('KEY_ALIAS')
            def kPass  = System.getenv('KEY_PASS')
            if (ksPath && ksPass && kAlias && kPass) {
                storeFile     file(ksPath)
                storePassword ksPass
                keyAlias      kAlias
                keyPassword   kPass
            }
        }
    }

    // Native ABI policy: release ships arm64-v8a only. Every targeted
    // source device is 64-bit ARM in practice; 32-bit-only devices are
    // not supported. The test rig uses an x86_64 emulator, so debug keeps
    // x86_64 (and arm64) so ./test e2e still works.
    buildTypes {
        debug {
            applicationIdSuffix '.debug'
            versionNameSuffix '-debug'
            ndk {
                abiFilters 'arm64-v8a', 'x86_64'
            }
        }
        release {
            ndk {
                abiFilters 'arm64-v8a'
            }
            minifyEnabled   true
            shrinkResources true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
                          'proguard-rules.pro'
            if (System.getenv('KEYSTORE_PATH')) {
                signingConfig signingConfigs.release
            }
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_17
        targetCompatibility JavaVersion.VERSION_17
    }

    packaging {
        // bouncycastle (transitive via :adb) is the dominant source of
        // dead weight in the APK. Each entry below is dead code/data for
        // our use case (we only call BC's asn1, crypto, util.encoders):
        //   - picnic post-quantum lookup tables: ~1.2 MB of .properties
        //   - cert-path-reviewer i18n messages: ~92 KB, en+de only
        //   - kotlin metadata: bleed from spake2-android (Kotlin lib);
        //     our code is pure Java and doesn't reflect on .kotlin_builtins
        //   - androidx annotation LICENSE.txt: 10 KB blob, no runtime use
        //   - duplicate META-INF licenses/notices: ordinary AGP cleanup
        resources.excludes += [
            'META-INF/LICENSE*',
            'META-INF/NOTICE*',
            'META-INF/versions/9/OSGI-INF/MANIFEST.MF',
            'META-INF/androidx/**',
            'META-INF/kotlin-stdlib*',
            'org/bouncycastle/pqc/crypto/picnic/**',
            'org/bouncycastle/x509/CertPathReviewerMessages*.properties',
            'kotlin/**',
        ]
    }

    testOptions {
        // android.util.Log and friends are stubs on the JVM unit-test
        // classpath; let them return defaults instead of throwing.
        unitTests.returnDefaultValues = true
    }
}

dependencies {
    implementation project(':adb')
    // bcprov is already pulled in transitively by :adb at runtime; we
    // need it on the compile classpath too for Adb.java's ASN.1
    // cert-builder. :adb keeps it 'implementation'-scoped upstream so
    // we declare it explicitly here rather than patch the vendor tree.
    implementation 'org.bouncycastle:bcprov-jdk15to18:1.81'

    // Bundled Conscrypt. libadb-android's TLS pairing exports keying
    // material via Conscrypt. Without a bundled copy it reflects into the
    // platform's hidden com.android.org.conscrypt.Conscrypt, which under
    // targetSdk 35 is invisible to reflection (getMethod throws
    // NoSuchMethodException and pairing fails on real devices). Bundling a
    // standalone Conscrypt flips libadb onto the public
    // org.conscrypt.Conscrypt API, which is not restricted. Ships a native
    // .so (filtered to arm64-v8a in release).
    implementation 'org.conscrypt:conscrypt-android:2.5.2'

    testImplementation 'junit:junit:4.13.2'
    testImplementation 'org.json:json:20240303'
}