aboutsummaryrefslogtreecommitdiff
path: root/app/build.gradle
diff options
context:
space:
mode:
authorLena <lena@omega>2026-08-01 00:00:00 +0000
committerLena <lena@omega>2026-08-01 00:00:00 +0000
commit827653aa291e37ae63c0cfa1eee4fbaa20cea122 (patch)
tree20f874004e1676b055bc695d3b1483bef9932fe7 /app/build.gradle
parentdcda3f64e0822554f647ec73fa8b0252268b87a0 (diff)
downloadscrcpy-android-827653aa291e37ae63c0cfa1eee4fbaa20cea122.tar.gz
build: pin and verify release inputs
Diffstat (limited to 'app/build.gradle')
-rw-r--r--app/build.gradle65
1 files changed, 35 insertions, 30 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 323f340..2c8ec99 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -5,18 +5,18 @@ plugins {
import java.security.MessageDigest
android {
- namespace 'invalid.lena.scrcpy'
- compileSdk 35
+ namespace = 'invalid.lena.scrcpy'
+ compileSdk 36
// 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.
+ // 35.0.0 is AGP 8.13's supported default.
buildToolsVersion '35.0.0'
defaultConfig {
// The published package id. Immutable across releases.
applicationId 'invalid.lena.scrcpy'
minSdk 31
- targetSdk 35
+ targetSdk 36
versionCode 4
versionName '0.4'
}
@@ -26,8 +26,8 @@ android {
// deterministic. This is the single most common reproducible-build
// breaker on AGP.
dependenciesInfo {
- includeInApk false
- includeInBundle false
+ includeInApk = false
+ includeInBundle = false
}
// Release signing pulls credentials from the environment. Set all
@@ -49,10 +49,9 @@ android {
}
}
- // 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.
+ // Ship one ordinary APK containing both supported 64-bit ABIs. arm64
+ // covers physical devices; x86_64 covers emulators and ChromeOS without
+ // introducing split-APK installation logic.
buildTypes {
debug {
applicationIdSuffix '.debug'
@@ -62,15 +61,32 @@ android {
}
}
release {
+ // x86_64 is here so the emulator can install and RUN the
+ // minified artifact. Without it no tier ever executed the
+ // variant that ships, and an R8 misconfiguration - a keep
+ // rule that is too narrow, a reflective edge R8 could not
+ // see - would first show up on a user's device. It costs a
+ // second ABI in the APK and buys coverage of the only build
+ // that matters.
+ //
+ // This is why the APK is ~7.5 MB while the dex shrank: it
+ // carries two copies of libconscrypt_jni.so and libspake2.so,
+ // stored uncompressed and 16 KiB aligned for Android 15+ page
+ // sizes. Uncompressed native libraries inflate the download
+ // and shrink the installation, because they are mapped from
+ // the APK instead of being extracted. A single-ABI build is
+ // about 3.5 MB; splits would give users that without giving
+ // up the emulator coverage, and are the obvious next step if
+ // download size starts to matter.
ndk {
- abiFilters 'arm64-v8a'
+ abiFilters 'arm64-v8a', 'x86_64'
}
minifyEnabled true
- shrinkResources true
+ shrinkResources = true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
if (signingReady) {
- signingConfig signingConfigs.release
+ signingConfig = signingConfigs.release
}
}
}
@@ -86,20 +102,14 @@ android {
// 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/pqc/legacy/picnic/**',
'org/bouncycastle/x509/CertPathReviewerMessages*.properties',
- 'kotlin/**',
]
}
@@ -122,15 +132,8 @@ dependencies {
// we declare it explicitly here rather than patch the vendor tree.
implementation 'org.bouncycastle:bcprov-jdk15to18:1.84'
- // 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'
+ // Wireless pairing requires the public Conscrypt API and native provider.
+ implementation 'org.conscrypt:conscrypt-android:2.6.1'
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.json:json:20240303'
@@ -151,14 +154,16 @@ tasks.register('verifyScrcpyServer') {
}
def expected = expectedServerSum.get()
def version = serverVersion.text.trim()
- if (!(expected ==~ /[0-9a-f]{64}/) || version.isEmpty()) {
+ if (!(expected ==~ /[0-9a-f]{64}/)
+ || !(version ==~ /[0-9]+(\.[0-9]+)*/)) {
throw new GradleException('scrcpy server checksum or version is invalid')
}
def digest = MessageDigest.getInstance('SHA-256')
serverJar.withInputStream { input ->
byte[] buffer = new byte[64 * 1024]
for (int n; (n = input.read(buffer)) >= 0; ) {
- if (n > 0) digest.update(buffer, 0, n)
+ if (n == 0) throw new GradleException('scrcpy server read made no progress')
+ digest.update(buffer, 0, n)
}
}
def actual = digest.digest().encodeHex().toString()