📄 build.gradle

jabjab / build.gradle
10.4 kB Raw History
1buildscript {
2 repositories {
3 google()
4 mavenCentral()
5 }
6 dependencies {
7 classpath 'com.android.tools.build:gradle:9.2.1'
8 classpath 'com.diffplug.spotless:spotless-plugin-gradle:8.10.2'
9 }
10}
11
12apply plugin: 'com.android.application'
13apply plugin: 'com.diffplug.spotless'
14
15repositories {
16 google()
17 mavenCentral()
18 maven { url = 'https://jitpack.io' }
19}
20
21spotless {
22 ratchetFrom '2.17.4'
23 java {
24 target '**/*.java'
25 googleJavaFormat().aosp().reflowLongStrings()
26 }
27}
28
29def abiCodes = ['armeabi-v7a': 1, 'x86': 2, 'x86_64': 3, 'arm64-v8a': 4]
30
31configurations.named('implementation') {
32 exclude group: 'org.jetbrains', module: 'annotations'
33}
34
35configurations {
36 freeImplementation {}
37 conversationsPlaystoreImplementation {}
38 quicksyImplementation {}
39 quicksyPlaystoreImplementation {}
40}
41
42dependencies {
43 coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.5'
44
45 annotationProcessor 'org.immutables:value:2.12.2'
46 implementation 'org.immutables:value-annotations:2.12.2'
47 annotationProcessor project(':libs:annotation-processor')
48 implementation project(':libs:annotation')
49 implementation 'androidx.appcompat:appcompat:1.8.0'
50 implementation 'androidx.cardview:cardview:1.0.0'
51 implementation 'androidx.concurrent:concurrent-futures:1.3.0'
52 implementation 'androidx.documentfile:documentfile:1.1.0'
53 implementation 'androidx.emoji2:emoji2:1.6.0'
54 freeImplementation 'androidx.emoji2:emoji2-bundled:1.6.0'
55 implementation 'androidx.emoji2:emoji2-emojipicker:1.6.0'
56 implementation 'androidx.exifinterface:exifinterface:1.4.2'
57 implementation 'androidx.heifwriter:heifwriter:1.1.0'
58 implementation 'androidx.preference:preference:1.2.1'
59 implementation 'androidx.biometric:biometric:1.1.0'
60 implementation 'androidx.sharetarget:sharetarget:1.2.0'
61 implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.2.0'
62 implementation 'androidx.viewpager:viewpager:1.1.0'
63 implementation 'androidx.work:work-runtime:2.11.2'
64 implementation 'com.github.open-keychain.open-keychain:openpgp-api:v5.7.1'
65 implementation 'com.google.android.material:material:1.14.0'
66 implementation 'com.google.guava:guava:33.7.1-android'
67 implementation 'com.google.zxing:core:3.5.4'
68 implementation 'com.leinardi.android:speed-dial:3.3.0'
69 implementation 'com.squareup.okhttp3:okhttp:5.5.0'
70 implementation 'com.squareup.retrofit2:converter-gson:3.0.0'
71 implementation 'com.squareup.retrofit2:retrofit:3.0.0'
72 implementation 'com.vanniktech:android-image-cropper:4.7.0'
73 implementation 'im.conversations.webrtc:webrtc-android:149.0.0'
74 implementation 'io.deepmedia.community:transcoder-android:0.11.2'
75 implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
76 //noinspection NewerVersionAvailable
77 implementation 'net.fellbaum:jemoji:1.7.6' //1.7.6 is the latest with Java 8 support
78 implementation 'org.bouncycastle:bcmail-jdk18on:1.86'
79 implementation 'org.conscrypt:conscrypt-android:2.7.0'
80 implementation 'org.hsluv:hsluv:1.0.2'
81 implementation 'org.jxmpp:jxmpp-jid:1.1.0'
82 implementation 'org.jxmpp:jxmpp-stringprep-libidn:1.1.0'
83 implementation 'org.minidns:minidns-client:1.1.1'
84 implementation 'org.minidns:minidns-dnssec:1.1.1'
85 implementation 'org.osmdroid:osmdroid-android:6.1.20'
86 //noinspection NewerVersionAvailable
87 implementation 'org.whispersystems:signal-protocol-java:2.6.2'
88 conversationsPlaystoreImplementation 'com.android.installreferrer:installreferrer:2.2'
89 quicksyImplementation 'io.michaelrocks:libphonenumber-android:9.0.38'
90 quicksyPlaystoreImplementation 'com.google.android.gms:play-services-auth-api-phone:18.3.1'
91
92 testImplementation 'junit:junit:4.13.2'
93 testImplementation 'org.robolectric:robolectric:4.17'
94 androidTestImplementation 'androidx.test.ext:junit:1.3.0'
95}
96
97// Load local.properties so GIPHY_API_KEY etc. don't need to be passed on the command line
98def localProps = new Properties()
99def localPropsFile = rootProject.file('local.properties')
100if (localPropsFile.exists()) localProps.load(new FileInputStream(localPropsFile))
101
102android {
103 namespace = 'tel.xmpp.jabjab'
104 compileSdk = 37
105
106 defaultConfig {
107 minSdk = 23
108 versionCode = 42317
109 versionName = '1.0.8'
110 applicationId = 'tel.xmpp.jabjab'
111 resValue('string', 'applicationId', applicationId)
112 def appName = "JabJab"
113 resValue('string', 'app_name', appName)
114 buildConfigField('String', 'APP_NAME', "\"${appName}\"")
115 // GIF search — override with GIPHY_API_KEY (or its documented alias, TENOR_API_KEY)
116 // gradle property. Only GIPHY_API_KEY was ever actually wired here despite CLAUDE.md
117 // documenting TENOR_API_KEY as the primary name — a build using the documented flag
118 // silently got no key at all, leaving GIF search permanently in its "no API key" state.
119 def giphyKey = localProps.getProperty('GIPHY_API_KEY') ?: project.findProperty('GIPHY_API_KEY')
120 ?: localProps.getProperty('TENOR_API_KEY') ?: project.findProperty('TENOR_API_KEY') ?: ""
121 buildConfigField('String', 'GIPHY_API_KEY', "\"${giphyKey}\"")
122 def updateUrl = project.findProperty('UPDATE_SERVER_URL') ?: ""
123 buildConfigField('String', 'UPDATE_SERVER_URL', "\"${updateUrl}\"")
124 // Conversations upstream version — read from conversations.doap at build time
125 def conversationsVersion = "unknown"
126 def doapFile = file("conversations.doap")
127 if (doapFile.exists()) {
128 def m = doapFile.text =~ /<revision>([^<]+)<\/revision>/
129 if (m.find()) conversationsVersion = m.group(1).trim()
130 }
131 buildConfigField('String', 'CONVERSATIONS_BASE_VERSION', "\"${conversationsVersion}\"")
132 base {
133 archivesName = "jabjab-${android.defaultConfig.versionName}-${android.defaultConfig.versionCode}"
134 }
135 }
136
137 splits {
138 abi {
139 universalApk = true
140 enable = true
141 reset()
142 //noinspection ChromeOsAbiSupport
143 include(abiCodes.keySet() as String[])
144 }
145 }
146
147 compileOptions {
148 coreLibraryDesugaringEnabled = true
149 sourceCompatibility = JavaVersion.VERSION_21
150 targetCompatibility = JavaVersion.VERSION_21
151 }
152
153 flavorDimensions += 'mode'
154 flavorDimensions += 'distribution'
155
156 productFlavors {
157 quicksy {
158 dimension = 'mode'
159 applicationId = 'im.quicksy.client'
160 resValue('string', 'applicationId', applicationId)
161 def appName = "Quicksy"
162 resValue('string', 'app_name', appName)
163 buildConfigField('String', 'APP_NAME', "\"${appName}\"")
164 buildConfigField('String', 'PRIVACY_POLICY', '"https://quicksy.im/privacy.htm"')
165
166 def propsFile = rootProject.file('quicksy-auth-secret.properties')
167 def key = null
168 if (propsFile.exists()) {
169 def props = new Properties()
170 propsFile.withInputStream { props.load(it) }
171 key = props.getProperty('QUICKSY_AUTHENTICATION_SECRET')
172 }
173 buildConfigField('String', 'QUICKSY_AUTHENTICATION_SECRET', key != null ? "\"${key}\"" : 'null')
174 }
175
176 conversations {
177 dimension = 'mode'
178 buildConfigField('String', 'PRIVACY_POLICY', '"https://conversations.im/privacy.html"')
179 }
180
181 playstore {
182 dimension = 'distribution'
183 }
184 free {
185 dimension = 'distribution'
186 }
187 }
188
189 sourceSets {
190 quicksyFree {
191 java.srcDir('src/quicksyFree/java')
192 }
193 quicksyPlaystore {
194 java.srcDir('src/quicksyPlaystore/java')
195 res.srcDir('src/quicksyPlaystore/res')
196 }
197 conversationsFree {
198 java.srcDir('src/conversationsFree/java')
199 }
200 conversationsPlaystore {
201 java.srcDir('src/conversationsPlaystore/java')
202 res.srcDir('src/conversationsPlaystore/res')
203 }
204 }
205
206 def signingPropsFile = ["signing.properties",
207 "${System.getProperty('user.home')}/.keys/android/jabjab/signing.properties"]
208 .collect { new File(it) }
209 .find { it.exists() }
210
211 if (signingPropsFile != null) {
212 Properties props = new Properties()
213 props.load(new FileInputStream(signingPropsFile))
214
215 // Password is never stored in signing.properties — read from env var set by build-release.sh
216 def ksPassword = props['keystore.password'] ?: ""
217
218 signingConfigs {
219 release {
220 storeFile = file(props['keystore'])
221 storePassword = ksPassword
222 keyAlias = props['keystore.alias']
223 keyPassword = ksPassword
224 }
225 }
226 }
227
228 buildTypes {
229 release {
230 shrinkResources = true
231 minifyEnabled = true
232 proguardFiles(getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro')
233 if (signingPropsFile != null) {
234 signingConfig = signingConfigs.getByName('release')
235 }
236 }
237 debug {
238 if (signingPropsFile != null) {
239 signingConfig = signingConfigs.getByName('release')
240 }
241 }
242 }
243
244 packaging {
245 resources {
246 excludes += ['META-INF/BCKEY.DSA', 'META-INF/BCKEY.SF', 'META-INF/LICENSE.md',
247 'META-INF/versions/9/OSGI-INF/MANIFEST.MF']
248 }
249 }
250
251 lint {
252 disable += ['MissingTranslation', 'InvalidPackage', 'AppCompatResource']
253 }
254
255 buildFeatures {
256 buildConfig = true
257 resValues = true
258 dataBinding = true
259 aidl = true
260 }
261
262 dependenciesInfo {
263 includeInApk = false
264 includeInBundle = false
265 }
266}
267
268subprojects {
269 plugins.withId('com.android.library') {
270 android {
271 lint {
272 disable += ['AndroidGradlePluginVersion', 'MissingTranslation']
273 }
274 }
275 }
276 plugins.withId('com.android.application') {
277 android {
278 lint {
279 disable += ['AndroidGradlePluginVersion', 'MissingTranslation']
280 }
281 }
282 }
283}

Built with passion for open-source software, XMPP, privacy, and security —
the belief that people deserve communication tools that serve them, not surveil them.

Dedicated to every brave man and woman who stands up against tyranny and oppression across the world.
And in memory of those who were silenced before they could speak freely.