build.gradle 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. import org.jetbrains.kotlin.gradle.tasks.KaptGenerateStubs
  2. plugins {
  3. id 'org.sonarqube'
  4. id 'org.jetbrains.kotlin.plugin.serialization' version "$kotlin_version"
  5. }
  6. apply plugin: 'com.android.application'
  7. apply plugin: 'kotlin-android'
  8. apply plugin: 'kotlin-kapt'
  9. // only apply the plugin if we are dealing with a AppGallery build
  10. if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")) {
  11. println "enabling hms plugin"
  12. apply plugin: 'com.huawei.agconnect'
  13. }
  14. // version codes
  15. // Only use the scheme "<major>.<minor>.<patch>" for the app_version
  16. def app_version = "5.6.2"
  17. // beta_suffix with leading dash (e.g. `-beta1`)
  18. // should be one of (alpha|beta|rc) and an increasing number or empty for a regular release.
  19. // Note: in nightly builds this will be overwritten with a nightly version "-n12345"
  20. def beta_suffix = ""
  21. def defaultVersionCode = 1014
  22. /**
  23. * Return the git hash, if git is installed.
  24. */
  25. def getGitHash = { ->
  26. def stdout = new ByteArrayOutputStream()
  27. def stderr = new ByteArrayOutputStream()
  28. try {
  29. exec {
  30. commandLine 'git', 'rev-parse', '--short', 'HEAD'
  31. standardOutput = stdout
  32. errorOutput = stderr
  33. ignoreExitValue true
  34. }
  35. } catch (ignored) { /* If git binary is not found, carry on */ }
  36. def hash = stdout.toString().trim()
  37. return (hash.isEmpty()) ? "?" : hash
  38. }
  39. /**
  40. * Look up the keystore with the specified name in a `keystore` directory
  41. * adjacent to this project directory. If it exists, return a signing config.
  42. * Otherwise, return null.
  43. */
  44. def findKeystore = { name ->
  45. def basePath = "${projectDir.getAbsolutePath()}/../../keystore"
  46. def storePath = "${basePath}/${name}.keystore"
  47. def storeFile = new File(storePath)
  48. if (storeFile.exists() && storeFile.isFile()) {
  49. def propertiesPath = "${basePath}/${name}.properties"
  50. def propertiesFile = new File(propertiesPath)
  51. if (propertiesFile.exists() && propertiesFile.isFile()) {
  52. Properties props = new Properties()
  53. propertiesFile.withInputStream { props.load(it) }
  54. return [
  55. storeFile: storePath,
  56. storePassword: props.storePassword,
  57. keyAlias: props.keyAlias,
  58. keyPassword: props.keyPassword,
  59. ]
  60. } else {
  61. return [
  62. storeFile: storePath,
  63. storePassword: null,
  64. keyAlias: null,
  65. keyPassword: null,
  66. ]
  67. }
  68. }
  69. }
  70. /**
  71. * Map with keystore paths (if found).
  72. */
  73. def keystores = [
  74. debug: findKeystore("debug"),
  75. release: findKeystore("threema"),
  76. hms_release: findKeystore("threema_hms"),
  77. onprem_release: findKeystore("onprem"),
  78. blue_release: findKeystore("threema_blue"),
  79. ]
  80. android {
  81. // NOTE: When adjusting compileSdkVersion, buildToolsVersion or ndkVersion,
  82. // make sure to adjust them in `scripts/Dockerfile` and
  83. // `.gitlab-ci.yml` as well!
  84. compileSdk 34
  85. buildToolsVersion = '34.0.0'
  86. ndkVersion '25.2.9519653'
  87. defaultConfig {
  88. // https://developer.android.com/training/testing/espresso/setup#analytics
  89. testInstrumentationRunnerArguments notAnnotation: 'ch.threema.app.TestFastlaneOnly,ch.threema.app.DangerousTest', disableAnalytics: 'true'
  90. minSdkVersion 21
  91. //noinspection OldTargetApi
  92. targetSdkVersion 34
  93. vectorDrawables.useSupportLibrary = true
  94. applicationId "ch.threema.app"
  95. testApplicationId 'ch.threema.app.test'
  96. versionCode defaultVersionCode
  97. versionName "${app_version}${beta_suffix}"
  98. resValue "string", "app_name", "Threema"
  99. // package name used for sync adapter - needs to match mime types below
  100. resValue "string", "package_name", applicationId
  101. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.profile"
  102. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.call"
  103. buildConfigField "int", "MAX_GROUP_SIZE", "256"
  104. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"g-\""
  105. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.g-\""
  106. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.threema.ch\""
  107. buildConfigField "int[]", "CHAT_SERVER_PORTS", "{5222, 443}"
  108. buildConfigField "String", "MEDIA_PATH", "\"Threema\""
  109. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  110. buildConfigField "boolean", "DISABLE_CERT_PINNING", "false"
  111. buildConfigField "boolean", "VIDEO_CALLS_ENABLED", "true"
  112. buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x45, (byte) 0x0b, (byte) 0x97, (byte) 0x57, (byte) 0x35, (byte) 0x27, (byte) 0x9f, (byte) 0xde, (byte) 0xcb, (byte) 0x33, (byte) 0x13, (byte) 0x64, (byte) 0x8f, (byte) 0x5f, (byte) 0xc6, (byte) 0xee, (byte) 0x9f, (byte) 0xf4, (byte) 0x36, (byte) 0x0e, (byte) 0xa9, (byte) 0x2a, (byte) 0x8c, (byte) 0x17, (byte) 0x51, (byte) 0xc6, (byte) 0x61, (byte) 0xe4, (byte) 0xc0, (byte) 0xd8, (byte) 0xc9, (byte) 0x09 }"
  113. buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0xda, (byte) 0x7c, (byte) 0x73, (byte) 0x79, (byte) 0x8f, (byte) 0x97, (byte) 0xd5, (byte) 0x87, (byte) 0xc3, (byte) 0xa2, (byte) 0x5e, (byte) 0xbe, (byte) 0x0a, (byte) 0x91, (byte) 0x41, (byte) 0x7f, (byte) 0x76, (byte) 0xdb, (byte) 0xcc, (byte) 0xcd, (byte) 0xda, (byte) 0x29, (byte) 0x30, (byte) 0xe6, (byte) 0xa9, (byte) 0x09, (byte) 0x0a, (byte) 0xf6, (byte) 0x2e, (byte) 0xba, (byte) 0x6f, (byte) 0x15 }"
  114. buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
  115. buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.threema.ch/\""
  116. buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.threema.ch/\""
  117. buildConfigField "String", "WORK_SERVER_URL", "null"
  118. buildConfigField "String", "WORK_SERVER_IPV6_URL", "null"
  119. buildConfigField "String", "MEDIATOR_SERVER_URL", "\"wss://mediator-{deviceGroupIdPrefix4}.threema.ch/{deviceGroupIdPrefix8}\""
  120. buildConfigField "String", "BLOB_SERVER_DOWNLOAD_URL", "\"https://blobp-{blobIdPrefix}.threema.ch/{blobId}\""
  121. buildConfigField "String", "BLOB_SERVER_DOWNLOAD_IPV6_URL", "\"https://ds-blobp-{blobIdPrefix}.threema.ch/{blobId}\""
  122. buildConfigField "String", "BLOB_SERVER_DONE_URL", "\"https://blobp-{blobIdPrefix}.threema.ch/{blobId}/done\""
  123. buildConfigField "String", "BLOB_SERVER_DONE_IPV6_URL", "\"https://ds-blobp-{blobIdPrefix}.threema.ch/{blobId}/done\""
  124. buildConfigField "String", "BLOB_SERVER_UPLOAD_URL", "\"https://blobp-upload.threema.ch/upload\""
  125. buildConfigField "String", "BLOB_SERVER_UPLOAD_IPV6_URL", "\"https://ds-blobp-upload.threema.ch/upload\""
  126. buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.threema.ch/\""
  127. buildConfigField "String", "SAFE_SERVER_URL", "\"https://safe-{backupIdPrefix8}.threema.ch/\""
  128. buildConfigField "String", "WEB_SERVER_URL", "\"https://web.threema.ch/\""
  129. buildConfigField "String", "APP_RATING_URL", "\"https://threema.ch/app-rating/android/{rating}\""
  130. buildConfigField "byte[]", "THREEMA_PUSH_PUBLIC_KEY", "new byte[] {(byte) 0xfd, (byte) 0x71, (byte) 0x1e, (byte) 0x1a, (byte) 0x0d, (byte) 0xb0, (byte) 0xe2, (byte) 0xf0, (byte) 0x3f, (byte) 0xca, (byte) 0xab, (byte) 0x6c, (byte) 0x43, (byte) 0xda, (byte) 0x25, (byte) 0x75, (byte) 0xb9, (byte) 0x51, (byte) 0x36, (byte) 0x64, (byte) 0xa6, (byte) 0x2a, (byte) 0x12, (byte) 0xbd, (byte) 0x07, (byte) 0x28, (byte) 0xd8, (byte) 0x7f, (byte) 0x71, (byte) 0x25, (byte) 0xcc, (byte) 0x24}"
  131. buildConfigField "String", "ONPREM_ID_PREFIX", "\"O\""
  132. buildConfigField "String", "LOG_TAG", "\"3ma\""
  133. buildConfigField "String", "DEFAULT_APP_THEME", "\"2\""
  134. buildConfigField "String[]", "ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", "null"
  135. buildConfigField "boolean", "MD_ENABLED", "false"
  136. buildConfigField "boolean", "EDIT_MESSAGES_ENABLED", "true"
  137. buildConfigField "boolean", "DELETE_MESSAGES_ENABLED", "true"
  138. buildConfigField "boolean", "SHOW_TIMESTAMPS_AND_TECHNICAL_INFO_IN_MESSAGE_DETAILS", "false"
  139. // config fields for action URLs / deep links
  140. buildConfigField "String", "uriScheme", "\"threema\""
  141. buildConfigField "String", "actionUrl", "\"go.threema.ch\""
  142. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  143. buildConfigField "String", "groupLinkActionUrl", "\"threema.group\""
  144. // duplicated for manifest
  145. manifestPlaceholders = [
  146. uriScheme: "threema",
  147. contactActionUrl: "threema.id",
  148. groupLinkActionUrl: "threema.group",
  149. actionUrl: "go.threema.ch",
  150. callMimeType: "vnd.android.cursor.item/vnd.ch.threema.app.call",
  151. ]
  152. testInstrumentationRunner 'ch.threema.app.ThreemaTestRunner'
  153. // Only include language resources for those languages
  154. resourceConfigurations += [
  155. "en",
  156. "be-rBY",
  157. "ca",
  158. "cs",
  159. "de",
  160. "es",
  161. "fr",
  162. "gsw",
  163. "hu",
  164. "it",
  165. "ja",
  166. "nl-rNL",
  167. "no",
  168. "pl",
  169. "pt-rBR",
  170. "rm",
  171. "ru",
  172. "sk",
  173. "tr",
  174. "uk",
  175. "zh-rCN",
  176. "zh-rTW"
  177. ]
  178. }
  179. splits {
  180. abi {
  181. enable true
  182. reset()
  183. include 'armeabi-v7a', 'x86', 'arm64-v8a', 'x86_64'
  184. exclude 'armeabi', 'mips', 'mips64'
  185. universalApk project.hasProperty("buildUniversalApk")
  186. }
  187. }
  188. // Assign different version code for each output
  189. def abiVersionCodes = ['armeabi-v7a': 2, 'arm64-v8a': 3, 'x86': 8, 'x86_64': 9]
  190. android.applicationVariants.all { variant ->
  191. variant.outputs.each { output ->
  192. def abi = output.getFilter("ABI")
  193. output.versionCodeOverride =
  194. abiVersionCodes.get(abi, 0) * 1000000 + defaultVersionCode
  195. }
  196. }
  197. namespace 'ch.threema.app'
  198. flavorDimensions = ["default"]
  199. productFlavors {
  200. none { }
  201. store_google { }
  202. store_threema {
  203. resValue "string", "shop_download_filename", "Threema-update.apk"
  204. }
  205. store_google_work {
  206. versionName "${app_version}k${beta_suffix}"
  207. applicationId "ch.threema.app.work"
  208. testApplicationId 'ch.threema.app.work.test'
  209. resValue "string", "app_name", "Threema Work"
  210. resValue "string", "package_name", applicationId
  211. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
  212. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
  213. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  214. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
  215. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
  216. buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.threema.ch/\""
  217. buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.threema.ch/\""
  218. buildConfigField "String", "APP_RATING_URL", "\"https://threema.ch/app-rating/android-work/{rating}\""
  219. buildConfigField "String", "LOG_TAG", "\"3mawrk\""
  220. buildConfigField "String", "DEFAULT_APP_THEME", "\"2\""
  221. // config fields for action URLs / deep links
  222. buildConfigField "String", "uriScheme", "\"threemawork\""
  223. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  224. manifestPlaceholders = [
  225. uriScheme: "threemawork",
  226. actionUrl: "work.threema.ch",
  227. callMimeType: "vnd.android.cursor.item/vnd.ch.threema.app.work.call",
  228. ]
  229. }
  230. green {
  231. // The app was previously named `sandbox`. The app id remains unchanged to still be able to install updates.
  232. applicationId "ch.threema.app.sandbox"
  233. testApplicationId 'ch.threema.app.sandbox.test'
  234. resValue "string", "app_name", "Threema Green"
  235. resValue "string", "package_name", applicationId
  236. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.profile"
  237. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.call"
  238. buildConfigField "String", "MEDIA_PATH", "\"ThreemaGreen\""
  239. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  240. buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  241. buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  242. buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
  243. buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
  244. buildConfigField "String", "MEDIATOR_SERVER_URL", "\"wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}\""
  245. buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""
  246. buildConfigField "String", "APP_RATING_URL", "\"https://test.threema.ch/app-rating/android/{rating}\""
  247. buildConfigField "boolean", "MD_ENABLED", "true"
  248. }
  249. sandbox_work {
  250. versionName "${app_version}k${beta_suffix}"
  251. applicationId "ch.threema.app.sandbox.work"
  252. testApplicationId 'ch.threema.app.sandbox.work.test'
  253. resValue "string", "app_name", "Threema Sandbox Work"
  254. resValue "string", "package_name", applicationId
  255. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.profile"
  256. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.sandbox.work.call"
  257. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  258. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
  259. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  260. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWorkSandbox\""
  261. buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  262. buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  263. buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
  264. buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
  265. buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.test.threema.ch/\""
  266. buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.test.threema.ch/\""
  267. buildConfigField "String", "MEDIATOR_SERVER_URL", "\"wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}\""
  268. buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""
  269. buildConfigField "String", "APP_RATING_URL", "\"https://test.threema.ch/app-rating/android-work/{rating}\""
  270. buildConfigField "String", "LOG_TAG", "\"3mawrk\""
  271. buildConfigField "String", "DEFAULT_APP_THEME", "\"2\""
  272. // config fields for action URLs / deep links
  273. buildConfigField "String", "uriScheme", "\"threemawork\""
  274. buildConfigField "String", "actionUrl", "\"work.test.threema.ch\""
  275. buildConfigField "boolean", "MD_ENABLED", "true"
  276. manifestPlaceholders = [
  277. uriScheme : "threemawork",
  278. actionUrl : "work.test.threema.ch",
  279. ]
  280. }
  281. onprem {
  282. versionName "${app_version}o${beta_suffix}"
  283. applicationId "ch.threema.app.onprem"
  284. testApplicationId 'ch.threema.app.onprem.test'
  285. resValue "string", "app_name", "Threema OnPrem"
  286. resValue "string", "package_name", applicationId
  287. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.profile"
  288. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.onprem.call"
  289. buildConfigField "int", "MAX_GROUP_SIZE", "256"
  290. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"\""
  291. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"\""
  292. buildConfigField "String", "CHAT_SERVER_SUFFIX", "null"
  293. buildConfigField "String", "MEDIA_PATH", "\"ThreemaOnPrem\""
  294. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "false"
  295. buildConfigField "byte[]", "SERVER_PUBKEY", "null"
  296. buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "null"
  297. buildConfigField "String", "DIRECTORY_SERVER_URL", "null"
  298. buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "null"
  299. buildConfigField "String", "BLOB_SERVER_DOWNLOAD_URL", "null"
  300. buildConfigField "String", "BLOB_SERVER_DOWNLOAD_IPV6_URL", "null"
  301. buildConfigField "String", "BLOB_SERVER_DONE_URL", "null"
  302. buildConfigField "String", "BLOB_SERVER_DONE_IPV6_URL", "null"
  303. buildConfigField "String", "BLOB_SERVER_UPLOAD_URL", "null"
  304. buildConfigField "String", "BLOB_SERVER_UPLOAD_IPV6_URL", "null"
  305. buildConfigField "String[]", "ONPREM_CONFIG_TRUSTED_PUBLIC_KEYS", "new String[] {\"ek1qBp4DyRmLL9J5sCmsKSfwbsiGNB4veDAODjkwe/k=\", \"Hrk8aCjwKkXySubI7CZ3y9Sx+oToEHjNkGw98WSRneU=\", \"5pEn1T/5bhecNWrp9NgUQweRfgVtu/I8gRb3VxGP7k4=\"}"
  306. buildConfigField "String", "LOG_TAG", "\"3maop\""
  307. // config fields for action URLs / deep links
  308. buildConfigField "String", "uriScheme", "\"threemaonprem\""
  309. buildConfigField "String", "actionUrl", "\"onprem.threema.ch\""
  310. manifestPlaceholders = [
  311. uriScheme: "threemaonprem",
  312. actionUrl: "onprem.threema.ch",
  313. callMimeType: "vnd.android.cursor.item/vnd.ch.threema.app.onprem.call",
  314. ]
  315. }
  316. blue { // Essentially like sandbox work, but with a different icon and application id, used for internal testing
  317. versionName "${app_version}b${beta_suffix}"
  318. // The app was previously named `red`. The app id remains unchanged to still be able to install updates.
  319. applicationId "ch.threema.app.red"
  320. testApplicationId 'ch.threema.app.blue.test'
  321. resValue "string", "app_name", "Threema Blue"
  322. resValue "string", "package_name", applicationId
  323. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.blue.profile"
  324. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.blue.call"
  325. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  326. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
  327. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  328. buildConfigField "String", "MEDIA_PATH", "\"ThreemaBlue\""
  329. buildConfigField "byte[]", "SERVER_PUBKEY", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  330. buildConfigField "byte[]", "SERVER_PUBKEY_ALT", "new byte[] {(byte) 0x5a, (byte) 0x98, (byte) 0xf2, (byte) 0x3d, (byte) 0xe6, (byte) 0x56, (byte) 0x05, (byte) 0xd0, (byte) 0x50, (byte) 0xdc, (byte) 0x00, (byte) 0x64, (byte) 0xbe, (byte) 0x07, (byte) 0xdd, (byte) 0xdd, (byte) 0x81, (byte) 0x1d, (byte) 0xa1, (byte) 0x16, (byte) 0xa5, (byte) 0x43, (byte) 0xce, (byte) 0x43, (byte) 0xaa, (byte) 0x26, (byte) 0x87, (byte) 0xd1, (byte) 0x9f, (byte) 0x20, (byte) 0xaf, (byte) 0x3c }"
  331. buildConfigField "String", "DIRECTORY_SERVER_URL", "\"https://apip.test.threema.ch/\""
  332. buildConfigField "String", "DIRECTORY_SERVER_IPV6_URL", "\"https://ds-apip.test.threema.ch/\""
  333. buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.test.threema.ch/\""
  334. buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.test.threema.ch/\""
  335. buildConfigField "String", "MEDIATOR_SERVER_URL", "\"wss://mediator-{deviceGroupIdPrefix4}.test.threema.ch/{deviceGroupIdPrefix8}\""
  336. buildConfigField "String", "AVATAR_FETCH_URL", "\"https://avatar.test.threema.ch/\""
  337. buildConfigField "String", "APP_RATING_URL", "\"https://test.threema.ch/app-rating/android-work/{rating}\""
  338. buildConfigField "String", "LOG_TAG", "\"3mablue\""
  339. // config fields for action URLs / deep links
  340. buildConfigField "String", "uriScheme", "\"threemablue\""
  341. buildConfigField "String", "actionUrl", "\"blue.threema.ch\""
  342. manifestPlaceholders = [
  343. uriScheme: "threemablue",
  344. actionUrl: "blue.threema.ch",
  345. callMimeType: "vnd.android.cursor.item/vnd.ch.threema.app.blue.call",
  346. ]
  347. }
  348. hms {
  349. applicationId "ch.threema.app.hms"
  350. }
  351. hms_work {
  352. versionName "${app_version}k${beta_suffix}"
  353. applicationId "ch.threema.app.work.hms"
  354. testApplicationId 'ch.threema.app.work.test.hms'
  355. resValue "string", "app_name", "Threema Work"
  356. resValue "string", "package_name", "ch.threema.app.work"
  357. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
  358. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
  359. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  360. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.w-\""
  361. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
  362. buildConfigField "String", "WORK_SERVER_URL", "\"https://apip-work.threema.ch/\""
  363. buildConfigField "String", "WORK_SERVER_IPV6_URL", "\"https://ds-apip-work.threema.ch/\""
  364. buildConfigField "String", "APP_RATING_URL", "\"https://threema.ch/app-rating/android-work/{rating}\""
  365. buildConfigField "String", "LOG_TAG", "\"3mawrk\""
  366. buildConfigField "String", "DEFAULT_APP_THEME", "\"2\""
  367. // config fields for action URLs / deep links
  368. buildConfigField "String", "uriScheme", "\"threemawork\""
  369. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  370. manifestPlaceholders = [
  371. uriScheme: "threemawork",
  372. actionUrl: "work.threema.ch",
  373. callMimeType: "vnd.android.cursor.item/vnd.ch.threema.app.work.call",
  374. ]
  375. }
  376. libre {
  377. versionName "${app_version}l${beta_suffix}"
  378. applicationId "ch.threema.app.libre"
  379. testApplicationId 'ch.threema.app.libre.test'
  380. resValue "string", "package_name", applicationId
  381. resValue "string", "app_name", "Threema Libre"
  382. buildConfigField "String", "MEDIA_PATH", "\"ThreemaLibre\""
  383. }
  384. }
  385. signingConfigs {
  386. // Debug config
  387. if (keystores.debug != null) {
  388. debug {
  389. storeFile file(keystores.debug.storeFile)
  390. }
  391. } else {
  392. logger.warn("No debug keystore found. Falling back to locally generated keystore.")
  393. }
  394. // Release config
  395. if (keystores.release != null) {
  396. release {
  397. storeFile file(keystores.release.storeFile)
  398. storePassword keystores.release.storePassword
  399. keyAlias keystores.release.keyAlias
  400. keyPassword keystores.release.keyPassword
  401. }
  402. } else {
  403. logger.warn("No release keystore found. Falling back to locally generated keystore.")
  404. }
  405. // Release config
  406. if (keystores.hms_release != null) {
  407. hms_release {
  408. storeFile file(keystores.hms_release.storeFile)
  409. storePassword keystores.hms_release.storePassword
  410. keyAlias keystores.hms_release.keyAlias
  411. keyPassword keystores.hms_release.keyPassword
  412. }
  413. } else {
  414. logger.warn("No hms keystore found. Falling back to locally generated keystore.")
  415. }
  416. // Onprem release config
  417. if (keystores.onprem_release != null) {
  418. onprem_release {
  419. storeFile file(keystores.onprem_release.storeFile)
  420. storePassword keystores.onprem_release.storePassword
  421. keyAlias keystores.onprem_release.keyAlias
  422. keyPassword keystores.onprem_release.keyPassword
  423. }
  424. } else {
  425. logger.warn("No onprem keystore found. Falling back to locally generated keystore.")
  426. }
  427. // Blue release config
  428. if (keystores.blue_release != null) {
  429. blue_release {
  430. storeFile file(keystores.blue_release.storeFile)
  431. storePassword keystores.blue_release.storePassword
  432. keyAlias keystores.blue_release.keyAlias
  433. keyPassword keystores.blue_release.keyPassword
  434. }
  435. } else {
  436. logger.warn("No blue keystore found. Falling back to locally generated keystore.")
  437. }
  438. // Note: Libre release is signed with HSM, no config here
  439. }
  440. sourceSets {
  441. main {
  442. assets.srcDirs = ['assets']
  443. jniLibs.srcDirs = ['libs']
  444. }
  445. // Based on Google services
  446. none {
  447. java.srcDir 'src/google_services_based/java'
  448. }
  449. store_google {
  450. java.srcDir 'src/google_services_based/java'
  451. }
  452. store_google_work {
  453. java.srcDir 'src/google_services_based/java'
  454. }
  455. store_threema {
  456. java.srcDir 'src/google_services_based/java'
  457. }
  458. libre {
  459. assets.srcDirs = ['src/foss_based/assets']
  460. java.srcDir 'src/foss_based/java'
  461. }
  462. onprem {
  463. java.srcDir 'src/google_services_based/java'
  464. }
  465. green {
  466. java.srcDir 'src/google_services_based/java'
  467. manifest.srcFile 'src/store_google/AndroidManifest.xml'
  468. }
  469. sandbox_work {
  470. java.srcDir 'src/google_services_based/java'
  471. res.srcDir 'src/store_google_work/res'
  472. manifest.srcFile 'src/store_google_work/AndroidManifest.xml'
  473. }
  474. blue {
  475. java.srcDir 'src/google_services_based/java'
  476. res.srcDir 'src/blue/res'
  477. }
  478. // Based on Huawei services
  479. hms {
  480. java.srcDir 'src/hms_services_based/java'
  481. }
  482. hms_work {
  483. java.srcDir 'src/hms_services_based/java'
  484. res.srcDir 'src/store_google_work/res'
  485. }
  486. // FOSS, no proprietary services
  487. libre {
  488. assets.srcDirs = ['src/foss_based/assets']
  489. java.srcDir 'src/foss_based/java'
  490. }
  491. }
  492. buildTypes {
  493. debug {
  494. debuggable true
  495. jniDebuggable false
  496. ndk {
  497. debugSymbolLevel 'FULL'
  498. }
  499. enableUnitTestCoverage false
  500. enableAndroidTestCoverage false
  501. if (keystores['debug'] != null) {
  502. signingConfig signingConfigs.debug
  503. }
  504. }
  505. release {
  506. debuggable false
  507. jniDebuggable false
  508. minifyEnabled true
  509. shrinkResources false // Caused inconsistencies between local and CI builds
  510. vcsInfo.include false // For reproducible builds independent from git history
  511. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-project.txt'
  512. ndk {
  513. debugSymbolLevel 'FULL' // 'SYMBOL_TABLE'
  514. }
  515. if (keystores['release'] != null) {
  516. productFlavors.store_google.signingConfig signingConfigs.release
  517. productFlavors.store_google_work.signingConfig signingConfigs.release
  518. productFlavors.store_threema.signingConfig signingConfigs.release
  519. productFlavors.green.signingConfig signingConfigs.release
  520. productFlavors.sandbox_work.signingConfig signingConfigs.release
  521. productFlavors.none.signingConfig signingConfigs.release
  522. }
  523. if (keystores['hms_release'] != null) {
  524. productFlavors.hms.signingConfig signingConfigs.hms_release
  525. productFlavors.hms_work.signingConfig signingConfigs.hms_release
  526. }
  527. if (keystores['onprem_release'] != null) {
  528. productFlavors.onprem.signingConfig signingConfigs.onprem_release
  529. }
  530. if (keystores['blue_release'] != null) {
  531. productFlavors.blue.signingConfig signingConfigs.blue_release
  532. }
  533. // Note: Libre release is signed with HSM, no config here
  534. }
  535. }
  536. // Only build relevant buildType / flavor combinations
  537. variantFilter { variant ->
  538. def names = variant.flavors*.name
  539. if (
  540. variant.buildType.name == "release" && (
  541. names.contains("green") || names.contains("sandbox_work")
  542. )
  543. ) {
  544. setIgnore(true)
  545. }
  546. }
  547. externalNativeBuild {
  548. ndkBuild {
  549. path 'jni/Android.mk'
  550. }
  551. }
  552. packagingOptions {
  553. jniLibs {
  554. // replacement for extractNativeLibs in AndroidManifest
  555. useLegacyPackaging = true
  556. }
  557. resources {
  558. excludes += [
  559. 'META-INF/DEPENDENCIES.txt',
  560. 'META-INF/LICENSE.txt',
  561. 'META-INF/NOTICE.txt',
  562. 'META-INF/NOTICE',
  563. 'META-INF/LICENSE',
  564. 'META-INF/DEPENDENCIES',
  565. 'META-INF/notice.txt',
  566. 'META-INF/license.txt',
  567. 'META-INF/dependencies.txt',
  568. 'META-INF/LGPL2.1',
  569. '**/*.proto',
  570. 'DebugProbesKt.bin'
  571. ]
  572. }
  573. }
  574. testOptions {
  575. // Disable animations in instrumentation tests
  576. animationsDisabled true
  577. unitTests {
  578. all {
  579. // All the usual Gradle options.
  580. testLogging {
  581. events "passed", "skipped", "failed", "standardOut", "standardError"
  582. outputs.upToDateWhen { false }
  583. exceptionFormat = 'full'
  584. }
  585. jvmArgs = jvmArgs + ['--add-opens=java.base/java.util=ALL-UNNAMED']
  586. jvmArgs = jvmArgs + ['--add-opens=java.base/java.util.stream=ALL-UNNAMED']
  587. jvmArgs = jvmArgs + ['--add-opens=java.base/java.lang=ALL-UNNAMED']
  588. }
  589. // By default, local unit tests throw an exception any time the code you are testing tries to access
  590. // Android platform APIs (unless you mock Android dependencies yourself or with a testing
  591. // framework like Mockito). However, you can enable the following property so that the test
  592. // returns either null or zero when accessing platform APIs, rather than throwing an exception.
  593. returnDefaultValues true
  594. }
  595. }
  596. compileOptions {
  597. coreLibraryDesugaringEnabled true
  598. sourceCompatibility JavaVersion.VERSION_11
  599. targetCompatibility JavaVersion.VERSION_11
  600. }
  601. java {
  602. toolchain {
  603. languageVersion.set(JavaLanguageVersion.of(17))
  604. }
  605. }
  606. kotlin {
  607. jvmToolchain(17)
  608. }
  609. androidResources {
  610. noCompress 'png'
  611. }
  612. lint {
  613. // if true, stop the gradle build if errors are found
  614. abortOnError true
  615. // if true, check all issues, including those that are off by default
  616. checkAllWarnings true
  617. // check dependencies
  618. checkDependencies true
  619. // set to true to have all release builds run lint on issues with severity=fatal
  620. // and abort the build (controlled by abortOnError above) if fatal issues are found
  621. checkReleaseBuilds true
  622. // turn off checking the given issue id's
  623. disable 'TypographyFractions', 'TypographyQuotes', 'RtlHardcoded', 'RtlCompat', 'RtlEnabled'
  624. // Set the severity of the given issues to error
  625. error 'Wakelock', 'TextViewEdits', 'ResourceAsColor'
  626. // Set the severity of the given issues to fatal (which means they will be
  627. // checked during release builds (even if the lint target is not included)
  628. fatal 'NewApi', 'InlinedApi'
  629. // Set the severity of the given issues to ignore (same as disabling the check)
  630. ignore 'TypographyQuotes'
  631. ignoreWarnings false
  632. // if true, don't include source code lines in the error output
  633. noLines false
  634. // if true, show all locations for an error, do not truncate lists, etc.
  635. showAll true
  636. // Set the severity of the given issues to warning
  637. warning 'MissingTranslation'
  638. // if true, treat all warnings as errors
  639. warningsAsErrors false
  640. // file to write report to (if not specified, defaults to lint-results.xml)
  641. xmlOutput file('lint-report.xml')
  642. // if true, generate an XML report for use by for example Jenkins
  643. xmlReport true
  644. }
  645. buildFeatures {
  646. compose true
  647. buildConfig true
  648. }
  649. composeOptions {
  650. kotlinCompilerExtensionVersion = "1.5.7"
  651. }
  652. }
  653. dependencies {
  654. configurations.all {
  655. // Prefer modules that are part of this build (multi-project or composite build)
  656. // over external modules
  657. resolutionStrategy.preferProjectModules()
  658. // Alternatively, we can fail eagerly on version conflict to see the conflicts
  659. //resolutionStrategy.failOnVersionConflict()
  660. }
  661. coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'
  662. implementation project(':domain')
  663. implementation 'net.zetetic:sqlcipher-android:4.5.7@aar'
  664. implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
  665. implementation 'net.sf.opencsv:opencsv:2.3'
  666. implementation 'net.lingala.zip4j:zip4j:2.11.5'
  667. implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.3'
  668. // commons-io >2.6 requires android 8
  669. implementation 'commons-io:commons-io:2.6'
  670. implementation 'org.apache.commons:commons-text:1.10.0'
  671. implementation "org.slf4j:slf4j-api:$slf4j_version"
  672. implementation 'com.vanniktech:android-image-cropper:4.5.0'
  673. implementation 'com.datatheorem.android.trustkit:trustkit:1.1.5'
  674. implementation 'me.zhanghai.android.fastscroll:library:1.3.0'
  675. implementation 'com.googlecode.ez-vcard:ez-vcard:0.11.3'
  676. implementation 'com.alexvasilkov:gesture-views:2.8.3'
  677. // AndroidX / Jetpack support libraries
  678. implementation "androidx.preference:preference-ktx:1.2.1"
  679. implementation 'androidx.recyclerview:recyclerview:1.3.2'
  680. implementation 'androidx.palette:palette-ktx:1.0.0'
  681. implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0"
  682. implementation 'androidx.core:core-ktx:1.13.1'
  683. implementation 'androidx.appcompat:appcompat:1.7.0'
  684. implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
  685. implementation 'androidx.biometric:biometric:1.1.0'
  686. implementation 'androidx.work:work-runtime-ktx:2.9.0'
  687. implementation 'androidx.fragment:fragment-ktx:1.8.0'
  688. implementation 'androidx.activity:activity-ktx:1.9.0'
  689. implementation 'androidx.sqlite:sqlite:2.2.2'
  690. implementation "androidx.concurrent:concurrent-futures:1.2.0"
  691. implementation "androidx.camera:camera-camera2:1.3.4"
  692. implementation "androidx.camera:camera-lifecycle:1.3.4"
  693. implementation "androidx.camera:camera-view:1.3.4"
  694. implementation 'androidx.camera:camera-video:1.3.4'
  695. implementation "androidx.media:media:1.7.0"
  696. implementation 'androidx.media3:media3-exoplayer:1.3.1'
  697. implementation 'androidx.media3:media3-ui:1.3.1'
  698. implementation "androidx.media3:media3-session:1.3.1"
  699. implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.2"
  700. implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.2"
  701. implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.2"
  702. implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.8.2"
  703. implementation "androidx.lifecycle:lifecycle-service:2.8.2"
  704. implementation "androidx.lifecycle:lifecycle-process:2.8.2"
  705. implementation "androidx.lifecycle:lifecycle-common-java8:2.8.2"
  706. implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
  707. implementation "androidx.paging:paging-runtime-ktx:3.3.0"
  708. implementation "androidx.sharetarget:sharetarget:1.2.0"
  709. implementation 'androidx.room:room-runtime:2.6.1'
  710. implementation 'androidx.window:window:1.3.0'
  711. kapt 'androidx.room:room-compiler:2.6.1'
  712. // Jetpack Compose
  713. def composeBom = platform('androidx.compose:compose-bom:2024.06.00')
  714. implementation composeBom
  715. implementation 'androidx.compose.material3:material3'
  716. implementation 'androidx.compose.ui:ui-tooling-preview'
  717. implementation 'androidx.activity:activity-compose:1.9.0'
  718. implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.6'
  719. implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.6'
  720. debugImplementation 'androidx.compose.ui:ui-tooling'
  721. androidTestImplementation composeBom
  722. implementation 'org.bouncycastle:bcprov-jdk15to18:1.78.1'
  723. implementation 'com.google.android.material:material:1.12.0'
  724. implementation 'com.google.zxing:core:3.3.3' // zxing 3.4 crashes on API < 24
  725. implementation 'com.googlecode.libphonenumber:libphonenumber:8.13.39' // make sure to update this in domain's build.gradle as well
  726. // webclient dependencies
  727. implementation 'org.msgpack:msgpack-core:0.8.24!!'
  728. implementation 'com.fasterxml.jackson.core:jackson-core:2.12.5!!'
  729. implementation 'com.neovisionaries:nv-websocket-client:2.9'
  730. // Backport of Streams and CompletableFuture. Remove once API level 24 is supported.
  731. implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.4'
  732. implementation('org.saltyrtc:saltyrtc-client:0.14.2') {
  733. exclude group: 'org.json'
  734. }
  735. implementation 'org.saltyrtc:chunked-dc:1.0.1'
  736. implementation 'ch.threema:webrtc-android:123.0.0'
  737. implementation('org.saltyrtc:saltyrtc-task-webrtc:0.18.1') {
  738. exclude module: 'saltyrtc-client'
  739. }
  740. // Glide components
  741. // Glide 4.15+ does not work on API 21
  742. implementation 'com.github.bumptech.glide:glide:4.16.0'
  743. kapt 'com.github.bumptech.glide:compiler:4.16.0'
  744. annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
  745. // Kotlin
  746. implementation 'androidx.core:core-ktx:1.13.1'
  747. implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
  748. implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
  749. implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.1"
  750. testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
  751. androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
  752. // use leak canary in debug builds
  753. if (!project.hasProperty("noLeakCanary")) {
  754. debugImplementation('com.squareup.leakcanary:leakcanary-android:2.13')
  755. }
  756. // test dependencies
  757. testImplementation "junit:junit:$junit_version"
  758. testImplementation(testFixtures(project(":domain")))
  759. // custom test helpers, shared between unit test and android tests
  760. testImplementation(project(":test-helpers"))
  761. androidTestImplementation(project(":test-helpers"))
  762. // use powermock instead of mockito. it support mocking static classes.
  763. def mockitoVersion = '2.0.9'
  764. testImplementation "org.powermock:powermock-api-mockito2:${mockitoVersion}"
  765. testImplementation "org.powermock:powermock-module-junit4-rule-agent:${mockitoVersion}"
  766. testImplementation "org.powermock:powermock-module-junit4-rule:${mockitoVersion}"
  767. testImplementation "org.powermock:powermock-module-junit4:${mockitoVersion}"
  768. // add JSON support to tests without mocking
  769. testImplementation 'org.json:json:20220924'
  770. testImplementation 'com.tngtech.archunit:archunit-junit4:0.18.0'
  771. androidTestImplementation(testFixtures(project(":domain")))
  772. androidTestImplementation 'androidx.test:rules:1.6.0'
  773. androidTestImplementation 'tools.fastlane:screengrab:2.1.1', {
  774. exclude group: 'androidx.annotation', module: 'annotation'
  775. }
  776. androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0', {
  777. exclude group: 'androidx.annotation', module: 'annotation'
  778. }
  779. androidTestImplementation 'androidx.test:runner:1.4.0', {
  780. exclude group: 'androidx.annotation', module: 'annotation'
  781. }
  782. androidTestImplementation 'androidx.test.ext:junit-ktx:1.2.0'
  783. androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0', {
  784. exclude group: 'androidx.annotation', module: 'annotation'
  785. exclude group: 'androidx.appcompat', module: 'appcompat'
  786. exclude group: 'androidx.legacy', module: 'legacy-support-v4'
  787. exclude group: 'com.google.android.material', module: 'material'
  788. exclude group: 'androidx.recyclerview', module: 'recyclerview'
  789. exclude(group: 'org.checkerframework', module: 'checker')
  790. exclude module: "protobuf-lite"
  791. }
  792. androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0', {
  793. exclude group: 'androidx.annotation', module: 'annotation'
  794. }
  795. androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.3.0'
  796. androidTestImplementation 'androidx.test:core-ktx:1.6.0'
  797. androidTestImplementation "org.mockito:mockito-core:4.8.1"
  798. androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlin_coroutines_version"
  799. // Google Play Services and related libraries
  800. def googleDependencies = [
  801. // Play services
  802. 'com.google.android.gms:play-services-base:18.0.1': [],
  803. // Firebase push
  804. 'com.google.firebase:firebase-messaging:23.1.2': [
  805. [group: 'com.google.firebase', module: 'firebase-core'],
  806. [group: 'com.google.firebase', module: 'firebase-analytics'],
  807. [group: 'com.google.firebase', module: 'firebase-measurement-connector'],
  808. ],
  809. ]
  810. googleDependencies.each {
  811. def dependency = it.key
  812. def excludes = it.value
  813. noneImplementation(dependency) { excludes.each { exclude it } }
  814. store_googleImplementation(dependency) { excludes.each { exclude it } }
  815. store_google_workImplementation(dependency) { excludes.each { exclude it } }
  816. store_threemaImplementation(dependency) { excludes.each { exclude it } }
  817. onpremImplementation(dependency) { excludes.each { exclude it } }
  818. greenImplementation(dependency) { excludes.each { exclude it } }
  819. sandbox_workImplementation(dependency) { excludes.each { exclude it } }
  820. blueImplementation(dependency) { excludes.each { exclude it } }
  821. }
  822. // Google Assistant Voice Action verification library
  823. noneImplementation(name: 'libgsaverification-client', ext: 'aar')
  824. store_googleImplementation(name: 'libgsaverification-client', ext: 'aar')
  825. store_google_workImplementation(name: 'libgsaverification-client', ext: 'aar')
  826. onpremImplementation(name: 'libgsaverification-client', ext: 'aar')
  827. store_threemaImplementation(name: 'libgsaverification-client', ext: 'aar')
  828. greenImplementation(name: 'libgsaverification-client', ext: 'aar')
  829. sandbox_workImplementation(name: 'libgsaverification-client', ext: 'aar')
  830. blueImplementation(name: 'libgsaverification-client', ext: 'aar')
  831. // Maplibre (may have transitive dependencies on Google location services)
  832. def maplibreDependency = 'org.maplibre.gl:android-sdk:11.0.1'
  833. noneImplementation maplibreDependency
  834. store_googleImplementation maplibreDependency
  835. store_google_workImplementation maplibreDependency
  836. store_threemaImplementation maplibreDependency
  837. libreImplementation maplibreDependency, { exclude group: 'com.google.android.gms' }
  838. onpremImplementation maplibreDependency
  839. greenImplementation maplibreDependency
  840. sandbox_workImplementation maplibreDependency
  841. blueImplementation maplibreDependency
  842. hmsImplementation maplibreDependency
  843. hms_workImplementation maplibreDependency
  844. // Huawei related libraries (only for hms* build variants)
  845. def huaweiDependencies = [
  846. // HMS push
  847. 'com.huawei.hms:push:6.3.0.304': [
  848. // Exclude agconnect dependency, we'll replace it with the vendored version below
  849. [group: 'com.huawei.agconnect'],
  850. ],
  851. ]
  852. huaweiDependencies.each {
  853. def dependency = it.key
  854. def excludes = it.value
  855. hmsImplementation(dependency) { excludes.each { exclude it } }
  856. hms_workImplementation(dependency) { excludes.each { exclude it } }
  857. }
  858. hmsImplementation(name: 'agconnect-core-1.9.1.301', ext: 'aar')
  859. hms_workImplementation(name: 'agconnect-core-1.9.1.301', ext: 'aar')
  860. }
  861. tasks.withType(KaptGenerateStubs).configureEach {
  862. kotlinOptions {
  863. jvmTarget = JavaVersion.VERSION_11.toString()
  864. }
  865. }
  866. sonarqube {
  867. properties {
  868. property "sonar.sources", "src/main/, ../scripts/, ../scripts-internal/"
  869. property "sonar.exclusions", "src/main/java/ch/threema/localcrypto/**, src/test/java/ch/threema/localcrypto/**"
  870. property "sonar.tests", "src/test/"
  871. property "sonar.sourceEncoding", "UTF-8"
  872. property "sonar.verbose", "true"
  873. property 'sonar.projectKey', 'android-client'
  874. property 'sonar.projectName', 'Threema for Android'
  875. }
  876. }
  877. // Set up Gradle tasks to fetch screenshots on UI test failures
  878. // See https://medium.com/stepstone-tech/how-to-capture-screenshots-for-failed-ui-tests-9927eea6e1e4
  879. def reportsDirectory = "$buildDir/reports/androidTests/connected"
  880. def screenshotsDirectory = "/sdcard/testfailures/screenshots/"
  881. def clearScreenshotsTask = task('clearScreenshots', type: Exec) {
  882. executable "${android.getAdbExe().toString()}"
  883. args 'shell', 'rm', '-r', screenshotsDirectory
  884. }
  885. def createScreenshotsDirectoryTask = task('createScreenshotsDirectory', type: Exec, group: 'reporting') {
  886. executable "${android.getAdbExe().toString()}"
  887. args 'shell', 'mkdir', '-p', screenshotsDirectory
  888. }
  889. def fetchScreenshotsTask = task('fetchScreenshots', type: Exec, group: 'reporting') {
  890. executable "${android.getAdbExe().toString()}"
  891. args 'pull', screenshotsDirectory + '.', reportsDirectory
  892. finalizedBy {
  893. clearScreenshotsTask
  894. }
  895. dependsOn {
  896. createScreenshotsDirectoryTask
  897. }
  898. doFirst {
  899. new File(reportsDirectory).mkdirs()
  900. }
  901. }
  902. tasks.whenTaskAdded { task ->
  903. if (task.name == 'connectedDebugAndroidTest') {
  904. task.finalizedBy {
  905. fetchScreenshotsTask
  906. }
  907. }
  908. }