1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-13 13:31:48 +00:00

Merge pull request #74583 from m4gr3d/setup_play_store_builds_3x

[3.x] Update the gradle build tasks to generate play store builds.
This commit is contained in:
Rémi Verschelde
2023-05-17 18:21:36 +02:00
7 changed files with 137 additions and 71 deletions

View File

@@ -54,6 +54,9 @@ if lib_arch_dir != "":
if env["target"] == "release": if env["target"] == "release":
lib_type_dir = "release" lib_type_dir = "release"
elif env["target"] == "release_debug": elif env["target"] == "release_debug":
if env["tools"] and env["store_release"]:
lib_type_dir = "release"
else:
lib_type_dir = "debug" lib_type_dir = "debug"
else: # debug else: # debug
lib_type_dir = "dev" lib_type_dir = "dev"

View File

@@ -24,6 +24,7 @@ def get_opts():
("ndk_platform", 'Target platform (android-<api>, e.g. "android-19")', "android-19"), ("ndk_platform", 'Target platform (android-<api>, e.g. "android-19")', "android-19"),
EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")), EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")),
BoolVariable("android_neon", "Enable NEON support (armv7 only)", True), BoolVariable("android_neon", "Enable NEON support (armv7 only)", True),
BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False),
] ]

View File

@@ -132,7 +132,7 @@ ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
String statusValue = map["status"] String statusValue = map["status"]
if (statusValue == null) { if (statusValue == null) {
statusCode = 0 statusCode = 0
} else if (statusValue.startsWith("alpha")) { } else if (statusValue.startsWith("alpha") || statusValue.startsWith("dev")) {
statusCode = 1 statusCode = 1
} else if (statusValue.startsWith("beta")) { } else if (statusValue.startsWith("beta")) {
statusCode = 2 statusCode = 2

View File

@@ -9,7 +9,7 @@ buildscript {
dependencies { dependencies {
classpath libraries.androidGradlePlugin classpath libraries.androidGradlePlugin
classpath libraries.kotlinGradlePlugin classpath libraries.kotlinGradlePlugin
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0' classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
} }
} }
@@ -36,8 +36,11 @@ allprojects {
ext { ext {
supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"] supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"]
supportedFlavors = ["editor", "template"] supportedFlavors = ["editor", "template"]
supportedTargetsMapByFlavors = [
"editor": [release: "release_debug", dev: "debug", debug: "release_debug"],
"template": [release: "release", dev: "debug", debug: "release_debug"]
]
// Used by gradle to specify which architecture to build for by default when running // Used by gradle to specify which architecture to build for by default when running
// `./gradlew build` (this command is usually used by Android Studio). // `./gradlew build` (this command is usually used by Android Studio).
@@ -49,6 +52,7 @@ ext {
def rootDir = "../../.." def rootDir = "../../.."
def binDir = "$rootDir/bin/" def binDir = "$rootDir/bin/"
def androidEditorBuildsDir = "$binDir/android_editor_builds/"
def getSconsTaskName(String flavor, String buildType, String abi) { def getSconsTaskName(String flavor, String buildType, String abi) {
return "compileGodotNativeLibs" + flavor.capitalize() + buildType.capitalize() + abi.capitalize() return "compileGodotNativeLibs" + flavor.capitalize() + buildType.capitalize() + abi.capitalize()
@@ -175,13 +179,7 @@ def templateExcludedBuildTask() {
if (!isAndroidStudio()) { if (!isAndroidStudio()) {
logger.lifecycle("Excluding Android studio build tasks") logger.lifecycle("Excluding Android studio build tasks")
for (String flavor : supportedFlavors) { for (String flavor : supportedFlavors) {
for (String buildType : supportedTargetsMap.keySet()) { for (String buildType : supportedTargetsMapByFlavors[flavor].keySet()) {
if (buildType == "release" && flavor == "editor") {
// The editor can't be used with target=release as debugging tools are then not
// included, and it would crash on errors instead of reporting them.
continue
}
for (String abi : selectedAbis) { for (String abi : selectedAbis) {
excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi) excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi)
} }
@@ -195,7 +193,7 @@ def templateBuildTasks() {
def tasks = [] def tasks = []
// Only build the apks and aar files for which we have native shared libraries. // Only build the apks and aar files for which we have native shared libraries.
for (String target : supportedTargetsMap.keySet()) { for (String target : supportedTargetsMapByFlavors["template"].keySet()) {
File targetLibs = new File("lib/libs/" + target) File targetLibs = new File("lib/libs/" + target)
if (targetLibs != null if (targetLibs != null
&& targetLibs.isDirectory() && targetLibs.isDirectory()
@@ -221,18 +219,46 @@ def isAndroidStudio() {
return sysProps != null && sysProps['idea.platform.prefix'] != null return sysProps != null && sysProps['idea.platform.prefix'] != null
} }
task copyEditorDebugBinaryToBin(type: Copy) { task copyEditorReleaseApkToBin(type: Copy) {
dependsOn ':editor:assembleDebug' dependsOn ':editor:assembleRelease'
from('editor/build/outputs/apk/debug') from('editor/build/outputs/apk/release')
into(binDir) into(androidEditorBuildsDir)
include('android_editor.apk') include('android_editor-release*.apk')
} }
task copyEditorDevBinaryToBin(type: Copy) { task copyEditorReleaseAabToBin(type: Copy) {
dependsOn ':editor:bundleRelease'
from('editor/build/outputs/bundle/release')
into(androidEditorBuildsDir)
include('android_editor-release*.aab')
}
task copyEditorDebugApkToBin(type: Copy) {
dependsOn ':editor:assembleDebug'
from('editor/build/outputs/apk/debug')
into(androidEditorBuildsDir)
include('android_editor-debug.apk')
}
task copyEditorDebugAabToBin(type: Copy) {
dependsOn ':editor:bundleDebug'
from('editor/build/outputs/bundle/debug')
into(androidEditorBuildsDir)
include('android_editor-debug.aab')
}
task copyEditorDevApkToBin(type: Copy) {
dependsOn ':editor:assembleDev' dependsOn ':editor:assembleDev'
from('editor/build/outputs/apk/dev') from('editor/build/outputs/apk/dev')
into(binDir) into(androidEditorBuildsDir)
include('android_editor_dev.apk') include('android_editor-dev.apk')
}
task copyEditorDevAabToBin(type: Copy) {
dependsOn ':editor:bundleDev'
from('editor/build/outputs/bundle/dev')
into(androidEditorBuildsDir)
include('android_editor-dev.aab')
} }
/** /**
@@ -247,18 +273,14 @@ task generateGodotEditor {
def tasks = [] def tasks = []
for (String target : supportedTargetsMap.keySet()) { for (String target : supportedTargetsMapByFlavors["editor"].keySet()) {
if (target == "release") {
// The editor can't be used with target=release as debugging tools are then not
// included, and it would crash on errors instead of reporting them.
continue
}
File targetLibs = new File("lib/libs/tools/" + target) File targetLibs = new File("lib/libs/tools/" + target)
if (targetLibs != null if (targetLibs != null
&& targetLibs.isDirectory() && targetLibs.isDirectory()
&& targetLibs.listFiles() != null && targetLibs.listFiles() != null
&& targetLibs.listFiles().length > 0) { && targetLibs.listFiles().length > 0) {
tasks += "copyEditor${target.capitalize()}BinaryToBin" tasks += "copyEditor${target.capitalize()}ApkToBin"
tasks += "copyEditor${target.capitalize()}AabToBin"
} }
} }
@@ -306,9 +328,11 @@ task cleanGodotEditor(type: Delete) {
// Delete the generated binary apks // Delete the generated binary apks
delete("editor/build/outputs/apk") delete("editor/build/outputs/apk")
// Delete the Godot editor apks in the Godot bin directory // Delete the generated aab binaries
delete("$binDir/android_editor.apk") delete("editor/build/outputs/bundle")
delete("$binDir/android_editor_dev.apk")
// Delete the Godot editor apks & aabs in the Godot bin directory
delete(androidEditorBuildsDir)
} }
/** /**

View File

@@ -13,22 +13,67 @@ dependencies {
} }
ext { ext {
// Build number added as a suffix to the version code, and incremented for each build/upload to // Retrieve the build number from the environment variable; default to 0 if none is specified.
// the Google Play store. // The build number is added as a suffix to the version code for upload to the Google Play store.
// This should be reset on each stable release of Godot. getEditorBuildNumber = { ->
editorBuildNumber = 0 int buildNumber = 0
String versionStatus = System.getenv("GODOT_VERSION_STATUS")
if (versionStatus != null && !versionStatus.isEmpty()) {
try {
buildNumber = Integer.parseInt(versionStatus.replaceAll("[^0-9]", ""));
} catch (NumberFormatException ignored) {
buildNumber = 0
}
}
return buildNumber
}
// Value by which the Godot version code should be offset by to make room for the build number // Value by which the Godot version code should be offset by to make room for the build number
editorBuildNumberOffset = 100 editorBuildNumberOffset = 100
// Return the keystore file used for signing the release build.
getGodotKeystoreFile = { ->
def keyStore = System.getenv("GODOT_ANDROID_SIGN_KEYSTORE")
if (keyStore == null) {
return null
}
return file(keyStore)
}
// Return the key alias used for signing the release build.
getGodotKeyAlias = { ->
def kAlias = System.getenv("GODOT_ANDROID_KEYSTORE_ALIAS")
return kAlias
}
// Return the password for the key used for signing the release build.
getGodotSigningPassword = { ->
def signingPassword = System.getenv("GODOT_ANDROID_SIGN_PASSWORD")
return signingPassword
}
// Returns true if the environment variables contains the configuration for signing the release
// build.
hasReleaseSigningConfigs = { ->
def keystoreFile = getGodotKeystoreFile()
def keyAlias = getGodotKeyAlias()
def signingPassword = getGodotSigningPassword()
return keystoreFile != null && keystoreFile.isFile()
&& keyAlias != null && !keyAlias.isEmpty()
&& signingPassword != null && !signingPassword.isEmpty()
}
} }
def generateVersionCode() { def generateVersionCode() {
int libraryVersionCode = getGodotLibraryVersionCode() int libraryVersionCode = getGodotLibraryVersionCode()
return (libraryVersionCode * editorBuildNumberOffset) + editorBuildNumber return (libraryVersionCode * editorBuildNumberOffset) + getEditorBuildNumber()
} }
def generateVersionName() { def generateVersionName() {
String libraryVersionName = getGodotLibraryVersionName() String libraryVersionName = getGodotLibraryVersionName()
return libraryVersionName + ".$editorBuildNumber" int buildNumber = getEditorBuildNumber()
return buildNumber == 0 ? libraryVersionName : libraryVersionName + ".$buildNumber"
} }
android { android {
@@ -45,6 +90,7 @@ android {
targetSdkVersion versions.targetSdk targetSdkVersion versions.targetSdk
missingDimensionStrategy 'products', 'editor' missingDimensionStrategy 'products', 'editor'
setProperty("archivesBaseName", "android_editor")
} }
compileOptions { compileOptions {
@@ -56,6 +102,15 @@ android {
jvmTarget = versions.javaVersion jvmTarget = versions.javaVersion
} }
signingConfigs {
release {
storeFile getGodotKeystoreFile()
storePassword getGodotSigningPassword()
keyAlias getGodotKeyAlias()
keyPassword getGodotSigningPassword()
}
}
buildTypes { buildTypes {
dev { dev {
initWith debug initWith debug
@@ -65,14 +120,14 @@ android {
debug { debug {
initWith release initWith release
// Need to swap with the release signing config when this is ready for public release. applicationIdSuffix ".debug"
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
release { release {
// This buildtype is disabled below. if (hasReleaseSigningConfigs()) {
// The editor can't be used with target=release only, as debugging tools are then not signingConfig signingConfigs.release
// included, and it would crash on errors instead of reporting them. }
} }
} }
@@ -82,20 +137,4 @@ android {
doNotStrip '**/*.so' doNotStrip '**/*.so'
} }
} }
// Disable 'release' buildtype.
// The editor can't be used with target=release only, as debugging tools are then not
// included, and it would crash on errors instead of reporting them.
variantFilter { variant ->
if (variant.buildType.name == "release") {
setIgnore(true)
}
}
applicationVariants.all { variant ->
variant.outputs.all { output ->
def suffix = variant.name == "dev" ? "_dev" : ""
output.outputFileName = "android_editor${suffix}.apk"
}
}
} }

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="godot_editor_name_string">Godot Editor 3 (debug)</string>
</resources>

View File

@@ -80,19 +80,11 @@ android {
release.jniLibs.srcDirs = ['libs/release'] release.jniLibs.srcDirs = ['libs/release']
// Editor jni library // Editor jni library
editorRelease.jniLibs.srcDirs = ['libs/tools/release']
editorDebug.jniLibs.srcDirs = ['libs/tools/debug'] editorDebug.jniLibs.srcDirs = ['libs/tools/debug']
editorDev.jniLibs.srcDirs = ['libs/tools/dev'] editorDev.jniLibs.srcDirs = ['libs/tools/dev']
} }
// Disable 'editorRelease'.
// The editor can't be used with target=release as debugging tools are then not
// included, and it would crash on errors instead of reporting them.
variantFilter { variant ->
if (variant.name == "editorRelease") {
setIgnore(true)
}
}
libraryVariants.all { variant -> libraryVariants.all { variant ->
def flavorName = variant.getFlavorName() def flavorName = variant.getFlavorName()
if (flavorName == null || flavorName == "") { if (flavorName == null || flavorName == "") {
@@ -102,11 +94,14 @@ android {
boolean toolsFlag = flavorName == "editor" boolean toolsFlag = flavorName == "editor"
def buildType = variant.buildType.name def buildType = variant.buildType.name
if (buildType == null || buildType == "" || !supportedTargetsMap.containsKey(buildType)) { if (buildType == null || buildType == "" || !supportedTargetsMapByFlavors[flavorName].containsKey(buildType)) {
throw new GradleException("Invalid build type: $buildType") throw new GradleException("Invalid build type: $buildType")
} }
def sconsTarget = supportedTargetsMap[buildType] boolean productionBuild = buildType != "dev"
boolean storeRelease = buildType == "release"
def sconsTarget = supportedTargetsMapByFlavors[flavorName][buildType]
if (sconsTarget == null || sconsTarget == "") { if (sconsTarget == null || sconsTarget == "") {
throw new GradleException("Invalid scons target: $sconsTarget") throw new GradleException("Invalid scons target: $sconsTarget")
} }
@@ -126,10 +121,10 @@ android {
def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows() def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows()
? [".bat", ".cmd", ".ps1", ".exe"] ? [".bat", ".cmd", ".ps1", ".exe"]
: [""]) : [""])
logger.lifecycle("Looking for $sconsName executable path") logger.debug("Looking for $sconsName executable path")
for (ext in sconsExts) { for (ext in sconsExts) {
String sconsNameExt = sconsName + ext String sconsNameExt = sconsName + ext
logger.lifecycle("Checking $sconsNameExt") logger.debug("Checking $sconsNameExt")
sconsExecutableFile = org.gradle.internal.os.OperatingSystem.current().findInPath(sconsNameExt) sconsExecutableFile = org.gradle.internal.os.OperatingSystem.current().findInPath(sconsNameExt)
if (sconsExecutableFile != null) { if (sconsExecutableFile != null) {
@@ -149,7 +144,7 @@ android {
if (sconsExecutableFile == null) { if (sconsExecutableFile == null) {
throw new GradleException("Unable to find executable path for the '$sconsName' command.") throw new GradleException("Unable to find executable path for the '$sconsName' command.")
} else { } else {
logger.lifecycle("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}") logger.debug("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}")
} }
for (String selectedAbi : selectedAbis) { for (String selectedAbi : selectedAbis) {
@@ -161,7 +156,7 @@ android {
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi) def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
tasks.create(name: taskName, type: Exec) { tasks.create(name: taskName, type: Exec) {
executable sconsExecutableFile.absolutePath executable sconsExecutableFile.absolutePath
args "--directory=${pathToRootDir}", "platform=android", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors() args "--directory=${pathToRootDir}", "platform=android", "store_release=${storeRelease}", "production=${productionBuild}", "tools=${toolsFlag}", "target=${sconsTarget}", "android_arch=${selectedAbi}", "-j" + Runtime.runtime.availableProcessors()
} }
// Schedule the tasks so the generated libs are present before the aar file is packaged. // Schedule the tasks so the generated libs are present before the aar file is packaged.