1plugins {2 id "com.android.application"3 id "org.jetbrains.kotlin.android"4 id "org.jetbrains.kotlin.plugin.compose"5 id "org.jetbrains.kotlin.plugin.parcelize"6 id "org.jetbrains.kotlin.plugin.serialization"7 id "kotlin-kapt"8 id "com.google.dagger.hilt.android"9}1011android {12 namespace "com.peachpasswords"13 compileSdk 351415 defaultConfig {16 applicationId "com.peachpasswords"17 minSdk 2618 targetSdk 3519 // Canonical version source (audit M-13). Bump versionName and versionCode20 // here for a release. The root VERSION file and docs/NOISE-CORE-PROVENANCE.md21 // should be derived from these values rather than maintained independently;22 // the three sources drift otherwise.23 versionCode 24014524 versionName "2.8.3"2526 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"27 vectorDrawables {28 useSupportLibrary true29 }30 }3132 signingConfigs {33 release {34 // Read from local.properties (koh-ignored) so the keystore and its35 // password never enter version history. Absent on a machine without36 // the key -> release build stays unsigned rather than failing.37 def props = new Properties()38 def f = rootProject.file("local.properties")39 if (f.exists()) { f.withInputStream { props.load(it) } }40 if (props.getProperty("peachStoreFile")) {41 storeFile file(props.getProperty("peachStoreFile"))42 storePassword props.getProperty("peachStorePassword")43 keyAlias props.getProperty("peachKeyAlias")44 keyPassword props.getProperty("peachKeyPassword")45 }46 // v3 is the only escape hatch from "this key is forever": it carries a47 // rotation lineage, so a future key can be proven to descend from this48 // one instead of forcing every tester to uninstall and lose their49 // vault. AGP leaves it off unless asked.50 enableV2Signing true51 enableV3Signing true52 }53 }5455 // ABI splits were tried and removed: the native libraries are ~2.5 MB of a56 // 24 MB APK, so per-ABI builds saved 8% in exchange for four artifacts and57 // a "which one do I need?" question at every install. The weight is 62 MB of58 // DEX, because `minifyEnabled false` below leaves R8 off entirely — that is59 // the lever worth pulling, and it needs its own pass with real-device60 // verification (kotlinx.serialization, BouncyCastle, Hilt, Compose).6162 buildTypes {63 debug {64 applicationIdSuffix ".debug"65 versionNameSuffix "-debug"66 debuggable true67 }68 release {69 signingConfig signingConfigs.release70 minifyEnabled false71 proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"72 }73 }7475 compileOptions {76 sourceCompatibility JavaVersion.VERSION_1777 targetCompatibility JavaVersion.VERSION_1778 }7980 kotlinOptions {81 jvmTarget = "17"82 }8384 buildFeatures {85 compose true86 buildConfig true87 }8889 composeOptions {90 kotlinCompilerExtensionVersion "1.5.15"91 }9293 packaging {94 resources {95 excludes += [96 "/META-INF/{AL2.0,LGPL2.1}",97 "META-INF/DEPENDENCIES",98 "META-INF/LICENSE*",99 "META-INF/NOTICE*",100 ]101 }102 }103104 testOptions {105 unitTests.all {106 def coreDir = rootProject.file("../peach-browser/crypto-core")107 def nativeLibrary = new File(108 coreDir,109 "target/release/libpeach_noise_core.dylib",110 )111 if (coreDir.exists()) {112 dependsOn rootProject.tasks.named("buildRustNoiseHost")113 systemProperty "peach.noise.library.path", nativeLibrary.absolutePath114 }115 }116 }117}118119dependencies {120 implementation platform("androidx.compose:compose-bom:2024.06.00")121 androidTestImplementation platform("androidx.compose:compose-bom:2024.06.00")122123 implementation "androidx.activity:activity-compose:1.9.2"124 implementation "androidx.autofill:autofill:1.1.0"125 implementation "androidx.biometric:biometric:1.1.0"126 implementation "androidx.core:core-splashscreen:1.0.1"127 implementation "androidx.appcompat:appcompat:1.7.0"128 implementation "androidx.credentials:credentials:1.5.0"129 implementation "androidx.credentials:credentials-play-services-auth:1.5.0"130 implementation "androidx.glance:glance-appwidget:1.1.0"131 implementation "androidx.glance:glance-material3:1.1.0"132 implementation "androidx.hilt:hilt-navigation-compose:1.2.0"133 // In-app updates: a periodic release check that survives Doze without a134 // service. hilt-work lets the worker take UpdateRepository by injection135 // rather than reaching for a global.136 implementation "androidx.hilt:hilt-work:1.2.0"137 kapt "androidx.hilt:hilt-compiler:1.2.0"138 implementation "androidx.work:work-runtime-ktx:2.9.1"139 implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.4"140 implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4"141 implementation "androidx.lifecycle:lifecycle-process:2.8.4"142 implementation "androidx.navigation:navigation-compose:2.8.0"143 // Deliberately pinned to 1.1.0-alpha06 (audit M-12). 1.1.0 stable exists144 // now and GradleDependency lint flags this coordinate; a bump is a policy145 // choice (Tink runtime vs. baseline AES, master-key rotation semantics),146 // not an oversight, and is tracked separately. Exact alpha (never a floating147 // range) so the resolved artifact is reproducible. Used only for the148 // duress/license EncryptedSharedPreferences; the vault slots are sealed by149 // VaultCrypto, not this.150 implementation "androidx.security:security-crypto:1.1.0-alpha06"151 implementation "androidx.compose.material3:material3"152 implementation "androidx.compose.ui:ui"153 implementation "androidx.compose.ui:ui-tooling-preview"154 implementation "androidx.compose.foundation:foundation"155 implementation "androidx.compose.material:material-icons-extended"156 implementation "androidx.core:core-ktx:1.13.1"157 implementation "com.google.android.material:material:1.12.0"158159 implementation "com.google.dagger:hilt-android:2.51.1"160 kapt "com.google.dagger:hilt-compiler:2.51.1"161 implementation "com.google.zxing:core:3.5.3"162 implementation "androidx.camera:camera-core:1.3.4"163 implementation "androidx.camera:camera-camera2:1.3.4"164 implementation "androidx.camera:camera-lifecycle:1.3.4"165 implementation "androidx.camera:camera-view:1.3.4"166 implementation "com.squareup.okhttp3:okhttp:4.12.0"167 implementation "org.bouncycastle:bcprov-jdk18on:1.78.1"168 // zstd-jni (reference libzstd) — per-section compression for the PeachScript169 // PCHS binary format (MF-2). Required for cross-platform interop with the170 // browser's zstd sections. The @aar variant ships the Android jniLibs171 // (lib/<abi>/libzstd-jni.so); the plain jar bundles only desktop natives and172 // would fail with UnsatisfiedLinkError on-device.173 implementation "com.github.luben:zstd-jni:1.5.6-3@aar"174 // The @aar ships only Android .so; the plain jar carries the desktop natives175 // the host JVM unit tests need.176 testImplementation "com.github.luben:zstd-jni:1.5.6-3"177 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"178 implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1"179180 debugImplementation "androidx.compose.ui:ui-tooling"181 debugImplementation "androidx.compose.ui:ui-test-manifest"182183 androidTestImplementation "androidx.test.ext:junit:1.2.1"184 androidTestImplementation "androidx.test.espresso:espresso-core:3.6.1"185 androidTestImplementation "androidx.compose.ui:ui-test-junit4"186187 testImplementation "junit:junit:4.13.2"188 // Real org.json on the unit-test classpath; android.jar's is a throwing stub,189 // so the release-manifest parser would otherwise be untestable off-device.190 testImplementation "org.json:json:20240303"191 testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1"192}