build.gradle 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725
  1. plugins {
  2. id "org.sonarqube" version "3.0"
  3. }
  4. apply plugin: 'com.android.application'
  5. // only apply the plugin if we are dealing with a AppGallery build
  6. if (getGradle().getStartParameter().getTaskRequests().toString().contains("Hms")) {
  7. println "enabling hms plugin"
  8. apply plugin: 'com.huawei.agconnect'
  9. }
  10. // version codes
  11. def app_version = "4.56"
  12. def beta_suffix = ""
  13. /**
  14. * Return the git hash, if git is installed.
  15. */
  16. def getGitHash = { ->
  17. def stdout = new ByteArrayOutputStream()
  18. def stderr = new ByteArrayOutputStream()
  19. try {
  20. exec {
  21. commandLine 'git', 'rev-parse', '--short', 'HEAD'
  22. standardOutput = stdout
  23. errorOutput = stderr
  24. ignoreExitValue true
  25. }
  26. } catch (ignored) { /* If git binary is not found, carry on */ }
  27. def hash = stdout.toString().trim()
  28. return (hash.isEmpty()) ? "?" : hash
  29. }
  30. /**
  31. * Look up the keystore with the specified name in a `keystore` directory
  32. * adjacent to this project directory. If it exists, return a signing config.
  33. * Otherwise, return null.
  34. */
  35. def findKeystore = { name ->
  36. def basePath = "${projectDir.getAbsolutePath()}/../../keystore"
  37. def storePath = "${basePath}/${name}.keystore"
  38. def storeFile = new File(storePath)
  39. if (storeFile.exists() && storeFile.isFile()) {
  40. def propertiesPath = "${basePath}/${name}.properties"
  41. def propertiesFile = new File(propertiesPath)
  42. if (propertiesFile.exists() && propertiesFile.isFile()) {
  43. Properties props = new Properties()
  44. propertiesFile.withInputStream { props.load(it) }
  45. return [
  46. storeFile: storePath,
  47. storePassword: props.storePassword,
  48. keyAlias: props.keyAlias,
  49. keyPassword: props.keyPassword,
  50. ]
  51. } else {
  52. return [
  53. storeFile: storePath,
  54. storePassword: null,
  55. keyAlias: null,
  56. keyPassword: null,
  57. ]
  58. }
  59. }
  60. }
  61. /**
  62. * Map with keystore paths (if found).
  63. */
  64. def keystores = [
  65. debug: findKeystore("debug"),
  66. release: findKeystore("threema"),
  67. hms_release: findKeystore("threema_hms"),
  68. ]
  69. android {
  70. // NOTE: When adjusting compileSdkVersion or buildToolsVersion,
  71. // make sure to adjust them in `scripts/Dockerfile` as well!
  72. compileSdkVersion 29
  73. buildToolsVersion '29.0.3'
  74. defaultConfig {
  75. minSdkVersion 19
  76. //noinspection OldTargetApi
  77. targetSdkVersion 29
  78. vectorDrawables.useSupportLibrary = true
  79. applicationId "ch.threema.app"
  80. testApplicationId 'ch.threema.app.test'
  81. versionCode 688
  82. versionName "${app_version}${beta_suffix}"
  83. resValue "string", "app_name", "Threema"
  84. // package name used for sync adapter
  85. resValue "string", "package_name", applicationId
  86. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.profile"
  87. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.call"
  88. resValue "integer", "max_group_size", "256"
  89. resValue "string", "shop_download_filename", "Threema-update.apk"
  90. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"g-\""
  91. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.\""
  92. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.threema.ch\""
  93. buildConfigField "String", "MEDIA_PATH", "\"Threema\""
  94. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  95. buildConfigField "boolean", "DISABLE_CERT_PINNING", "false"
  96. buildConfigField "boolean", "VIDEO_CALLS_ENABLED", "true"
  97. 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 }"
  98. 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 }"
  99. buildConfigField "String", "GIT_HASH", "\"${getGitHash()}\""
  100. buildConfigField "boolean", "SEND_CONSUMED_DELIVERY_RECEIPTS", "false"
  101. // config fields for action URLs / deep links
  102. buildConfigField "String", "uriScheme", "\"threema\""
  103. buildConfigField "String", "actionUrl", "\"go.threema.ch\""
  104. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  105. // duplicated for manifest
  106. manifestPlaceholders = [
  107. uriScheme: "threema",
  108. actionUrl: "go.threema.ch",
  109. contactActionUrl: "threema.id"
  110. ]
  111. ndk {
  112. abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
  113. }
  114. testInstrumentationRunner 'ch.threema.app.ThreemaTestRunner'
  115. testInstrumentationRunnerArgument 'notAnnotation', 'ch.threema.app.TestFastlaneOnly,ch.threema.app.DangerousTest'
  116. testInstrumentationRunnerArgument 'disableAnalytics', 'true' // https://developer.android.com/training/testing/espresso/setup#analytics
  117. }
  118. splits {
  119. abi {
  120. enable true
  121. reset()
  122. include 'armeabi-v7a', 'x86', "arm64-v8a", "x86_64"
  123. exclude 'armeabi', 'mips', 'mips64'
  124. universalApk true
  125. }
  126. }
  127. // Assign different version code for each output
  128. project.ext.versionCodes = ['armeabi': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'mips': 5, 'mips64': 6, 'x86': 8, 'x86_64': 9]
  129. android.applicationVariants.all { variant ->
  130. variant.outputs.each { output ->
  131. output.versionCodeOverride =
  132. project.ext.versionCodes.get(output.getFilter(com.android.build.OutputFile.ABI), 0) * 1000000 + android.defaultConfig.versionCode
  133. }
  134. }
  135. flavorDimensions "default"
  136. productFlavors {
  137. none { }
  138. store_google {
  139. resValue "string", "shop_download_filename", ""
  140. }
  141. store_threema { }
  142. store_google_work {
  143. versionName "${app_version}k${beta_suffix}"
  144. applicationId "ch.threema.app.work"
  145. testApplicationId 'ch.threema.app.work.test'
  146. resValue "string", "package_name", applicationId
  147. resValue "string", "app_name", "Threema Work"
  148. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
  149. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
  150. resValue "integer", "max_group_size", "256"
  151. resValue "string", "shop_download_filename", ""
  152. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  153. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.\""
  154. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.threema.ch\""
  155. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
  156. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  157. // config fields for action URLs / deep links
  158. buildConfigField "String", "uriScheme", "\"threemawork\""
  159. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  160. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  161. manifestPlaceholders = [
  162. uriScheme: "threemawork",
  163. actionUrl: "work.threema.ch",
  164. contactActionUrl: "threema.id"
  165. ]
  166. }
  167. sandbox {
  168. applicationId "ch.threema.app.sandbox"
  169. testApplicationId 'ch.threema.app.sandbox.test'
  170. resValue "string", "package_name", applicationId
  171. resValue "string", "app_name", "Threema Sandbox"
  172. buildConfigField "String", "MEDIA_PATH", "\"ThreemaSandbox\""
  173. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  174. 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 }"
  175. 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 }"
  176. }
  177. sandbox_work {
  178. versionName "${app_version}k${beta_suffix}"
  179. applicationId "ch.threema.app.sandbox.work"
  180. testApplicationId 'ch.threema.app.sandbox.work.test'
  181. resValue "string", "package_name", applicationId
  182. resValue "string", "app_name", "Threema Sandbox Work"
  183. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
  184. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
  185. resValue "integer", "max_group_size", "256"
  186. resValue "string", "shop_download_filename", ""
  187. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  188. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.\""
  189. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWorkSandbox\""
  190. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  191. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  192. 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 }"
  193. 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 }"
  194. // config fields for action URLs / deep links
  195. buildConfigField "String", "uriScheme", "\"threemawork\""
  196. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  197. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  198. manifestPlaceholders = [
  199. uriScheme: "threemawork",
  200. actionUrl: "work.threema.ch",
  201. contactActionUrl: "threema.id"
  202. ]
  203. }
  204. red { // Essentially like sandbox work, but with a different icon and accent color, used for internal testing
  205. versionName "${app_version}r${beta_suffix}"
  206. applicationId "ch.threema.app.red"
  207. testApplicationId 'ch.threema.app.red.test'
  208. resValue "string", "package_name", applicationId
  209. resValue "string", "app_name", "Threema Red"
  210. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.redwork.profile"
  211. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.redwork.call"
  212. resValue "integer", "max_group_size", "256"
  213. resValue "string", "shop_download_filename", ""
  214. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  215. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.\""
  216. buildConfigField "String", "MEDIA_PATH", "\"ThreemaRed\""
  217. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  218. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.test.threema.ch\""
  219. 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 }"
  220. 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 }"
  221. buildConfigField "boolean", "SEND_CONSUMED_DELIVERY_RECEIPTS", "true"
  222. // config fields for action URLs / deep links
  223. buildConfigField "String", "uriScheme", "\"threemawork\""
  224. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  225. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  226. manifestPlaceholders = [
  227. uriScheme: "threemawork",
  228. actionUrl: "work.threema.ch",
  229. contactActionUrl: "threema.id"
  230. ]
  231. }
  232. hms {
  233. applicationId "ch.threema.app.hms"
  234. resValue "string", "package_name", applicationId
  235. }
  236. hms_work {
  237. versionName "${app_version}k${beta_suffix}"
  238. applicationId "ch.threema.app.work.hms"
  239. testApplicationId 'ch.threema.app.work.test.hms'
  240. resValue "string", "package_name", applicationId
  241. resValue "string", "app_name", "Threema Work"
  242. resValue "string", "contacts_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.profile"
  243. resValue "string", "call_mime_type", "vnd.android.cursor.item/vnd.ch.threema.app.work.call"
  244. resValue "integer", "max_group_size", "256"
  245. resValue "string", "shop_download_filename", ""
  246. buildConfigField "String", "CHAT_SERVER_PREFIX", "\"w-\""
  247. buildConfigField "String", "CHAT_SERVER_IPV6_PREFIX", "\"ds.\""
  248. buildConfigField "String", "CHAT_SERVER_SUFFIX", "\".0.threema.ch\""
  249. buildConfigField "String", "MEDIA_PATH", "\"ThreemaWork\""
  250. buildConfigField "boolean", "CHAT_SERVER_GROUPS", "true"
  251. // config fields for action URLs / deep links
  252. buildConfigField "String", "uriScheme", "\"threemawork\""
  253. buildConfigField "String", "actionUrl", "\"work.threema.ch\""
  254. buildConfigField "String", "contactActionUrl", "\"threema.id\""
  255. manifestPlaceholders = [
  256. uriScheme: "threemawork",
  257. actionUrl: "work.threema.ch",
  258. contactActionUrl: "threema.id"
  259. ]
  260. }
  261. }
  262. signingConfigs {
  263. // Debug config
  264. if (keystores.debug != null) {
  265. debug {
  266. storeFile file(keystores.debug.storeFile)
  267. }
  268. } else {
  269. logger.warn("No debug keystore found. Falling back to locally generated keystore.")
  270. }
  271. // Release config
  272. if (keystores.release != null) {
  273. release {
  274. storeFile file(keystores.release.storeFile)
  275. storePassword keystores.release.storePassword
  276. keyAlias keystores.release.keyAlias
  277. keyPassword keystores.release.keyPassword
  278. }
  279. } else {
  280. logger.warn("No release keystore found. Falling back to locally generated keystore.")
  281. }
  282. // Release config
  283. if (keystores.hms_release != null) {
  284. hms_release {
  285. storeFile file(keystores.hms_release.storeFile)
  286. storePassword keystores.hms_release.storePassword
  287. keyAlias keystores.hms_release.keyAlias
  288. keyPassword keystores.hms_release.keyPassword
  289. }
  290. } else {
  291. logger.warn("No hms keystore found. Falling back to locally generated keystore.")
  292. }
  293. }
  294. sourceSets {
  295. none {
  296. java.srcDir 'src/google_services_based/java'
  297. manifest.srcFile 'src/store_google/AndroidManifest.xml'
  298. }
  299. main {
  300. assets.srcDirs = ['assets']
  301. jniLibs.srcDirs = ['libs']
  302. }
  303. store_google {
  304. java.srcDir 'src/google_services_based/java'
  305. }
  306. store_google_work {
  307. java.srcDir 'src/google_services_based/java'
  308. }
  309. store_threema {
  310. java.srcDir 'src/google_services_based/java'
  311. }
  312. hms {
  313. java.srcDir 'src/hms_services_based/java'
  314. }
  315. hms_work {
  316. java.srcDir 'src/hms_services_based/java'
  317. res.srcDir 'src/store_google_work/res'
  318. }
  319. sandbox {
  320. java.srcDir 'src/google_services_based/java'
  321. manifest.srcFile 'src/store_google/AndroidManifest.xml'
  322. }
  323. sandbox_work {
  324. java.srcDirs = ['src/store_google_work/java', 'src/google_services_based/java']
  325. res.srcDir 'src/store_google_work/res'
  326. manifest.srcFile 'src/store_google_work/AndroidManifest.xml'
  327. }
  328. red {
  329. java.srcDir 'src/google_services_based/java'
  330. res.srcDir 'src/red/res'
  331. }
  332. }
  333. buildTypes {
  334. debug {
  335. debuggable true
  336. jniDebuggable false
  337. multiDexEnabled true
  338. multiDexKeepProguard file('multidex-keep.pro')
  339. if (keystores['debug'] != null) {
  340. signingConfig signingConfigs.debug
  341. }
  342. }
  343. release {
  344. debuggable false
  345. jniDebuggable false
  346. minifyEnabled true
  347. shrinkResources false // Caused inconsistencies between local and CI builds
  348. zipAlignEnabled true
  349. multiDexEnabled true
  350. multiDexKeepProguard file('multidex-keep.pro')
  351. proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-project.txt'
  352. if (keystores['release'] != null) {
  353. productFlavors.store_google.signingConfig signingConfigs.release
  354. productFlavors.store_google_work.signingConfig signingConfigs.release
  355. productFlavors.store_threema.signingConfig signingConfigs.release
  356. productFlavors.red.signingConfig signingConfigs.release
  357. productFlavors.sandbox.signingConfig signingConfigs.release
  358. productFlavors.sandbox_work.signingConfig signingConfigs.release
  359. productFlavors.none.signingConfig signingConfigs.release
  360. }
  361. if (keystores['hms_release'] != null) {
  362. productFlavors.hms.signingConfig signingConfigs.hms_release
  363. productFlavors.hms_work.signingConfig signingConfigs.hms_release
  364. }
  365. }
  366. }
  367. externalNativeBuild {
  368. ndkBuild {
  369. path 'jni/Android.mk'
  370. }
  371. }
  372. lintOptions {
  373. // set to true to have all release builds run lint on issues with severity=fatal
  374. // and abort the build (controlled by abortOnError above) if fatal issues are found
  375. checkReleaseBuilds true
  376. // set to true to turn off analysis progress reporting by lint
  377. // quiet true
  378. // if true, stop the gradle build if errors are found
  379. abortOnError true
  380. // if true, only report errors
  381. ignoreWarnings false
  382. // if true, emit full/absolute paths to files with errors (true by default)
  383. //absolutePaths true
  384. // if true, check all issues, including those that are off by default
  385. checkAllWarnings true
  386. // if true, treat all warnings as errors
  387. warningsAsErrors false
  388. // turn off checking the given issue id's
  389. disable 'TypographyFractions', 'TypographyQuotes'
  390. // turn on the given issue id's
  391. disable 'RtlHardcoded', 'RtlCompat', 'RtlEnabled'
  392. // check *only* the given issue id's
  393. // check 'NewApi', 'InlinedApi'
  394. // if true, don't include source code lines in the error output
  395. noLines false
  396. // if true, show all locations for an error, do not truncate lists, etc.
  397. showAll true
  398. // if true, generate an XML report for use by for example Jenkins
  399. xmlReport true
  400. // file to write report to (if not specified, defaults to lint-results.xml)
  401. xmlOutput file("lint-report.xml")
  402. // Set the severity of the given issues to fatal (which means they will be
  403. // checked during release builds (even if the lint target is not included)
  404. fatal 'NewApi', 'InlinedApi'
  405. // Set the severity of the given issues to error
  406. error 'Wakelock', 'TextViewEdits', 'ResourceAsColor'
  407. // Set the severity of the given issues to warning
  408. warning 'MissingTranslation'
  409. // Set the severity of the given issues to ignore (same as disabling the check)
  410. ignore 'TypographyQuotes'
  411. }
  412. packagingOptions {
  413. exclude 'META-INF/DEPENDENCIES.txt'
  414. exclude 'META-INF/LICENSE.txt'
  415. exclude 'META-INF/NOTICE.txt'
  416. exclude 'META-INF/NOTICE'
  417. exclude 'META-INF/LICENSE'
  418. exclude 'META-INF/DEPENDENCIES'
  419. exclude 'META-INF/notice.txt'
  420. exclude 'META-INF/license.txt'
  421. exclude 'META-INF/dependencies.txt'
  422. exclude 'META-INF/LGPL2.1'
  423. // fix https://stackoverflow.com/questions/42739916/aarch64-linux-android-strip-file-missing
  424. doNotStrip '*/mips/*.so'
  425. doNotStrip '*/mips64/*.so'
  426. doNotStrip '*/armeabi/*.so'
  427. }
  428. testOptions {
  429. // Disable animations in instrumentation tests
  430. animationsDisabled true
  431. unitTests {
  432. all {
  433. // All the usual Gradle options.
  434. testLogging {
  435. events "passed", "skipped", "failed", "standardOut", "standardError"
  436. outputs.upToDateWhen { false }
  437. exceptionFormat = 'full'
  438. }
  439. }
  440. // By default, local unit tests throw an exception any time the code you are testing tries to access
  441. // Android platform APIs (unless you mock Android dependencies yourself or with a testing
  442. // framework like Mockito). However, you can enable the following property so that the test
  443. // returns either null or zero when accessing platform APIs, rather than throwing an exception.
  444. returnDefaultValues true
  445. }
  446. }
  447. compileOptions {
  448. targetCompatibility 1.8
  449. sourceCompatibility 1.8
  450. }
  451. aaptOptions {
  452. noCompress 'png'
  453. }
  454. }
  455. dependencies {
  456. configurations.all {
  457. // Prefer modules that are part of this build (multi-project or composite build)
  458. // over external modules
  459. resolutionStrategy.preferProjectModules()
  460. // Alternatively, we can fail eagerly on version conflict to see the conflicts
  461. //resolutionStrategy.failOnVersionConflict()
  462. }
  463. implementation 'net.zetetic:android-database-sqlcipher:4.4.3'
  464. implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
  465. implementation 'net.sf.opencsv:opencsv:2.3'
  466. implementation 'net.lingala.zip4j:zip4j:2.9.0'
  467. implementation 'com.getkeepsafe.taptargetview:taptargetview:1.13.2'
  468. implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:9.2.1'
  469. // commons-io >2.6 requires android 8
  470. implementation 'commons-io:commons-io:2.6'
  471. implementation 'org.slf4j:slf4j-api:1.7.30'
  472. implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.23'
  473. implementation 'com.theartofdev.edmodo:android-image-cropper:2.8.0'
  474. implementation 'com.datatheorem.android.trustkit:trustkit:1.1.3'
  475. implementation 'com.takisoft.preferencex:preferencex:1.1.0'
  476. implementation 'me.zhanghai.android.fastscroll:library:1.1.5'
  477. // AndroidX / Jetpack support libraries
  478. implementation "androidx.core:core:1.5.0"
  479. implementation "androidx.preference:preference:1.1.1"
  480. implementation 'androidx.legacy:legacy-support-v13:1.0.0'
  481. implementation 'androidx.recyclerview:recyclerview:1.2.1'
  482. implementation 'androidx.palette:palette:1.0.0'
  483. implementation 'androidx.appcompat:appcompat:1.3.0'
  484. implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
  485. implementation 'androidx.biometric:biometric:1.1.0'
  486. implementation "androidx.work:work-runtime:2.5.0"
  487. implementation 'androidx.fragment:fragment:1.3.5'
  488. implementation 'androidx.activity:activity:1.2.3'
  489. implementation 'androidx.sqlite:sqlite:2.1.0'
  490. implementation "androidx.concurrent:concurrent-futures:1.1.0"
  491. implementation "androidx.camera:camera-camera2:1.0.1"
  492. implementation "androidx.camera:camera-lifecycle:1.0.1"
  493. // camera-view >1.0.0-alpha25 requires compileSDK 30
  494. implementation "androidx.camera:camera-view:1.0.0-alpha25"
  495. implementation 'androidx.multidex:multidex:2.0.1'
  496. implementation "androidx.lifecycle:lifecycle-viewmodel:2.3.1"
  497. implementation "androidx.lifecycle:lifecycle-livedata:2.3.1"
  498. implementation "androidx.lifecycle:lifecycle-runtime:2.3.1"
  499. implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.3.1"
  500. implementation "androidx.lifecycle:lifecycle-service:2.3.1"
  501. implementation "androidx.lifecycle:lifecycle-process:2.3.1"
  502. implementation "androidx.lifecycle:lifecycle-common-java8:2.3.1"
  503. implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
  504. implementation 'androidx.legacy:legacy-support-v4:1.0.0'
  505. implementation "androidx.paging:paging-runtime:3.0.0"
  506. implementation 'com.google.android.material:material:1.4.0'
  507. implementation 'com.google.android.exoplayer:exoplayer-core:2.13.3'
  508. implementation 'com.google.android.exoplayer:exoplayer-ui:2.13.3'
  509. implementation 'com.google.protobuf:protobuf-javalite:3.9.1'
  510. implementation 'com.google.zxing:core:3.3.3' // zxing 3.4 crashes on kitkat
  511. implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.26'
  512. // webclient dependencies
  513. implementation 'org.msgpack:msgpack-core:0.8.22!!'
  514. implementation 'com.neovisionaries:nv-websocket-client:2.9'
  515. // Backport of Streams and CompletableFuture. Remove once API level 24 is supported.
  516. implementation 'net.sourceforge.streamsupport:streamsupport-cfuture:1.7.2'
  517. // Google Assistant Voice Action verification library
  518. implementation(name:'libgsaverification-client', ext:'aar')
  519. implementation('org.saltyrtc:saltyrtc-client:0.14.2') {
  520. exclude group: 'org.json'
  521. }
  522. implementation 'org.saltyrtc:chunked-dc:1.0.1'
  523. implementation 'ch.threema:webrtc-android:91.0.1'
  524. implementation('org.saltyrtc:saltyrtc-task-webrtc:0.18.1') {
  525. exclude module: 'saltyrtc-client'
  526. }
  527. // Glide components
  528. implementation 'com.github.bumptech.glide:glide:4.11.0'
  529. annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
  530. // use leak canary in debug builds
  531. // debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.5'
  532. // test dependencies
  533. testImplementation 'junit:junit:4.12'
  534. // use powermock instead of mockito. it support mocking static classes.
  535. def mockitoVersion = '2.0.7'
  536. testImplementation "org.powermock:powermock-api-mockito2:${mockitoVersion}"
  537. testImplementation "org.powermock:powermock-module-junit4-rule-agent:${mockitoVersion}"
  538. testImplementation "org.powermock:powermock-module-junit4-rule:${mockitoVersion}"
  539. testImplementation "org.powermock:powermock-module-junit4:${mockitoVersion}"
  540. // add JSON support to tests without mocking
  541. testImplementation 'org.json:json:20160212'
  542. androidTestImplementation 'androidx.test:rules:1.2.0'
  543. androidTestImplementation 'tools.fastlane:screengrab:2.0.0', {
  544. exclude group: 'androidx.annotation', module: 'annotation'
  545. }
  546. androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0', {
  547. exclude group: 'androidx.annotation', module: 'annotation'
  548. }
  549. androidTestImplementation 'androidx.test:runner:1.1.0', {
  550. exclude group: 'androidx.annotation', module: 'annotation'
  551. }
  552. androidTestImplementation 'androidx.test.ext:junit:1.1.1'
  553. androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.1.0', {
  554. exclude group: 'androidx.annotation', module: 'annotation'
  555. exclude group: 'androidx.appcompat', module: 'appcompat'
  556. exclude group: 'androidx.legacy', module: 'legacy-support-v4'
  557. exclude group: 'com.google.android.material', module: 'material'
  558. exclude group: 'androidx.recyclerview', module: 'recyclerview'
  559. }
  560. androidTestImplementation 'androidx.test.espresso:espresso-intents:3.1.0', {
  561. exclude group: 'androidx.annotation', module: 'annotation'
  562. }
  563. androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
  564. // Google Play Services and related libraries
  565. def googleDependencies = [
  566. // Play services
  567. 'com.google.android.gms:play-services-base:16.1.0': [],
  568. // Support for wearables
  569. 'com.google.android.gms:play-services-wearable:17.0.0': [],
  570. // Firebase push
  571. //
  572. // Note: Do not upgrade to a higher version of firebase-messaging,
  573. // as we do not want the Firebase Installations API in our app
  574. 'com.google.firebase:firebase-messaging:20.1.0': [
  575. [group: 'com.google.firebase', module: 'firebase-core'],
  576. [group: 'com.google.firebase', module: 'firebase-analytics'],
  577. [group: 'com.google.firebase', module: 'firebase-measurement-connector'],
  578. ],
  579. ]
  580. googleDependencies.each {
  581. def dependency = it.key
  582. def excludes = it.value
  583. noneImplementation(dependency) { excludes.each { exclude it } }
  584. store_googleImplementation(dependency) { excludes.each { exclude it } }
  585. store_google_workImplementation(dependency) { excludes.each { exclude it } }
  586. store_threemaImplementation(dependency) { excludes.each { exclude it } }
  587. sandboxImplementation(dependency) { excludes.each { exclude it } }
  588. sandbox_workImplementation(dependency) { excludes.each { exclude it } }
  589. redImplementation(dependency) { excludes.each { exclude it } }
  590. }
  591. // Huawei related libraries (only for hms* build variants)
  592. def huaweiDependencies = [
  593. // HMS push
  594. 'com.huawei.hms:push:5.0.4.302': [
  595. // Exclude agconnect dependency, we'll replace it with the vendored version below
  596. [group: 'com.huawei.agconnect'],
  597. ],
  598. ]
  599. huaweiDependencies.each {
  600. def dependency = it.key
  601. def excludes = it.value
  602. hmsImplementation(dependency) { excludes.each { exclude it } }
  603. hms_workImplementation(dependency) { excludes.each { exclude it } }
  604. }
  605. hmsImplementation(name: 'agconnect-core-1.4.0.300', ext: 'aar')
  606. hms_workImplementation(name: 'agconnect-core-1.4.0.300', ext: 'aar')
  607. }
  608. sonarqube {
  609. properties {
  610. property "sonar.projectKey", "android-client"
  611. property "sonar.projectName", "Threema for Android"
  612. property "sonar.sources", "src/main/, ../scripts/, ../scripts-internal/"
  613. // Exclusion notes:
  614. // - Protobuf code is generated
  615. // - Java Client code (including jnacl) is already being checked by SonarQube separately
  616. property "sonar.exclusions", "src/main/java/ch/threema/protobuf/**, src/main/java/ch/threema/client/**, src/test/java/ch/threema/client/**, src/main/java/ch/threema/base/**, src/main/java/ch/threema/localcrypto/**, src/test/java/ch/threema/localcrypto/**, src/main/java/com/neilalexander/jnacl/**"
  617. property "sonar.tests", "src/test/"
  618. property "sonar.sourceEncoding", "UTF-8"
  619. property "sonar.verbose", "true"
  620. }
  621. }
  622. // Set up Gradle tasks to fetch screenshots on UI test failures
  623. // See https://medium.com/stepstone-tech/how-to-capture-screenshots-for-failed-ui-tests-9927eea6e1e4
  624. def reportsDirectory = "$buildDir/reports/androidTests/connected"
  625. def screenshotsDirectory = "/sdcard/testfailures/screenshots/"
  626. def clearScreenshotsTask = task('clearScreenshots', type: Exec) {
  627. executable "${android.getAdbExe().toString()}"
  628. args 'shell', 'rm', '-r', screenshotsDirectory
  629. }
  630. def createScreenshotsDirectoryTask = task('createScreenshotsDirectory', type: Exec, group: 'reporting') {
  631. executable "${android.getAdbExe().toString()}"
  632. args 'shell', 'mkdir', '-p', screenshotsDirectory
  633. }
  634. def fetchScreenshotsTask = task('fetchScreenshots', type: Exec, group: 'reporting') {
  635. executable "${android.getAdbExe().toString()}"
  636. args 'pull', screenshotsDirectory + '.', reportsDirectory
  637. finalizedBy {
  638. clearScreenshotsTask
  639. }
  640. dependsOn {
  641. createScreenshotsDirectoryTask
  642. }
  643. doFirst {
  644. new File(reportsDirectory).mkdirs()
  645. }
  646. }
  647. tasks.whenTaskAdded { task ->
  648. if (task.name == 'connectedDebugAndroidTest') {
  649. task.finalizedBy {
  650. fetchScreenshotsTask
  651. }
  652. }
  653. }