build.gradle.kts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // SPDX-FileCopyrightText: 2023 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-3.0-or-later
  3. import android.annotation.SuppressLint
  4. import kotlin.collections.setOf
  5. import org.jlleitschuh.gradle.ktlint.reporter.ReporterType
  6. import com.github.triplet.gradle.androidpublisher.ReleaseStatus
  7. plugins {
  8. id("com.android.application")
  9. id("org.jetbrains.kotlin.android")
  10. id("kotlin-parcelize")
  11. kotlin("plugin.serialization") version "1.9.20"
  12. id("androidx.navigation.safeargs.kotlin")
  13. id("org.jlleitschuh.gradle.ktlint") version "11.4.0"
  14. id("com.github.triplet.play") version "3.8.6"
  15. }
  16. /**
  17. * Use the number of seconds/10 since Jan 1 2016 as the versionCode.
  18. * This lets us upload a new build at most every 10 seconds for the
  19. * next 680 years.
  20. */
  21. val autoVersion = (((System.currentTimeMillis() / 1000) - 1451606400) / 10).toInt()
  22. @Suppress("UnstableApiUsage")
  23. android {
  24. namespace = "org.yuzu.yuzu_emu"
  25. compileSdkVersion = "android-34"
  26. ndkVersion = "26.1.10909125"
  27. buildFeatures {
  28. viewBinding = true
  29. }
  30. compileOptions {
  31. sourceCompatibility = JavaVersion.VERSION_17
  32. targetCompatibility = JavaVersion.VERSION_17
  33. }
  34. kotlinOptions {
  35. jvmTarget = "17"
  36. }
  37. packaging {
  38. // This is necessary for libadrenotools custom driver loading
  39. jniLibs.useLegacyPackaging = true
  40. }
  41. androidResources {
  42. generateLocaleConfig = true
  43. }
  44. defaultConfig {
  45. // TODO If this is ever modified, change application_id in strings.xml
  46. applicationId = "org.yuzu.yuzu_emu"
  47. minSdk = 30
  48. targetSdk = 34
  49. versionName = getGitVersion()
  50. versionCode = if (System.getenv("AUTO_VERSIONED") == "true") {
  51. autoVersion
  52. } else {
  53. 1
  54. }
  55. ndk {
  56. @SuppressLint("ChromeOsAbiSupport")
  57. abiFilters += listOf("arm64-v8a")
  58. }
  59. buildConfigField("String", "GIT_HASH", "\"${getGitHash()}\"")
  60. buildConfigField("String", "BRANCH", "\"${getBranch()}\"")
  61. }
  62. val keystoreFile = System.getenv("ANDROID_KEYSTORE_FILE")
  63. signingConfigs {
  64. if (keystoreFile != null) {
  65. create("release") {
  66. storeFile = file(keystoreFile)
  67. storePassword = System.getenv("ANDROID_KEYSTORE_PASS")
  68. keyAlias = System.getenv("ANDROID_KEY_ALIAS")
  69. keyPassword = System.getenv("ANDROID_KEYSTORE_PASS")
  70. }
  71. }
  72. create("default") {
  73. storeFile = file("$projectDir/debug.keystore")
  74. storePassword = "android"
  75. keyAlias = "androiddebugkey"
  76. keyPassword = "android"
  77. }
  78. }
  79. // Define build types, which are orthogonal to product flavors.
  80. buildTypes {
  81. // Signed by release key, allowing for upload to Play Store.
  82. release {
  83. signingConfig = if (keystoreFile != null) {
  84. signingConfigs.getByName("release")
  85. } else {
  86. signingConfigs.getByName("default")
  87. }
  88. resValue("string", "app_name_suffixed", "yuzu")
  89. isMinifyEnabled = true
  90. isDebuggable = false
  91. proguardFiles(
  92. getDefaultProguardFile("proguard-android.txt"),
  93. "proguard-rules.pro"
  94. )
  95. }
  96. // builds a release build that doesn't need signing
  97. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
  98. register("relWithDebInfo") {
  99. isDefault = true
  100. resValue("string", "app_name_suffixed", "yuzu Debug Release")
  101. signingConfig = signingConfigs.getByName("default")
  102. isMinifyEnabled = true
  103. isDebuggable = true
  104. proguardFiles(
  105. getDefaultProguardFile("proguard-android.txt"),
  106. "proguard-rules.pro"
  107. )
  108. versionNameSuffix = "-relWithDebInfo"
  109. applicationIdSuffix = ".relWithDebInfo"
  110. isJniDebuggable = true
  111. }
  112. // Signed by debug key disallowing distribution on Play Store.
  113. // Attaches 'debug' suffix to version and package name, allowing installation alongside the release build.
  114. debug {
  115. signingConfig = signingConfigs.getByName("default")
  116. resValue("string", "app_name_suffixed", "yuzu Debug")
  117. isDebuggable = true
  118. isJniDebuggable = true
  119. versionNameSuffix = "-debug"
  120. applicationIdSuffix = ".debug"
  121. }
  122. }
  123. flavorDimensions.add("version")
  124. productFlavors {
  125. create("mainline") {
  126. isDefault = true
  127. dimension = "version"
  128. buildConfigField("Boolean", "PREMIUM", "false")
  129. }
  130. create("ea") {
  131. dimension = "version"
  132. buildConfigField("Boolean", "PREMIUM", "true")
  133. applicationIdSuffix = ".ea"
  134. }
  135. }
  136. externalNativeBuild {
  137. cmake {
  138. version = "3.22.1"
  139. path = file("../../../CMakeLists.txt")
  140. }
  141. }
  142. defaultConfig {
  143. externalNativeBuild {
  144. cmake {
  145. arguments(
  146. "-DENABLE_QT=0", // Don't use QT
  147. "-DENABLE_SDL2=0", // Don't use SDL
  148. "-DENABLE_WEB_SERVICE=0", // Don't use telemetry
  149. "-DBUNDLE_SPEEX=ON",
  150. "-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work
  151. "-DYUZU_USE_BUNDLED_VCPKG=ON",
  152. "-DYUZU_USE_BUNDLED_FFMPEG=ON",
  153. "-DYUZU_ENABLE_LTO=ON",
  154. "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"
  155. )
  156. abiFilters("arm64-v8a", "x86_64")
  157. }
  158. }
  159. }
  160. }
  161. tasks.create<Delete>("ktlintReset") {
  162. delete(File(buildDir.path + File.separator + "intermediates/ktLint"))
  163. }
  164. val showFormatHelp = {
  165. logger.lifecycle(
  166. "If this check fails, please try running \"gradlew ktlintFormat\" for automatic " +
  167. "codestyle fixes"
  168. )
  169. }
  170. tasks.getByPath("ktlintKotlinScriptCheck").doFirst { showFormatHelp.invoke() }
  171. tasks.getByPath("ktlintMainSourceSetCheck").doFirst { showFormatHelp.invoke() }
  172. tasks.getByPath("loadKtlintReporters").dependsOn("ktlintReset")
  173. ktlint {
  174. version.set("0.47.1")
  175. android.set(true)
  176. ignoreFailures.set(false)
  177. disabledRules.set(
  178. setOf(
  179. "no-wildcard-imports",
  180. "package-name",
  181. "import-ordering"
  182. )
  183. )
  184. reporters {
  185. reporter(ReporterType.CHECKSTYLE)
  186. }
  187. }
  188. play {
  189. val keyPath = System.getenv("SERVICE_ACCOUNT_KEY_PATH")
  190. if (keyPath != null) {
  191. serviceAccountCredentials.set(File(keyPath))
  192. }
  193. track.set(System.getenv("STORE_TRACK") ?: "internal")
  194. releaseStatus.set(ReleaseStatus.COMPLETED)
  195. }
  196. dependencies {
  197. implementation("androidx.core:core-ktx:1.12.0")
  198. implementation("androidx.appcompat:appcompat:1.6.1")
  199. implementation("androidx.recyclerview:recyclerview:1.3.1")
  200. implementation("androidx.constraintlayout:constraintlayout:2.1.4")
  201. implementation("androidx.fragment:fragment-ktx:1.6.1")
  202. implementation("androidx.documentfile:documentfile:1.0.1")
  203. implementation("com.google.android.material:material:1.9.0")
  204. implementation("androidx.preference:preference-ktx:1.2.1")
  205. implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2")
  206. implementation("io.coil-kt:coil:2.2.2")
  207. implementation("androidx.core:core-splashscreen:1.0.1")
  208. implementation("androidx.window:window:1.2.0-beta03")
  209. implementation("androidx.constraintlayout:constraintlayout:2.1.4")
  210. implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
  211. implementation("androidx.navigation:navigation-fragment-ktx:2.7.4")
  212. implementation("androidx.navigation:navigation-ui-ktx:2.7.4")
  213. implementation("info.debatty:java-string-similarity:2.0.0")
  214. implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
  215. }
  216. fun runGitCommand(command: List<String>): String {
  217. return try {
  218. ProcessBuilder(command)
  219. .directory(project.rootDir)
  220. .redirectOutput(ProcessBuilder.Redirect.PIPE)
  221. .redirectError(ProcessBuilder.Redirect.PIPE)
  222. .start().inputStream.bufferedReader().use { it.readText() }
  223. .trim()
  224. } catch (e: Exception) {
  225. logger.error("Cannot find git")
  226. ""
  227. }
  228. }
  229. fun getGitVersion(): String {
  230. val gitVersion = runGitCommand(
  231. listOf(
  232. "git",
  233. "describe",
  234. "--always",
  235. "--long"
  236. )
  237. ).replace(Regex("(-0)?-[^-]+$"), "")
  238. val versionName = if (System.getenv("GITHUB_ACTIONS") != null) {
  239. System.getenv("GIT_TAG_NAME") ?: gitVersion
  240. } else {
  241. gitVersion
  242. }
  243. return versionName.ifEmpty { "0.0" }
  244. }
  245. fun getGitHash(): String =
  246. runGitCommand(listOf("git", "rev-parse", "--short", "HEAD")).ifEmpty { "dummy-hash" }
  247. fun getBranch(): String =
  248. runGitCommand(listOf("git", "rev-parse", "--abbrev-ref", "HEAD")).ifEmpty { "dummy-hash" }