build.gradle.kts 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095
  1. import com.android.build.gradle.internal.api.ApkVariantOutputImpl
  2. import com.android.build.gradle.internal.tasks.factory.dependsOn
  3. import config.BuildFeatureFlags
  4. import config.PublicKeys
  5. import config.setProductNames
  6. import org.gradle.api.tasks.testing.logging.TestExceptionFormat
  7. import org.gradle.kotlin.dsl.lintChecks
  8. import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
  9. import utils.*
  10. plugins {
  11. alias(libs.plugins.sonarqube)
  12. alias(libs.plugins.kotlin.serialization)
  13. alias(libs.plugins.rust.android)
  14. id("com.android.application")
  15. id("kotlin-android")
  16. alias(libs.plugins.ksp)
  17. alias(libs.plugins.compose.compiler)
  18. alias(libs.plugins.stem)
  19. }
  20. // only apply the plugin if we are dealing with an AppGallery build
  21. if (gradle.startParameter.taskRequests.toString().contains("Hms")) {
  22. logger.info("enabling hms plugin")
  23. apply {
  24. plugin("com.huawei.agconnect")
  25. }
  26. }
  27. /**
  28. * Only use the scheme "<major>.<minor>.<patch>" for the appVersion
  29. */
  30. val appVersion = "6.3.1"
  31. /**
  32. * betaSuffix with leading dash (e.g. `-beta1`).
  33. * Should be one of (alpha|beta|rc) and an increasing number, or empty for a regular release.
  34. * Note: in nightly builds this will be overwritten with a nightly version "-n12345"
  35. */
  36. val betaSuffix = ""
  37. val defaultVersionCode = 1116
  38. /**
  39. * Map with keystore paths (if found).
  40. */
  41. val keystores: Map<String, KeystoreConfig?> = mapOf(
  42. "debug" to findKeystore(projectDir, "debug"),
  43. "release" to findKeystore(projectDir, "threema"),
  44. "hms_release" to findKeystore(projectDir, "threema_hms"),
  45. "onprem_release" to findKeystore(projectDir, "onprem"),
  46. "blue_release" to findKeystore(projectDir, "threema_blue"),
  47. )
  48. android {
  49. // NOTE: When adjusting compileSdkVersion, buildToolsVersion or ndkVersion,
  50. // make sure to adjust them in `scripts/Dockerfile` as well!
  51. compileSdk = 35
  52. buildToolsVersion = "35.0.0"
  53. ndkVersion = "28.2.13676358"
  54. defaultConfig {
  55. // https://developer.android.com/training/testing/espresso/setup#analytics
  56. with(testInstrumentationRunnerArguments) {
  57. put("notAnnotation", "ch.threema.app.DangerousTest")
  58. put("disableAnalytics", "true")
  59. }
  60. minSdk = 24
  61. targetSdk = 35
  62. vectorDrawables.useSupportLibrary = true
  63. applicationId = "ch.threema.app"
  64. testApplicationId = "$applicationId.test"
  65. versionCode = defaultVersionCode
  66. versionName = "$appVersion$betaSuffix"
  67. setProductNames(
  68. appName = "Threema",
  69. )
  70. intBuildConfigField("DEFAULT_VERSION_CODE", defaultVersionCode)
  71. // package name used for sync adapter - needs to match mime types below
  72. stringResValue("package_name", applicationId!!)
  73. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
  74. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
  75. intBuildConfigField("MAX_GROUP_SIZE", 256)
  76. stringBuildConfigField("CHAT_SERVER_PREFIX", "g-")
  77. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.g-")
  78. stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.threema.ch")
  79. intArrayBuildConfigField("CHAT_SERVER_PORTS", intArrayOf(5222, 443))
  80. stringBuildConfigField("MEDIA_PATH", "Threema")
  81. booleanBuildConfigField("CHAT_SERVER_GROUPS", true)
  82. booleanBuildConfigField("DISABLE_CERT_PINNING", false)
  83. booleanBuildConfigField("VIDEO_CALLS_ENABLED", true)
  84. // This public key is pinned for the chat server protocol.
  85. byteArrayBuildConfigField("SERVER_PUBKEY", PublicKeys.prodServer)
  86. byteArrayBuildConfigField("SERVER_PUBKEY_ALT", PublicKeys.prodServerAlt)
  87. stringBuildConfigField("GIT_HASH", getGitHash())
  88. stringBuildConfigField("GIT_BRANCH", getGitBranch())
  89. stringBuildConfigField("DIRECTORY_SERVER_URL", "https://apip.threema.ch/")
  90. stringBuildConfigField("DIRECTORY_SERVER_IPV6_URL", "https://ds-apip.threema.ch/")
  91. stringBuildConfigField("WORK_SERVER_URL", null)
  92. stringBuildConfigField("WORK_SERVER_IPV6_URL", null)
  93. stringBuildConfigField("MEDIATOR_SERVER_URL", "wss://mediator-{deviceGroupIdPrefix4}.threema.ch/{deviceGroupIdPrefix8}")
  94. // Base blob url used for "download" and "done" calls
  95. stringBuildConfigField("BLOB_SERVER_URL", "https://blobp-{blobIdPrefix}.threema.ch")
  96. stringBuildConfigField("BLOB_SERVER_IPV6_URL", "https://ds-blobp-{blobIdPrefix}.threema.ch")
  97. // Specific blob url used for "upload" calls
  98. stringBuildConfigField("BLOB_SERVER_URL_UPLOAD", "https://blobp-upload.threema.ch/upload")
  99. stringBuildConfigField("BLOB_SERVER_IPV6_URL_UPLOAD", "https://ds-blobp-upload.threema.ch/upload")
  100. // Base blob mirror url used for "download", "upload", "done"
  101. stringBuildConfigField("BLOB_MIRROR_SERVER_URL", "https://blob-mirror-{deviceGroupIdPrefix4}.threema.ch/{deviceGroupIdPrefix8}")
  102. stringBuildConfigField("AVATAR_FETCH_URL", "https://avatar.threema.ch/")
  103. stringBuildConfigField("SAFE_SERVER_URL", "https://safe-{backupIdPrefix8}.threema.ch/")
  104. stringBuildConfigField("WEB_SERVER_URL", "https://web.threema.ch/")
  105. stringBuildConfigField("APP_RATING_URL", "https://threema.com/app-rating/android/{rating}")
  106. stringBuildConfigField("MAP_STYLES_URL", "https://map.threema.ch/styles/threema/style.json")
  107. stringBuildConfigField("MAP_POI_AROUND_URL", "https://poi.threema.ch/around/{latitude}/{longitude}/{radius}/")
  108. stringBuildConfigField("MAP_POI_NAMES_URL", "https://poi.threema.ch/names/{latitude}/{longitude}/{query}/")
  109. byteArrayBuildConfigField("THREEMA_PUSH_PUBLIC_KEY", PublicKeys.threemaPush)
  110. stringBuildConfigField("ONPREM_ID_PREFIX", "O")
  111. stringBuildConfigField("LOG_TAG", "3ma")
  112. stringBuildConfigField("DEFAULT_APP_THEME", "2")
  113. stringArrayBuildConfigField("ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", emptyArray())
  114. booleanBuildConfigField("MD_SYNC_DISTRIBUTION_LISTS", false)
  115. booleanBuildConfigField("AVAILABILITY_STATUS_ENABLED", BuildFeatureFlags["availability_status"] ?: false)
  116. booleanBuildConfigField("CRASH_REPORTING_SUPPORTED", BuildFeatureFlags["crash_reporting"] ?: false)
  117. // config fields for action URLs / deep links
  118. stringBuildConfigField("uriScheme", "threema")
  119. stringBuildConfigField("actionUrl", "go.threema.ch")
  120. stringBuildConfigField("contactActionUrl", "threema.id")
  121. // The OPPF url must be null in the default config. Do not change this.
  122. stringBuildConfigField("PRESET_OPPF_URL", null)
  123. with(manifestPlaceholders) {
  124. put("uriScheme", "threema")
  125. put("contactActionUrl", "threema.id")
  126. put("actionUrl", "go.threema.ch")
  127. put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
  128. }
  129. testInstrumentationRunner = "$applicationId.ThreemaTestRunner"
  130. // Only include language resources for those languages
  131. androidResources.localeFilters.addAll(
  132. setOf(
  133. "en",
  134. "be-rBY",
  135. "bg",
  136. "ca",
  137. "cs",
  138. "de",
  139. "es",
  140. "fr",
  141. "gsw",
  142. "hu",
  143. "it",
  144. "ja",
  145. "nl-rNL",
  146. "no",
  147. "pl",
  148. "pt-rBR",
  149. "ru",
  150. "sk",
  151. "tr",
  152. "uk",
  153. "zh-rCN",
  154. "zh-rTW",
  155. ),
  156. )
  157. }
  158. splits {
  159. abi {
  160. isEnable = true
  161. reset()
  162. if (project.hasProperty("noAbiSplits")) {
  163. isUniversalApk = true
  164. } else {
  165. include("armeabi-v7a", "x86", "arm64-v8a", "x86_64")
  166. isUniversalApk = project.hasProperty("buildUniversalApk")
  167. }
  168. }
  169. }
  170. // Assign different version code for each output
  171. android.applicationVariants.all {
  172. outputs.all {
  173. if (this is ApkVariantOutputImpl) {
  174. val abi = getFilter("ABI")
  175. val abiVersionCode = when (abi) {
  176. "armeabi-v7a" -> 2
  177. "arm64-v8a" -> 3
  178. "x86" -> 8
  179. "x86_64" -> 9
  180. else -> 0
  181. }
  182. versionCodeOverride = abiVersionCode * 1_000_000 + defaultVersionCode
  183. }
  184. }
  185. }
  186. namespace = "ch.threema.app"
  187. flavorDimensions.add("default")
  188. productFlavors {
  189. create("none")
  190. create("store_google")
  191. create("store_threema") {
  192. stringResValue("shop_download_filename", "Threema-update.apk")
  193. }
  194. create("store_google_work") {
  195. versionName = "${appVersion}k$betaSuffix"
  196. applicationId = "ch.threema.app.work"
  197. testApplicationId = "$applicationId.test"
  198. setProductNames(appName = "Threema Work")
  199. stringResValue("package_name", applicationId!!)
  200. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
  201. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
  202. stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
  203. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
  204. stringBuildConfigField("MEDIA_PATH", "ThreemaWork")
  205. stringBuildConfigField("WORK_SERVER_URL", "https://apip-work.threema.ch/")
  206. stringBuildConfigField("WORK_SERVER_IPV6_URL", "https://ds-apip-work.threema.ch/")
  207. stringBuildConfigField("APP_RATING_URL", "https://threema.com/app-rating/android-work/{rating}")
  208. stringBuildConfigField("LOG_TAG", "3mawrk")
  209. stringBuildConfigField("DEFAULT_APP_THEME", "2")
  210. // config fields for action URLs / deep links
  211. stringBuildConfigField("uriScheme", "threemawork")
  212. stringBuildConfigField("actionUrl", "work.threema.ch")
  213. with(manifestPlaceholders) {
  214. put("uriScheme", "threemawork")
  215. put("actionUrl", "work.threema.ch")
  216. put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
  217. }
  218. }
  219. create("green") {
  220. applicationId = "ch.threema.app.green"
  221. testApplicationId = "$applicationId.test"
  222. setProductNames(appName = "Threema Green")
  223. stringResValue("package_name", applicationId!!)
  224. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
  225. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
  226. stringBuildConfigField("MEDIA_PATH", "ThreemaGreen")
  227. stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.test.threema.ch")
  228. // This public key is pinned for the chat server protocol.
  229. byteArrayBuildConfigField("SERVER_PUBKEY", PublicKeys.sandboxServer)
  230. byteArrayBuildConfigField("SERVER_PUBKEY_ALT", PublicKeys.sandboxServer)
  231. stringBuildConfigField("DIRECTORY_SERVER_URL", "https://apip.test.threema.ch/")
  232. stringBuildConfigField("DIRECTORY_SERVER_IPV6_URL", "https://ds-apip.test.threema.ch/")
  233. stringBuildConfigField("MEDIATOR_SERVER_URL", "wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  234. stringBuildConfigField("BLOB_SERVER_URL", "https://blobp-{blobIdPrefix}.test.threema.ch")
  235. stringBuildConfigField("BLOB_SERVER_IPV6_URL", "https://ds-blobp-{blobIdPrefix}.test.threema.ch")
  236. stringBuildConfigField("BLOB_SERVER_URL_UPLOAD", "https://blobp-upload.test.threema.ch/upload")
  237. stringBuildConfigField("BLOB_SERVER_IPV6_URL_UPLOAD", "https://ds-blobp-upload.test.threema.ch/upload")
  238. stringBuildConfigField("AVATAR_FETCH_URL", "https://avatar.test.threema.ch/")
  239. stringBuildConfigField("APP_RATING_URL", "https://test.threema.com/app-rating/android/{rating}")
  240. stringBuildConfigField("MAP_STYLES_URL", "https://map.test.threema.ch/styles/threema/style.json")
  241. stringBuildConfigField("MAP_POI_AROUND_URL", "https://poi.test.threema.ch/around/{latitude}/{longitude}/{radius}/")
  242. stringBuildConfigField("MAP_POI_NAMES_URL", "https://poi.test.threema.ch/names/{latitude}/{longitude}/{query}/")
  243. stringBuildConfigField("BLOB_MIRROR_SERVER_URL", "https://blob-mirror-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  244. booleanBuildConfigField("CRASH_REPORTING_SUPPORTED", true)
  245. }
  246. create("sandbox_work") {
  247. versionName = "${appVersion}k$betaSuffix"
  248. applicationId = "ch.threema.app.sandbox.work"
  249. testApplicationId = "$applicationId.test"
  250. setProductNames(
  251. appName = "Threema Sandbox Work",
  252. appNameDesktop = "Threema Blue",
  253. )
  254. stringResValue("package_name", applicationId!!)
  255. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
  256. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
  257. stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
  258. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
  259. stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.test.threema.ch")
  260. stringBuildConfigField("MEDIA_PATH", "ThreemaWorkSandbox")
  261. // This public key is pinned for the chat server protocol.
  262. byteArrayBuildConfigField("SERVER_PUBKEY", PublicKeys.sandboxServer)
  263. byteArrayBuildConfigField("SERVER_PUBKEY_ALT", PublicKeys.sandboxServer)
  264. stringBuildConfigField("DIRECTORY_SERVER_URL", "https://apip.test.threema.ch/")
  265. stringBuildConfigField("DIRECTORY_SERVER_IPV6_URL", "https://ds-apip.test.threema.ch/")
  266. stringBuildConfigField("WORK_SERVER_URL", "https://apip-work.test.threema.ch/")
  267. stringBuildConfigField("WORK_SERVER_IPV6_URL", "https://ds-apip-work.test.threema.ch/")
  268. stringBuildConfigField("MEDIATOR_SERVER_URL", "wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  269. stringBuildConfigField("BLOB_SERVER_URL", "https://blobp-{blobIdPrefix}.test.threema.ch")
  270. stringBuildConfigField("BLOB_SERVER_IPV6_URL", "https://ds-blobp-{blobIdPrefix}.test.threema.ch")
  271. stringBuildConfigField("BLOB_SERVER_URL_UPLOAD", "https://blobp-upload.test.threema.ch/upload")
  272. stringBuildConfigField("BLOB_SERVER_IPV6_URL_UPLOAD", "https://ds-blobp-upload.test.threema.ch/upload")
  273. stringBuildConfigField("AVATAR_FETCH_URL", "https://avatar.test.threema.ch/")
  274. stringBuildConfigField("APP_RATING_URL", "https://test.threema.com/app-rating/android-work/{rating}")
  275. stringBuildConfigField("MAP_STYLES_URL", "https://map.test.threema.ch/styles/threema/style.json")
  276. stringBuildConfigField("MAP_POI_AROUND_URL", "https://poi.test.threema.ch/around/{latitude}/{longitude}/{radius}/")
  277. stringBuildConfigField("MAP_POI_NAMES_URL", "https://poi.test.threema.ch/names/{latitude}/{longitude}/{query}/")
  278. stringBuildConfigField("LOG_TAG", "3mawrk")
  279. stringBuildConfigField("DEFAULT_APP_THEME", "2")
  280. stringBuildConfigField("BLOB_MIRROR_SERVER_URL", "https://blob-mirror-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  281. // config fields for action URLs / deep links
  282. stringBuildConfigField("uriScheme", "threemawork")
  283. stringBuildConfigField("actionUrl", "work.test.threema.ch")
  284. booleanBuildConfigField("CRASH_REPORTING_SUPPORTED", true)
  285. stringBuildConfigField("MD_CLIENT_DOWNLOAD_URL", "https://three.ma/mdw")
  286. with(manifestPlaceholders) {
  287. put("uriScheme", "threemawork")
  288. put("actionUrl", "work.test.threema.ch")
  289. }
  290. }
  291. create("onprem") {
  292. versionName = "${appVersion}o$betaSuffix"
  293. applicationId = "ch.threema.app.onprem"
  294. testApplicationId = "$applicationId.test"
  295. setProductNames(
  296. appName = "Threema OnPrem",
  297. shortAppName = "Threema",
  298. companyName = "Threema",
  299. )
  300. stringResValue("package_name", applicationId!!)
  301. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.$applicationId.profile")
  302. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.$applicationId.call")
  303. intBuildConfigField("MAX_GROUP_SIZE", 256)
  304. stringBuildConfigField("CHAT_SERVER_PREFIX", "")
  305. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "")
  306. stringBuildConfigField("CHAT_SERVER_SUFFIX", null)
  307. stringBuildConfigField("MEDIA_PATH", "ThreemaOnPrem")
  308. booleanBuildConfigField("CHAT_SERVER_GROUPS", false)
  309. byteArrayBuildConfigField("SERVER_PUBKEY", null)
  310. byteArrayBuildConfigField("SERVER_PUBKEY_ALT", null)
  311. stringBuildConfigField("DIRECTORY_SERVER_URL", null)
  312. stringBuildConfigField("DIRECTORY_SERVER_IPV6_URL", null)
  313. stringBuildConfigField("BLOB_SERVER_URL", null)
  314. stringBuildConfigField("BLOB_SERVER_IPV6_URL", null)
  315. stringBuildConfigField("BLOB_SERVER_URL_UPLOAD", null)
  316. stringBuildConfigField("BLOB_SERVER_IPV6_URL_UPLOAD", null)
  317. stringBuildConfigField("BLOB_MIRROR_SERVER_URL", null)
  318. stringArrayBuildConfigField("ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", PublicKeys.onPremTrusted)
  319. stringBuildConfigField("LOG_TAG", "3maop")
  320. // config fields for action URLs / deep links
  321. val uriScheme = "threemaonprem"
  322. val actionUrl = "onprem.threema.ch"
  323. stringBuildConfigField("uriScheme", uriScheme)
  324. stringBuildConfigField("actionUrl", actionUrl)
  325. stringBuildConfigField("PRESET_OPPF_URL", null)
  326. stringBuildConfigField("MD_CLIENT_DOWNLOAD_URL", "https://three.ma/mdo")
  327. with(manifestPlaceholders) {
  328. put("uriScheme", uriScheme)
  329. put("actionUrl", actionUrl)
  330. put("callMimeType", "vnd.android.cursor.item/vnd.$applicationId.call")
  331. }
  332. }
  333. create("blue") {
  334. // Essentially like sandbox work, but with a different icon and application id, used for internal testing
  335. versionName = "${appVersion}b$betaSuffix"
  336. // The app was previously named `red`. The app id remains unchanged to still be able to install updates.
  337. applicationId = "ch.threema.app.red"
  338. testApplicationId = "ch.threema.app.blue.test"
  339. setProductNames(appName = "Threema Blue")
  340. stringResValue("package_name", applicationId!!)
  341. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.blue.profile")
  342. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.blue.call")
  343. stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
  344. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
  345. stringBuildConfigField("CHAT_SERVER_SUFFIX", ".0.test.threema.ch")
  346. stringBuildConfigField("MEDIA_PATH", "ThreemaBlue")
  347. // This public key is pinned for the chat server protocol.
  348. byteArrayBuildConfigField("SERVER_PUBKEY", PublicKeys.sandboxServer)
  349. byteArrayBuildConfigField("SERVER_PUBKEY_ALT", PublicKeys.sandboxServer)
  350. stringBuildConfigField("DIRECTORY_SERVER_URL", "https://apip.test.threema.ch/")
  351. stringBuildConfigField("DIRECTORY_SERVER_IPV6_URL", "https://ds-apip.test.threema.ch/")
  352. stringBuildConfigField("WORK_SERVER_URL", "https://apip-work.test.threema.ch/")
  353. stringBuildConfigField("WORK_SERVER_IPV6_URL", "https://ds-apip-work.test.threema.ch/")
  354. stringBuildConfigField("MEDIATOR_SERVER_URL", "wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  355. stringBuildConfigField("BLOB_SERVER_URL", "https://blobp-{blobIdPrefix}.test.threema.ch")
  356. stringBuildConfigField("BLOB_SERVER_IPV6_URL", "https://ds-blobp-{blobIdPrefix}.test.threema.ch")
  357. stringBuildConfigField("BLOB_SERVER_URL_UPLOAD", "https://blobp-upload.test.threema.ch/upload")
  358. stringBuildConfigField("BLOB_SERVER_IPV6_URL_UPLOAD", "https://ds-blobp-upload.test.threema.ch/upload")
  359. stringBuildConfigField("AVATAR_FETCH_URL", "https://avatar.test.threema.ch/")
  360. stringBuildConfigField("APP_RATING_URL", "https://test.threema.com/app-rating/android-work/{rating}")
  361. stringBuildConfigField("MAP_STYLES_URL", "https://map.test.threema.ch/styles/threema/style.json")
  362. stringBuildConfigField("MAP_POI_AROUND_URL", "https://poi.test.threema.ch/around/{latitude}/{longitude}/{radius}/")
  363. stringBuildConfigField("MAP_POI_NAMES_URL", "https://poi.test.threema.ch/names/{latitude}/{longitude}/{query}/")
  364. stringBuildConfigField("LOG_TAG", "3mablue")
  365. stringBuildConfigField("BLOB_MIRROR_SERVER_URL", "https://blob-mirror-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}")
  366. booleanBuildConfigField("CRASH_REPORTING_SUPPORTED", true)
  367. // config fields for action URLs / deep links
  368. stringBuildConfigField("uriScheme", "threemablue")
  369. stringBuildConfigField("actionUrl", "blue.threema.ch")
  370. with(manifestPlaceholders) {
  371. put("uriScheme", "threemablue")
  372. put("actionUrl", "blue.threema.ch")
  373. put("callMimeType", "vnd.android.cursor.item/vnd.ch.threema.app.blue.call")
  374. }
  375. }
  376. create("hms") {
  377. applicationId = "ch.threema.app.hms"
  378. }
  379. create("hms_work") {
  380. versionName = "${appVersion}k$betaSuffix"
  381. applicationId = "ch.threema.app.work.hms"
  382. testApplicationId = "ch.threema.app.work.test.hms"
  383. setProductNames(appName = "Threema Work")
  384. stringResValue("package_name", "ch.threema.app.work")
  385. stringResValue("contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile")
  386. stringResValue("call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call")
  387. stringBuildConfigField("CHAT_SERVER_PREFIX", "w-")
  388. stringBuildConfigField("CHAT_SERVER_IPV6_PREFIX", "ds.w-")
  389. stringBuildConfigField("MEDIA_PATH", "ThreemaWork")
  390. stringBuildConfigField("WORK_SERVER_URL", "https://apip-work.threema.ch/")
  391. stringBuildConfigField("WORK_SERVER_IPV6_URL", "https://ds-apip-work.threema.ch/")
  392. stringBuildConfigField("APP_RATING_URL", "https://threema.com/app-rating/android-work/{rating}")
  393. stringBuildConfigField("LOG_TAG", "3mawrk")
  394. stringBuildConfigField("DEFAULT_APP_THEME", "2")
  395. // config fields for action URLs / deep links
  396. stringBuildConfigField("uriScheme", "threemawork")
  397. stringBuildConfigField("actionUrl", "work.threema.ch")
  398. with(manifestPlaceholders) {
  399. put("uriScheme", "threemawork")
  400. put("actionUrl", "work.threema.ch")
  401. put("callMimeType", "vnd.android.cursor.item/vnd.ch.threema.app.work.call")
  402. }
  403. }
  404. create("libre") {
  405. versionName = "${appVersion}l$betaSuffix"
  406. applicationId = "ch.threema.app.libre"
  407. testApplicationId = "$applicationId.test"
  408. stringResValue("package_name", applicationId!!)
  409. setProductNames(
  410. appName = "Threema Libre",
  411. appNameDesktop = "Threema",
  412. )
  413. stringBuildConfigField("MEDIA_PATH", "ThreemaLibre")
  414. }
  415. }
  416. signingConfigs {
  417. // Debug config
  418. keystores["debug"]
  419. ?.let { keystore ->
  420. getByName("debug") {
  421. storeFile = keystore.storeFile
  422. }
  423. }
  424. ?: run {
  425. logger.warn("No debug keystore found. Falling back to locally generated keystore.")
  426. }
  427. // Release config
  428. keystores["release"]
  429. ?.let { keystore ->
  430. create("release") {
  431. apply(keystore)
  432. }
  433. }
  434. ?: run {
  435. logger.warn("No release keystore found. Falling back to locally generated keystore.")
  436. }
  437. // Release config
  438. keystores["hms_release"]
  439. ?.let { keystore ->
  440. create("hms_release") {
  441. apply(keystore)
  442. }
  443. }
  444. ?: run {
  445. logger.warn("No hms keystore found. Falling back to locally generated keystore.")
  446. }
  447. // Onprem release config
  448. keystores["onprem_release"]
  449. ?.let { keystore ->
  450. create("onprem_release") {
  451. apply(keystore)
  452. }
  453. }
  454. ?: run {
  455. logger.warn("No onprem keystore found. Falling back to locally generated keystore.")
  456. }
  457. // Blue release config
  458. keystores["blue_release"]
  459. ?.let { keystore ->
  460. create("blue_release") {
  461. apply(keystore)
  462. }
  463. }
  464. ?: run {
  465. logger.warn("No blue keystore found. Falling back to locally generated keystore.")
  466. }
  467. // Note: Libre release is signed with HSM, no config here
  468. }
  469. sourceSets {
  470. getByName("main") {
  471. assets.srcDirs("assets")
  472. jniLibs.srcDirs("libs")
  473. res.srcDir("src/main/res-rendezvous")
  474. java.srcDir("./build/generated/source/protobuf/main/java")
  475. java.srcDir("./build/generated/source/protobuf/main/kotlin")
  476. }
  477. // Based on Google services
  478. getByName("none") {
  479. java.srcDir("src/google_services_based/java")
  480. }
  481. getByName("store_google") {
  482. java.srcDir("src/google_services_based/java")
  483. }
  484. getByName("store_google_work") {
  485. java.srcDir("src/google_services_based/java")
  486. }
  487. getByName("store_threema") {
  488. java.srcDir("src/google_services_based/java")
  489. }
  490. getByName("libre") {
  491. assets.srcDirs("src/foss_based/assets")
  492. java.srcDir("src/foss_based/java")
  493. }
  494. getByName("onprem") {
  495. java.srcDir("src/google_services_based/java")
  496. }
  497. getByName("green") {
  498. java.srcDir("src/google_services_based/java")
  499. manifest.srcFile("src/store_google/AndroidManifest.xml")
  500. }
  501. getByName("sandbox_work") {
  502. java.srcDir("src/google_services_based/java")
  503. res.srcDir("src/store_google_work/res")
  504. manifest.srcFile("src/store_google_work/AndroidManifest.xml")
  505. }
  506. getByName("blue") {
  507. java.srcDir("src/google_services_based/java")
  508. res.srcDir("src/blue/res")
  509. }
  510. // Based on Huawei services
  511. getByName("hms") {
  512. java.srcDir("src/hms_services_based/java")
  513. }
  514. getByName("hms_work") {
  515. java.srcDir("src/hms_services_based/java")
  516. res.srcDir("src/store_google_work/res")
  517. }
  518. // FOSS, no proprietary services
  519. getByName("libre") {
  520. assets.srcDirs("src/foss_based/assets")
  521. java.srcDir("src/foss_based/java")
  522. }
  523. }
  524. buildTypes {
  525. debug {
  526. isDebuggable = true
  527. ndk {
  528. debugSymbolLevel = "FULL"
  529. }
  530. enableUnitTestCoverage = false
  531. enableAndroidTestCoverage = false
  532. if (keystores["debug"] != null) {
  533. signingConfig = signingConfigs["debug"]
  534. }
  535. }
  536. release {
  537. isDebuggable = false
  538. isMinifyEnabled = true
  539. isShrinkResources = false // Caused inconsistencies between local and CI builds
  540. vcsInfo.include = false // For reproducible builds independent from git history
  541. proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-project.txt")
  542. ndk {
  543. debugSymbolLevel = "FULL" // 'SYMBOL_TABLE'
  544. }
  545. if (keystores["release"] != null) {
  546. val releaseSigningConfig = signingConfigs["release"]
  547. productFlavors["store_google"].signingConfig = releaseSigningConfig
  548. productFlavors["store_google_work"].signingConfig = releaseSigningConfig
  549. productFlavors["store_threema"].signingConfig = releaseSigningConfig
  550. productFlavors["green"].signingConfig = releaseSigningConfig
  551. productFlavors["sandbox_work"].signingConfig = releaseSigningConfig
  552. productFlavors["none"].signingConfig = releaseSigningConfig
  553. }
  554. if (keystores["hms_release"] != null) {
  555. val hmsReleaseSigningConfig = signingConfigs["hms_release"]
  556. productFlavors["hms"].signingConfig = hmsReleaseSigningConfig
  557. productFlavors["hms_work"].signingConfig = hmsReleaseSigningConfig
  558. }
  559. if (keystores["onprem_release"] != null) {
  560. productFlavors["onprem"].signingConfig = signingConfigs["onprem_release"]
  561. }
  562. if (keystores["blue_release"] != null) {
  563. productFlavors["blue"].signingConfig = signingConfigs["blue_release"]
  564. }
  565. // Note: Libre release is signed with HSM, no config here
  566. }
  567. }
  568. packaging {
  569. jniLibs {
  570. // replacement for extractNativeLibs in AndroidManifest
  571. useLegacyPackaging = true
  572. }
  573. resources {
  574. excludes.addAll(
  575. setOf(
  576. "META-INF/DEPENDENCIES.txt",
  577. "META-INF/LICENSE.txt",
  578. "META-INF/LICENSE.md",
  579. "META-INF/LICENSE-notice.md",
  580. "META-INF/NOTICE.txt",
  581. "META-INF/NOTICE",
  582. "META-INF/LICENSE",
  583. "META-INF/DEPENDENCIES",
  584. "META-INF/notice.txt",
  585. "META-INF/license.txt",
  586. "META-INF/dependencies.txt",
  587. "META-INF/LGPL2.1",
  588. "**/*.proto",
  589. "DebugProbesKt.bin",
  590. ),
  591. )
  592. }
  593. }
  594. testOptions {
  595. // Disable animations in instrumentation tests
  596. animationsDisabled = true
  597. unitTests {
  598. all { test ->
  599. test.outputs.upToDateWhen { false }
  600. test.testLogging {
  601. events("passed", "skipped", "failed", "standardOut", "standardError")
  602. exceptionFormat = TestExceptionFormat.FULL
  603. }
  604. test.jvmArgs = test.jvmArgs!! + listOf(
  605. "--add-opens=java.base/java.util=ALL-UNNAMED",
  606. "--add-opens=java.base/java.util.stream=ALL-UNNAMED",
  607. "--add-opens=java.base/java.lang=ALL-UNNAMED",
  608. "-Xmx4096m",
  609. )
  610. }
  611. // By default, local unit tests throw an exception any time the code you are testing tries to access
  612. // Android platform APIs (unless you mock Android dependencies yourself or with a testing
  613. // framework like Mockk). However, you can enable the following property so that the test
  614. // returns either null or zero when accessing platform APIs, rather than throwing an exception.
  615. isReturnDefaultValues = true
  616. }
  617. }
  618. compileOptions {
  619. isCoreLibraryDesugaringEnabled = true
  620. sourceCompatibility = JavaVersion.VERSION_11
  621. targetCompatibility = JavaVersion.VERSION_11
  622. }
  623. java {
  624. toolchain {
  625. languageVersion.set(JavaLanguageVersion.of(17))
  626. }
  627. }
  628. kotlin {
  629. jvmToolchain(17)
  630. }
  631. androidResources {
  632. noCompress.add("png")
  633. }
  634. lint {
  635. // if true, stop the gradle build if errors are found
  636. abortOnError = true
  637. // if true, check all issues, including those that are off by default
  638. checkAllWarnings = true
  639. // check dependencies
  640. checkDependencies = true
  641. // set to true to have all release builds run lint on issues with severity=fatal
  642. // and abort the build (controlled by abortOnError above) if fatal issues are found
  643. checkReleaseBuilds = true
  644. // turn off checking the given issue id's
  645. disable.addAll(setOf("TypographyFractions", "TypographyQuotes", "RtlHardcoded", "RtlCompat", "RtlEnabled"))
  646. // Set the severity of the given issues to error
  647. error.addAll(setOf("Wakelock", "TextViewEdits", "ResourceAsColor"))
  648. // Set the severity of the given issues to fatal (which means they will be
  649. // checked during release builds (even if the lint target is not included)
  650. fatal.addAll(setOf("NewApi", "InlinedApi", "LoggerName"))
  651. ignoreWarnings = false
  652. // if true, don't include source code lines in the error output
  653. noLines = false
  654. // if true, show all locations for an error, do not truncate lists, etc.
  655. showAll = true
  656. // Set the severity of the given issues to warning
  657. warning.add("MissingTranslation")
  658. // if true, treat all warnings as errors
  659. warningsAsErrors = false
  660. // file to write report to (if not specified, defaults to lint-results.xml)
  661. xmlOutput = file("lint-report.xml")
  662. // if true, generate an XML report for use by for example Jenkins
  663. xmlReport = true
  664. }
  665. buildFeatures {
  666. compose = true
  667. buildConfig = true
  668. }
  669. }
  670. composeCompiler {
  671. includeSourceInformation = true
  672. stabilityConfigurationFiles.add(rootProject.layout.projectDirectory.file("stability_config.conf"))
  673. }
  674. // Only build relevant buildType / flavor combinations
  675. androidComponents {
  676. beforeVariants { variant ->
  677. val name = variant.name
  678. if (variant.buildType == "release" && ("green" in name || "sandbox_work" in name)) {
  679. variant.enable = false
  680. }
  681. }
  682. }
  683. dependencies {
  684. configurations.all {
  685. // Prefer modules that are part of this build (multi-project or composite build)
  686. // over external modules
  687. resolutionStrategy.preferProjectModules()
  688. // Alternatively, we can fail eagerly on version conflict to see the conflicts
  689. // resolutionStrategy.failOnVersionConflict()
  690. }
  691. coreLibraryDesugaring(libs.desugarJdkLibs)
  692. implementation(project(":domain"))
  693. implementation(project("::commonAndroid"))
  694. implementation(project(":common"))
  695. lintChecks(project(":lint-rules"))
  696. // Dependency Injection
  697. implementation(libs.koin.android)
  698. implementation(libs.koin.androidCompat)
  699. implementation(libs.koin.compose)
  700. testImplementation(libs.koin.test)
  701. testImplementation(libs.koin.test.junit4)
  702. implementation(libs.sqlcipher.android)
  703. implementation(libs.subsamplingScaleImageView)
  704. implementation(libs.opencsv)
  705. implementation(libs.zip4j)
  706. implementation(libs.taptargetview)
  707. implementation(libs.commonsIo)
  708. implementation(libs.slf4j.api)
  709. implementation(libs.androidImageCropper)
  710. implementation(libs.fastscroll)
  711. implementation(libs.ezVcard)
  712. implementation(libs.gestureViews)
  713. // AndroidX / Jetpack support libraries
  714. implementation(libs.androidx.preference)
  715. implementation(libs.androidx.recyclerview)
  716. implementation(libs.androidx.palette)
  717. implementation(libs.androidx.swiperefreshlayout)
  718. implementation(libs.androidx.core)
  719. implementation(libs.androidx.appcompat)
  720. implementation(libs.androidx.constraintlayout)
  721. implementation(libs.androidx.biometric)
  722. implementation(libs.androidx.work.runtime)
  723. implementation(libs.androidx.fragment)
  724. implementation(libs.androidx.activity)
  725. implementation(libs.androidx.sqlite)
  726. implementation(libs.androidx.concurrent.futures)
  727. implementation(libs.androidx.camera2)
  728. implementation(libs.androidx.camera.lifecycle)
  729. implementation(libs.androidx.camera.view)
  730. implementation(libs.androidx.camera.video)
  731. implementation(libs.androidx.media)
  732. implementation(libs.androidx.media3.exoplayer)
  733. implementation(libs.androidx.media3.ui)
  734. implementation(libs.androidx.media3.session)
  735. implementation(libs.androidx.lifecycle.viewmodel)
  736. implementation(libs.androidx.lifecycle.livedata)
  737. implementation(libs.androidx.lifecycle.runtime)
  738. implementation(libs.androidx.lifecycle.viewmodel.savedstate)
  739. implementation(libs.androidx.lifecycle.service)
  740. implementation(libs.androidx.lifecycle.process)
  741. implementation(libs.androidx.lifecycle.commonJava8)
  742. implementation(libs.androidx.lifecycle.extensions)
  743. implementation(libs.androidx.paging.runtime)
  744. implementation(libs.androidx.sharetarget)
  745. implementation(libs.androidx.room.runtime)
  746. implementation(libs.androidx.window)
  747. implementation(libs.androidx.splashscreen)
  748. ksp(libs.androidx.room.compiler)
  749. // Jetpack Compose
  750. implementation(platform(libs.compose.bom))
  751. implementation(libs.androidx.material3)
  752. implementation(libs.androidx.ui.tooling.preview)
  753. implementation(libs.androidx.activity.compose)
  754. implementation(libs.androidx.lifecycle.viewmodel.compose)
  755. implementation(libs.androidx.lifecycle.runtime.compose)
  756. debugImplementation(libs.androidx.ui.tooling)
  757. androidTestImplementation(platform(libs.compose.bom))
  758. implementation(libs.bcprov.jdk15to18)
  759. implementation(libs.material)
  760. implementation(libs.zxing)
  761. implementation(libs.libphonenumber)
  762. // webclient dependencies
  763. implementation(libs.msgpack.core)
  764. implementation(libs.jackson.core)
  765. implementation(libs.nvWebsocket.client)
  766. implementation(libs.streamsupport.cfuture)
  767. implementation(libs.saltyrtc.client) {
  768. exclude(group = "org.json")
  769. }
  770. implementation(libs.chunkedDc)
  771. implementation(libs.webrtcAndroid)
  772. implementation(libs.saltyrtc.taskWebrtc) {
  773. exclude(module = "saltyrtc-client")
  774. }
  775. // Glide components
  776. implementation(libs.glide)
  777. ksp(libs.glide.ksp)
  778. // Kotlin
  779. implementation(libs.kotlin.stdlib)
  780. implementation(libs.kotlinx.coroutines.android)
  781. implementation(libs.kotlinx.serialization.json)
  782. testImplementation(libs.kotlin.test)
  783. androidTestImplementation(libs.kotlin.test)
  784. // use leak canary in debug builds if requested
  785. if (project.hasProperty("leakCanary")) {
  786. debugImplementation(libs.leakcanary)
  787. }
  788. // test dependencies
  789. testImplementation(libs.junit)
  790. testImplementation(testFixtures(project(":domain")))
  791. // custom test helpers, shared between unit test and android tests
  792. testImplementation(project(":test-helpers"))
  793. androidTestImplementation(project(":test-helpers"))
  794. testImplementation(libs.mockk)
  795. androidTestImplementation(libs.mockkAndroid)
  796. // add JSON support to tests without mocking
  797. testImplementation(libs.json)
  798. testImplementation(libs.archunit.junit4)
  799. androidTestImplementation(testFixtures(project(":domain")))
  800. androidTestImplementation(libs.androidx.test.rules)
  801. androidTestImplementation(libs.fastlane.screengrab) {
  802. exclude(group = "androidx.annotation", module = "annotation")
  803. }
  804. androidTestImplementation(libs.androidx.espresso.core) {
  805. exclude(group = "androidx.annotation", module = "annotation")
  806. }
  807. androidTestImplementation(libs.androidx.test.runner) {
  808. exclude(group = "androidx.annotation", module = "annotation")
  809. }
  810. androidTestImplementation(libs.androidx.junit)
  811. androidTestImplementation(libs.androidx.espresso.contrib) {
  812. exclude(group = "androidx.annotation", module = "annotation")
  813. exclude(group = "androidx.appcompat", module = "appcompat")
  814. exclude(group = "androidx.legacy", module = "legacy-support-v4")
  815. exclude(group = "com.google.android.material", module = "material")
  816. exclude(group = "androidx.recyclerview", module = "recyclerview")
  817. exclude(group = "org.checkerframework", module = "checker")
  818. exclude(module = "protobuf-lite")
  819. }
  820. androidTestImplementation(libs.androidx.espresso.intents) {
  821. exclude(group = "androidx.annotation", module = "annotation")
  822. }
  823. androidTestImplementation(libs.androidx.test.uiautomator)
  824. androidTestImplementation(libs.androidx.test.core)
  825. androidTestImplementation(libs.kotlinx.coroutines.test)
  826. testImplementation(libs.kotlinx.coroutines.test)
  827. // Google Play Services and related libraries
  828. "noneImplementation"(libs.playServices.base)
  829. "store_googleImplementation"(libs.playServices.base)
  830. "store_google_workImplementation"(libs.playServices.base)
  831. "store_threemaImplementation"(libs.playServices.base)
  832. "onpremImplementation"(libs.playServices.base)
  833. "greenImplementation"(libs.playServices.base)
  834. "sandbox_workImplementation"(libs.playServices.base)
  835. "blueImplementation"(libs.playServices.base)
  836. fun ExternalModuleDependency.excludeFirebaseDependencies() {
  837. exclude(group = "com.google.firebase", module = "firebase-core")
  838. exclude(group = "com.google.firebase", module = "firebase-analytics")
  839. exclude(group = "com.google.firebase", module = "firebase-measurement-connector")
  840. }
  841. "noneImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  842. "store_googleImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  843. "store_google_workImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  844. "store_threemaImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  845. "onpremImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  846. "greenImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  847. "sandbox_workImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  848. "blueImplementation"(libs.firebase.messaging) { excludeFirebaseDependencies() }
  849. // Google Assistant Voice Action verification library
  850. "noneImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  851. "store_googleImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  852. "store_google_workImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  853. "onpremImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  854. "store_threemaImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  855. "greenImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  856. "sandbox_workImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  857. "blueImplementation"(group = "", name = "libgsaverification-client", ext = "aar")
  858. // Maplibre (may have transitive dependencies on Google location services)
  859. "noneImplementation"(libs.maplibre)
  860. "store_googleImplementation"(libs.maplibre)
  861. "store_google_workImplementation"(libs.maplibre)
  862. "store_threemaImplementation"(libs.maplibre)
  863. "libreImplementation"(libs.maplibre) {
  864. exclude(group = "com.google.android.gms")
  865. }
  866. "onpremImplementation"(libs.maplibre)
  867. "greenImplementation"(libs.maplibre)
  868. "sandbox_workImplementation"(libs.maplibre)
  869. "blueImplementation"(libs.maplibre)
  870. "hmsImplementation"(libs.maplibre)
  871. "hms_workImplementation"(libs.maplibre)
  872. // Huawei related libraries (only for hms* build variants)
  873. // Exclude agconnect dependency, we'll replace it with the vendored version below
  874. "hmsImplementation"(libs.hmsPush) {
  875. exclude(group = "com.huawei.agconnect")
  876. }
  877. "hms_workImplementation"(libs.hmsPush) {
  878. exclude(group = "com.huawei.agconnect")
  879. }
  880. "hmsImplementation"(group = "", name = "agconnect-core-1.9.1.301", ext = "aar")
  881. "hms_workImplementation"(group = "", name = "agconnect-core-1.9.1.301", ext = "aar")
  882. }
  883. // Define the cargo attributes. These will be used by the rust-android plugin that will create the
  884. // 'cargoBuild' task that builds native libraries that will be added to the apk. Note that the
  885. // kotlin bindings are created in the domain module. Building native libraries with rust-android
  886. // cannot be done in any other module than 'app'.
  887. cargo {
  888. prebuiltToolchains = true
  889. targetDirectory = "$projectDir/build/generated/source/libthreema"
  890. module = "$projectDir/../domain/libthreema" // must contain Cargo.toml
  891. libname = "libthreema" // must match the Cargo.toml's package name
  892. profile = "release"
  893. pythonCommand = "python3"
  894. targets = listOf("x86_64", "arm64", "arm", "x86")
  895. features {
  896. defaultAnd(arrayOf("uniffi"))
  897. }
  898. extraCargoBuildArguments = listOf("--lib", "--target-dir", "$projectDir/build/generated/source/libthreema", "--locked")
  899. verbose = false
  900. }
  901. afterEvaluate {
  902. // The `cargoBuild` task isn't available until after evaluation.
  903. android.applicationVariants.configureEach {
  904. val variantName = name.replaceFirstChar { it.uppercase() }
  905. // Set the dependency so that cargoBuild is executed before the native libs are merged
  906. tasks["merge${variantName}NativeLibs"].dependsOn(tasks["cargoBuild"])
  907. }
  908. }
  909. sonarqube {
  910. properties {
  911. property(
  912. "sonar.sources",
  913. listOf(
  914. "src/main/",
  915. "../scripts/",
  916. "../scripts-internal/",
  917. )
  918. .joinToString(separator = ", "),
  919. )
  920. property(
  921. "sonar.exclusions",
  922. listOf(
  923. "src/**/res/",
  924. "src/**/res-rendezvous/",
  925. "**/emojis/EmojiParser.kt",
  926. "**/emojis/EmojiSpritemap.kt",
  927. )
  928. .joinToString(separator = ", "),
  929. )
  930. property("sonar.tests", "src/test/")
  931. property("sonar.sourceEncoding", "UTF-8")
  932. property("sonar.verbose", "true")
  933. property("sonar.projectKey", "android-client")
  934. property("sonar.projectName", "Threema for Android")
  935. }
  936. }
  937. androidStem {
  938. includeLocalizedOnlyTemplates = true
  939. }
  940. tasks.register<Exec>("compileProto") {
  941. group = "build"
  942. description = "generate class bindings from protobuf files in the 'protobuf' directory"
  943. workingDir(project.projectDir)
  944. commandLine("./compile-proto.sh")
  945. }
  946. project.tasks.preBuild.dependsOn("compileProto")
  947. tasks.withType<Test> {
  948. // Necessary to load the dynamic libthreema library in unit tests
  949. systemProperty("jna.library.path", "${project.projectDir}/../domain/libthreema/target/release")
  950. }
  951. // Set up Gradle tasks to fetch screenshots on UI test failures
  952. // See https://medium.com/stepstone-tech/how-to-capture-screenshots-for-failed-ui-tests-9927eea6e1e4
  953. val reportsDirectory = "${layout.buildDirectory}/reports/androidTests/connected"
  954. val screenshotsDirectory = "/sdcard/testfailures/screenshots/"
  955. val clearScreenshotsTask = tasks.register<Exec>("clearScreenshots") {
  956. executable = android.adbExecutable.toString()
  957. args("shell", "rm", "-r", screenshotsDirectory)
  958. }
  959. val createScreenshotsDirectoryTask = tasks.register<Exec>("createScreenshotsDirectory") {
  960. group = "reporting"
  961. executable = android.adbExecutable.toString()
  962. args("shell", "mkdir", "-p", screenshotsDirectory)
  963. }
  964. val fetchScreenshotsTask = tasks.register<Exec>("fetchScreenshots") {
  965. group = "reporting"
  966. executable = android.adbExecutable.toString()
  967. args("pull", "$screenshotsDirectory.", reportsDirectory)
  968. finalizedBy(clearScreenshotsTask)
  969. dependsOn(createScreenshotsDirectoryTask)
  970. doFirst {
  971. file(reportsDirectory).mkdirs()
  972. }
  973. }
  974. tasks.whenTaskAdded {
  975. if (name == "connectedDebugAndroidTest") {
  976. finalizedBy(fetchScreenshotsTask)
  977. }
  978. }
  979. // Let the compose compiler generate stability reports
  980. tasks.withType<KotlinCompile>().configureEach {
  981. compilerOptions {
  982. val composeCompilerReportsPath = "${project.layout.buildDirectory.get().dir("compose_conpiler").asFile.absolutePath}/reports"
  983. freeCompilerArgs.addAll(
  984. listOf(
  985. "-P",
  986. "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=$composeCompilerReportsPath",
  987. ),
  988. )
  989. }
  990. }