build.gradle 47 KB

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