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 // VERSION is the single semantic-version authority. versionCode remains16 // Android/Gradle metadata because Kepr's manifest does not carry it; the17 // updater enforces exact VERSION plus a strictly newer code.18 def versionAuthorityFile = rootProject.file("VERSION")19 if (!versionAuthorityFile.isFile()) {20 throw new GradleException("VERSION is missing; it is the semantic-version authority")21 }22 def semanticVersion = versionAuthorityFile.getText("UTF-8").trim()23 if (!(semanticVersion ==~ /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$/)) {24 throw new GradleException("VERSION must contain exactly one strict major.minor.patch value")25 }26 if (semanticVersion.split("\\.").any { it.toBigInteger() > Integer.MAX_VALUE }) {27 throw new GradleException("VERSION contains a semantic-version component outside Gradle's supported range")28 }2930 defaultConfig {31 applicationId "com.peachpasswords"32 minSdk 2633 targetSdk 3534 // Keep the Android code in Gradle; the semantic name comes from root VERSION.35 versionCode 24016536 versionName semanticVersion3738 testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"39 vectorDrawables {40 useSupportLibrary true41 }42 }4344 signingConfigs {45 release {46 // Read from local.properties (koh-ignored) so the keystore and its47 // password never enter version history. Absent on a machine without48 // the key -> release build stays unsigned rather than failing.49 def props = new Properties()50 def f = rootProject.file("local.properties")51 if (f.exists()) { f.withInputStream { props.load(it) } }52 if (props.getProperty("peachStoreFile")) {53 storeFile file(props.getProperty("peachStoreFile"))54 storePassword props.getProperty("peachStorePassword")55 keyAlias props.getProperty("peachKeyAlias")56 keyPassword props.getProperty("peachKeyPassword")57 }58 // v3 is the only escape hatch from "this key is forever": it carries a59 // rotation lineage, so a future key can be proven to descend from this60 // one instead of forcing every tester to uninstall and lose their61 // vault. AGP leaves it off unless asked.62 enableV2Signing true63 enableV3Signing true64 }65 }6667 splits {68 abi {69 enable true70 reset()71 include "arm64-v8a", "x86_64"72 universalApk false73 }74 }7576 buildTypes {77 debug {78 applicationIdSuffix ".debug"79 versionNameSuffix "-debug"80 debuggable true81 }82 release {83 signingConfig signingConfigs.release84 minifyEnabled false85 proguardFiles getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"86 }87 }8889 compileOptions {90 sourceCompatibility JavaVersion.VERSION_1791 targetCompatibility JavaVersion.VERSION_1792 }9394 kotlinOptions {95 jvmTarget = "17"96 }9798 buildFeatures {99 compose true100 buildConfig true101 }102103 composeOptions {104 kotlinCompilerExtensionVersion "1.5.15"105 }106107 packaging {108 resources {109 excludes += [110 "/META-INF/{AL2.0,LGPL2.1}",111 "META-INF/DEPENDENCIES",112 "META-INF/LICENSE*",113 "META-INF/NOTICE*",114 ]115 }116 }117118 testOptions {119 unitTests.returnDefaultValues = true120 unitTests.all {121 def coreDir = rootProject.file("../peach-browser/crypto-core")122 def nativeLibrary = new File(123 coreDir,124 "target/release/libpeach_noise_core.dylib",125 )126 if (coreDir.exists()) {127 dependsOn rootProject.tasks.named("buildRustNoiseHost")128 systemProperty "peach.noise.library.path", nativeLibrary.absolutePath129 }130 }131 }132}133134dependencies {135 implementation platform("androidx.compose:compose-bom:2024.06.00")136 androidTestImplementation platform("androidx.compose:compose-bom:2024.06.00")137138 implementation "androidx.activity:activity-compose:1.9.2"139 implementation "androidx.autofill:autofill:1.1.0"140 implementation "androidx.biometric:biometric:1.1.0"141 implementation "androidx.core:core-splashscreen:1.0.1"142 implementation "androidx.appcompat:appcompat:1.7.0"143 implementation "androidx.credentials:credentials:1.5.0"144 implementation "androidx.credentials:credentials-play-services-auth:1.5.0"145 implementation "androidx.glance:glance-appwidget:1.1.0"146 implementation "androidx.glance:glance-material3:1.1.0"147 implementation "androidx.hilt:hilt-navigation-compose:1.2.0"148 // In-app updates: a periodic release check that survives Doze without a149 // service. hilt-work lets the worker take UpdateRepository by injection150 // rather than reaching for a global.151 implementation "androidx.hilt:hilt-work:1.2.0"152 kapt "androidx.hilt:hilt-compiler:1.2.0"153 implementation "androidx.work:work-runtime-ktx:2.9.1"154 implementation "androidx.lifecycle:lifecycle-runtime-compose:2.8.4"155 implementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.8.4"156 implementation "androidx.lifecycle:lifecycle-process:2.8.4"157 implementation "androidx.navigation:navigation-compose:2.8.0"158 // Deliberately pinned to 1.1.0-alpha06 (audit M-12). 1.1.0 stable exists159 // now and GradleDependency lint flags this coordinate; a bump is a policy160 // choice (Tink runtime vs. baseline AES, master-key rotation semantics),161 // not an oversight, and is tracked separately. Exact alpha (never a floating162 // range) so the resolved artifact is reproducible. Used only for the163 // duress/license EncryptedSharedPreferences; the vault slots are sealed by164 // VaultCrypto, not this.165 implementation "androidx.security:security-crypto:1.1.0-alpha06"166 implementation "androidx.compose.material3:material3"167 implementation "androidx.compose.ui:ui"168 implementation "androidx.compose.ui:ui-tooling-preview"169 implementation "androidx.compose.foundation:foundation"170 implementation "androidx.compose.material:material-icons-extended"171 implementation "androidx.core:core-ktx:1.13.1"172 implementation "com.google.android.material:material:1.12.0"173174 implementation "com.google.dagger:hilt-android:2.51.1"175 kapt "com.google.dagger:hilt-compiler:2.51.1"176 implementation "com.google.zxing:core:3.5.3"177 implementation "androidx.camera:camera-core:1.3.4"178 implementation "androidx.camera:camera-camera2:1.3.4"179 implementation "androidx.camera:camera-lifecycle:1.3.4"180 implementation "androidx.camera:camera-view:1.3.4"181 implementation "com.squareup.okhttp3:okhttp:4.12.0"182 implementation "org.bouncycastle:bcprov-jdk18on:1.78.1"183 // zstd-jni (reference libzstd) — per-section compression for the PeachScript184 // PCHS binary format (MF-2). Required for cross-platform interop with the185 // browser's zstd sections. The @aar variant ships the Android jniLibs186 // (lib/<abi>/libzstd-jni.so); the plain jar bundles only desktop natives and187 // would fail with UnsatisfiedLinkError on-device.188 implementation "com.github.luben:zstd-jni:1.5.6-3@aar"189 // The @aar ships only Android .so; the plain jar carries the desktop natives190 // the host JVM unit tests need.191 testImplementation "com.github.luben:zstd-jni:1.5.6-3"192 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1"193 implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.1"194195 debugImplementation "androidx.compose.ui:ui-tooling"196 debugImplementation "androidx.compose.ui:ui-test-manifest"197198 androidTestImplementation "androidx.test.ext:junit:1.2.1"199 androidTestImplementation "androidx.test:core:1.6.1"200 androidTestImplementation "androidx.test.espresso:espresso-core:3.6.1"201 androidTestImplementation "androidx.compose.ui:ui-test-junit4"202203 testImplementation "junit:junit:4.13.2"204 // Real org.json on the unit-test classpath; android.jar's is a throwing stub,205 // so the release-manifest parser would otherwise be untestable off-device.206 testImplementation "org.json:json:20240303"207 testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.1"208}