build.gradle 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. // Gradle build config for Godot Engine's Android port.
  2. plugins {
  3. id 'com.android.application'
  4. id 'org.jetbrains.kotlin.android'
  5. }
  6. apply from: 'config.gradle'
  7. allprojects {
  8. repositories {
  9. google()
  10. mavenCentral()
  11. gradlePluginPortal()
  12. maven { url "https://plugins.gradle.org/m2/" }
  13. maven { url "https://central.sonatype.com/repository/maven-snapshots/"}
  14. // Godot user plugins custom maven repos
  15. String[] mavenRepos = getGodotPluginsMavenRepos()
  16. if (mavenRepos != null && mavenRepos.size() > 0) {
  17. for (String repoUrl : mavenRepos) {
  18. maven {
  19. url repoUrl
  20. }
  21. }
  22. }
  23. }
  24. }
  25. configurations {
  26. // Initializes a placeholder for the devImplementation dependency configuration.
  27. devImplementation {}
  28. // Initializes a placeholder for the monoImplementation dependency configuration.
  29. monoImplementation {}
  30. }
  31. dependencies {
  32. // Android instrumented test dependencies
  33. androidTestImplementation "androidx.test.ext:junit:$versions.junitVersion"
  34. androidTestImplementation "androidx.test.espresso:espresso-core:$versions.espressoCoreVersion"
  35. androidTestImplementation "org.jetbrains.kotlin:kotlin-test:$versions.kotlinTestVersion"
  36. androidTestImplementation "androidx.test:runner:$versions.testRunnerVersion"
  37. androidTestUtil "androidx.test:orchestrator:$versions.testOrchestratorVersion"
  38. implementation "androidx.fragment:fragment:$versions.fragmentVersion"
  39. implementation "androidx.core:core-splashscreen:$versions.splashscreenVersion"
  40. if (rootProject.findProject(":lib")) {
  41. implementation project(":lib")
  42. } else if (rootProject.findProject(":godot:lib")) {
  43. implementation project(":godot:lib")
  44. } else {
  45. // Godot gradle build mode. In this scenario this project is the only one around and the Godot
  46. // library is available through the pre-generated godot-lib.*.aar android archive files.
  47. debugImplementation fileTree(dir: 'libs/debug', include: ['**/*.jar', '*.aar'])
  48. devImplementation fileTree(dir: 'libs/dev', include: ['**/*.jar', '*.aar'])
  49. releaseImplementation fileTree(dir: 'libs/release', include: ['**/*.jar', '*.aar'])
  50. }
  51. // Godot user plugins remote dependencies
  52. String[] remoteDeps = getGodotPluginsRemoteBinaries()
  53. if (remoteDeps != null && remoteDeps.size() > 0) {
  54. for (String dep : remoteDeps) {
  55. implementation dep
  56. }
  57. }
  58. // Godot user plugins local dependencies
  59. String[] pluginsBinaries = getGodotPluginsLocalBinaries()
  60. if (pluginsBinaries != null && pluginsBinaries.size() > 0) {
  61. implementation files(pluginsBinaries)
  62. }
  63. // Automatically pick up local dependencies in res://addons
  64. String addonsDirectory = getAddonsDirectory()
  65. if (addonsDirectory != null && !addonsDirectory.isBlank()) {
  66. implementation fileTree(dir: "$addonsDirectory", include: ['*.jar', '*.aar'])
  67. }
  68. // .NET dependencies
  69. String jar = '../../../../modules/mono/thirdparty/libSystem.Security.Cryptography.Native.Android.jar'
  70. if (file(jar).exists()) {
  71. monoImplementation files(jar)
  72. }
  73. }
  74. android {
  75. compileSdkVersion versions.compileSdk
  76. buildToolsVersion versions.buildTools
  77. ndkVersion versions.ndkVersion
  78. compileOptions {
  79. sourceCompatibility versions.javaVersion
  80. targetCompatibility versions.javaVersion
  81. }
  82. kotlinOptions {
  83. jvmTarget = versions.javaVersion
  84. }
  85. assetPacks = [":assetPackInstallTime"]
  86. namespace = 'com.godot.game'
  87. defaultConfig {
  88. // The default ignore pattern for the 'assets' directory includes hidden files and directories which are used by Godot projects.
  89. aaptOptions {
  90. ignoreAssetsPattern "!.svn:!.git:!.gitignore:!.ds_store:!*.scc:!CVS:!thumbs.db:!picasa.ini:!*~"
  91. }
  92. ndk {
  93. debugSymbolLevel 'NONE'
  94. String[] export_abi_list = getExportEnabledABIs()
  95. abiFilters export_abi_list
  96. }
  97. // Feel free to modify the application id to your own.
  98. applicationId getExportPackageName()
  99. versionCode getExportVersionCode()
  100. versionName getExportVersionName()
  101. minSdkVersion getExportMinSdkVersion()
  102. targetSdkVersion getExportTargetSdkVersion()
  103. missingDimensionStrategy 'products', 'template'
  104. testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  105. // The following argument makes the Android Test Orchestrator run its
  106. // "pm clear" command after each test invocation. This command ensures
  107. // that the app's state is completely cleared between tests.
  108. testInstrumentationRunnerArguments clearPackageData: 'true'
  109. }
  110. testOptions {
  111. execution 'ANDROIDX_TEST_ORCHESTRATOR'
  112. }
  113. lintOptions {
  114. abortOnError false
  115. disable 'MissingTranslation', 'UnusedResources'
  116. }
  117. ndkVersion versions.ndkVersion
  118. packagingOptions {
  119. exclude 'META-INF/LICENSE'
  120. exclude 'META-INF/NOTICE'
  121. // Debug symbols are kept for development within Android Studio.
  122. if (shouldNotStrip()) {
  123. jniLibs {
  124. keepDebugSymbols += '**/*.so'
  125. }
  126. }
  127. jniLibs {
  128. // Setting this to true causes AGP to package compressed native libraries when building the app
  129. // For more background, see:
  130. // - https://developer.android.com/build/releases/past-releases/agp-3-6-0-release-notes#extractNativeLibs
  131. // - https://stackoverflow.com/a/44704840
  132. useLegacyPackaging shouldUseLegacyPackaging()
  133. }
  134. // Always select Godot's version of libc++_shared.so in case deps have their own
  135. pickFirst 'lib/x86/libc++_shared.so'
  136. pickFirst 'lib/x86_64/libc++_shared.so'
  137. pickFirst 'lib/armeabi-v7a/libc++_shared.so'
  138. pickFirst 'lib/arm64-v8a/libc++_shared.so'
  139. }
  140. signingConfigs {
  141. debug {
  142. if (hasCustomDebugKeystore()) {
  143. storeFile new File(getDebugKeystoreFile())
  144. storePassword getDebugKeystorePassword()
  145. keyAlias getDebugKeyAlias()
  146. keyPassword getDebugKeystorePassword()
  147. }
  148. }
  149. release {
  150. File keystoreFile = new File(getReleaseKeystoreFile())
  151. if (keystoreFile.isFile()) {
  152. storeFile keystoreFile
  153. storePassword getReleaseKeystorePassword()
  154. keyAlias getReleaseKeyAlias()
  155. keyPassword getReleaseKeystorePassword()
  156. }
  157. }
  158. }
  159. buildFeatures {
  160. buildConfig = true
  161. }
  162. buildTypes {
  163. debug {
  164. // Signing and zip-aligning are skipped for prebuilt builds, but
  165. // performed for Godot gradle builds.
  166. zipAlignEnabled shouldZipAlign()
  167. if (shouldSign()) {
  168. signingConfig signingConfigs.debug
  169. } else {
  170. signingConfig null
  171. }
  172. }
  173. dev {
  174. initWith debug
  175. // Signing and zip-aligning are skipped for prebuilt builds, but
  176. // performed for Godot gradle builds.
  177. zipAlignEnabled shouldZipAlign()
  178. if (shouldSign()) {
  179. signingConfig signingConfigs.debug
  180. } else {
  181. signingConfig null
  182. }
  183. }
  184. release {
  185. // Signing and zip-aligning are skipped for prebuilt builds, but
  186. // performed for Godot gradle builds.
  187. zipAlignEnabled shouldZipAlign()
  188. if (shouldSign()) {
  189. signingConfig signingConfigs.release
  190. } else {
  191. signingConfig null
  192. }
  193. }
  194. }
  195. flavorDimensions 'edition'
  196. productFlavors {
  197. // Product flavor for the standard (no .net support) builds.
  198. standard {
  199. getIsDefault().set(true)
  200. }
  201. // Product flavor for the Mono (.net) builds.
  202. mono {}
  203. // Product flavor used for running instrumented tests.
  204. instrumented {
  205. applicationIdSuffix ".instrumented"
  206. versionNameSuffix "-instrumented"
  207. }
  208. }
  209. sourceSets {
  210. main.res.srcDirs += ['res']
  211. debug.jniLibs.srcDirs = ['libs/debug', 'libs/debug/vulkan_validation_layers']
  212. dev.jniLibs.srcDirs = ['libs/dev']
  213. release.jniLibs.srcDirs = ['libs/release']
  214. }
  215. applicationVariants.all { variant ->
  216. variant.outputs.all { output ->
  217. String filenameSuffix = variant.flavorName == "mono" ? variant.name : variant.buildType.name
  218. output.outputFileName = "android_${filenameSuffix}.apk"
  219. }
  220. }
  221. }
  222. task copyAndRenameBinary(type: Copy) {
  223. // The 'doNotTrackState' is added to disable gradle's up-to-date checks for output files
  224. // and directories. Otherwise this check may cause permissions access failures on Windows
  225. // machines.
  226. doNotTrackState("No need for up-to-date checks for the copy-and-rename operation")
  227. String exportPath = getExportPath()
  228. String exportFilename = getExportFilename()
  229. String exportEdition = getExportEdition()
  230. String exportBuildType = getExportBuildType()
  231. String exportBuildTypeCapitalized = exportBuildType.capitalize()
  232. String exportFormat = getExportFormat()
  233. boolean isAab = exportFormat == "aab"
  234. boolean isMono = exportEdition == "mono"
  235. String filenameSuffix = isAab ? "${exportEdition}-${exportBuildType}" : exportBuildType
  236. if (isMono) {
  237. filenameSuffix = isAab ? "${exportEdition}-${exportBuildType}" : "${exportEdition}${exportBuildTypeCapitalized}"
  238. }
  239. String sourceFilename = isAab ? "${project.name}-${filenameSuffix}.aab" : "android_${filenameSuffix}.apk"
  240. String sourceFilepath = isAab ? "$buildDir/outputs/bundle/${exportEdition}${exportBuildTypeCapitalized}/$sourceFilename" : "$buildDir/outputs/apk/$exportEdition/$exportBuildType/$sourceFilename"
  241. from sourceFilepath
  242. into exportPath
  243. rename sourceFilename, exportFilename
  244. }
  245. /**
  246. * Used to validate the version of the Java SDK used for the Godot gradle builds.
  247. */
  248. task validateJavaVersion {
  249. if (!JavaVersion.current().isCompatibleWith(versions.javaVersion)) {
  250. throw new GradleException("Invalid Java version ${JavaVersion.current()}. Version ${versions.javaVersion} is the minimum supported Java version for Godot gradle builds.")
  251. }
  252. }
  253. /*
  254. * Older versions of our vendor plugin include a loader that we no longer need.
  255. * This code ensures those are removed.
  256. */
  257. tasks.withType( com.android.build.gradle.internal.tasks.MergeNativeLibsTask) {
  258. doFirst {
  259. externalLibNativeLibs.each { jniDir ->
  260. if (jniDir.getCanonicalPath().contains("godot-openxr-") || jniDir.getCanonicalPath().contains("godotopenxr")) {
  261. // Delete the 'libopenxr_loader.so' files from the vendors plugin so we only use the version from the
  262. // openxr loader dependency.
  263. File armFile = new File(jniDir, "arm64-v8a/libopenxr_loader.so")
  264. if (armFile.exists()) {
  265. armFile.delete()
  266. }
  267. File x86File = new File(jniDir, "x86_64/libopenxr_loader.so")
  268. if (x86File.exists()) {
  269. x86File.delete()
  270. }
  271. }
  272. }
  273. }
  274. }
  275. /*
  276. When they're scheduled to run, the copy*AARToAppModule tasks generate dependencies for the 'app'
  277. module, so we're ensuring the ':app:preBuild' task is set to run after those tasks.
  278. */
  279. if (rootProject.tasks.findByPath("copyDebugAARToAppModule") != null) {
  280. preBuild.mustRunAfter(rootProject.tasks.named("copyDebugAARToAppModule"))
  281. }
  282. if (rootProject.tasks.findByPath("copyDevAARToAppModule") != null) {
  283. preBuild.mustRunAfter(rootProject.tasks.named("copyDevAARToAppModule"))
  284. }
  285. if (rootProject.tasks.findByPath("copyReleaseAARToAppModule") != null) {
  286. preBuild.mustRunAfter(rootProject.tasks.named("copyReleaseAARToAppModule"))
  287. }