Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[3.x] Update the gradle build tasks to generate play store builds. #74583

Merged
merged 1 commit into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion platform/android/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ if lib_arch_dir != "":
if env["target"] == "release":
lib_type_dir = "release"
elif env["target"] == "release_debug":
lib_type_dir = "debug"
if env["tools"] and env["store_release"]:
lib_type_dir = "release"
else:
lib_type_dir = "debug"
else: # debug
lib_type_dir = "dev"

Expand Down
1 change: 1 addition & 0 deletions platform/android/detect.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def get_opts():
("ndk_platform", 'Target platform (android-<api>, e.g. "android-19")', "android-19"),
EnumVariable("android_arch", "Target architecture", "armv7", ("armv7", "arm64v8", "x86", "x86_64")),
BoolVariable("android_neon", "Enable NEON support (armv7 only)", True),
BoolVariable("store_release", "Editor build for Google Play Store (for official builds only)", False),
]


Expand Down
2 changes: 1 addition & 1 deletion platform/android/java/app/config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ ext.generateGodotLibraryVersion = { List<String> requiredKeys ->
String statusValue = map["status"]
if (statusValue == null) {
statusCode = 0
} else if (statusValue.startsWith("alpha")) {
} else if (statusValue.startsWith("alpha") || statusValue.startsWith("dev")) {
statusCode = 1
} else if (statusValue.startsWith("beta")) {
statusCode = 2
Expand Down
76 changes: 50 additions & 26 deletions platform/android/java/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ buildscript {
dependencies {
classpath libraries.androidGradlePlugin
classpath libraries.kotlinGradlePlugin
classpath 'io.github.gradle-nexus:publish-plugin:1.1.0'
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
}
}

Expand All @@ -36,8 +36,11 @@ allprojects {

ext {
supportedAbis = ["armv7", "arm64v8", "x86", "x86_64"]
supportedTargetsMap = [release: "release", dev: "debug", debug: "release_debug"]
supportedFlavors = ["editor", "template"]
supportedTargetsMapByFlavors = [
"editor": [release: "release_debug", dev: "debug", debug: "release_debug"],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change release builtype for the editor to storeRelease

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On further investigations, I'm sticking with release because every Android project has an automatic release build type. Changing it to storeRelease will require additional logic to disable the default release build type so we may as well leverage what already exists.

"template": [release: "release", dev: "debug", debug: "release_debug"]
]

// Used by gradle to specify which architecture to build for by default when running
// `./gradlew build` (this command is usually used by Android Studio).
Expand All @@ -49,6 +52,7 @@ ext {

def rootDir = "../../.."
def binDir = "$rootDir/bin/"
def androidEditorBuildsDir = "$binDir/android_editor_builds/"

def getSconsTaskName(String flavor, String buildType, String abi) {
return "compileGodotNativeLibs" + flavor.capitalize() + buildType.capitalize() + abi.capitalize()
Expand Down Expand Up @@ -175,13 +179,7 @@ def templateExcludedBuildTask() {
if (!isAndroidStudio()) {
logger.lifecycle("Excluding Android studio build tasks")
for (String flavor : supportedFlavors) {
for (String buildType : supportedTargetsMap.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 buildType : supportedTargetsMapByFlavors[flavor].keySet()) {
for (String abi : selectedAbis) {
excludedTasks += ":lib:" + getSconsTaskName(flavor, buildType, abi)
}
Expand All @@ -195,7 +193,7 @@ def templateBuildTasks() {
def tasks = []

// 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)
if (targetLibs != null
&& targetLibs.isDirectory()
Expand All @@ -221,18 +219,46 @@ def isAndroidStudio() {
return sysProps != null && sysProps['idea.platform.prefix'] != null
}

task copyEditorDebugBinaryToBin(type: Copy) {
task copyEditorReleaseApkToBin(type: Copy) {
dependsOn ':editor:assembleRelease'
from('editor/build/outputs/apk/release')
into(androidEditorBuildsDir)
include('android_editor-release*.apk')
}

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(binDir)
include('android_editor.apk')
into(androidEditorBuildsDir)
include('android_editor-debug.apk')
}

task copyEditorDevBinaryToBin(type: Copy) {
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'
from('editor/build/outputs/apk/dev')
into(binDir)
include('android_editor_dev.apk')
into(androidEditorBuildsDir)
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')
}

/**
Expand All @@ -247,18 +273,14 @@ task generateGodotEditor {

def tasks = []

for (String target : supportedTargetsMap.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
}
for (String target : supportedTargetsMapByFlavors["editor"].keySet()) {
File targetLibs = new File("lib/libs/tools/" + target)
if (targetLibs != null
&& targetLibs.isDirectory()
&& targetLibs.listFiles() != null
&& targetLibs.listFiles().length > 0) {
tasks += "copyEditor${target.capitalize()}BinaryToBin"
tasks += "copyEditor${target.capitalize()}ApkToBin"
tasks += "copyEditor${target.capitalize()}AabToBin"
}
}

Expand Down Expand Up @@ -306,9 +328,11 @@ task cleanGodotEditor(type: Delete) {
// Delete the generated binary apks
delete("editor/build/outputs/apk")

// Delete the Godot editor apks in the Godot bin directory
delete("$binDir/android_editor.apk")
delete("$binDir/android_editor_dev.apk")
// Delete the generated aab binaries
delete("editor/build/outputs/bundle")

// Delete the Godot editor apks & aabs in the Godot bin directory
delete(androidEditorBuildsDir)
}

/**
Expand Down
91 changes: 65 additions & 26 deletions platform/android/java/editor/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,67 @@ dependencies {
}

ext {
// Build number added as a suffix to the version code, and incremented for each build/upload to
// the Google Play store.
// This should be reset on each stable release of Godot.
editorBuildNumber = 0
// Retrieve the build number from the environment variable; default to 0 if none is specified.
// The build number is added as a suffix to the version code for upload to the Google Play store.
getEditorBuildNumber = { ->
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
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() {
int libraryVersionCode = getGodotLibraryVersionCode()
return (libraryVersionCode * editorBuildNumberOffset) + editorBuildNumber
return (libraryVersionCode * editorBuildNumberOffset) + getEditorBuildNumber()
}

def generateVersionName() {
String libraryVersionName = getGodotLibraryVersionName()
return libraryVersionName + ".$editorBuildNumber"
int buildNumber = getEditorBuildNumber()
return buildNumber == 0 ? libraryVersionName : libraryVersionName + ".$buildNumber"
}

android {
Expand All @@ -45,6 +90,7 @@ android {
targetSdkVersion versions.targetSdk

missingDimensionStrategy 'products', 'editor'
setProperty("archivesBaseName", "android_editor")
}

compileOptions {
Expand All @@ -56,6 +102,15 @@ android {
jvmTarget = versions.javaVersion
}

signingConfigs {
release {
storeFile getGodotKeystoreFile()
storePassword getGodotSigningPassword()
keyAlias getGodotKeyAlias()
keyPassword getGodotSigningPassword()
}
}

buildTypes {
dev {
initWith debug
Expand All @@ -65,14 +120,14 @@ android {
debug {
initWith release

// Need to swap with the release signing config when this is ready for public release.
applicationIdSuffix ".debug"
signingConfig signingConfigs.debug
}

release {
// This buildtype is disabled below.
// 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.
if (hasReleaseSigningConfigs()) {
signingConfig signingConfigs.release
}
}
}

Expand All @@ -82,20 +137,4 @@ android {
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"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="godot_editor_name_string">Godot Editor 3 (debug)</string>
</resources>
25 changes: 10 additions & 15 deletions platform/android/java/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -80,19 +80,11 @@ android {
release.jniLibs.srcDirs = ['libs/release']

// Editor jni library
editorRelease.jniLibs.srcDirs = ['libs/tools/release']
editorDebug.jniLibs.srcDirs = ['libs/tools/debug']
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 ->
def flavorName = variant.getFlavorName()
if (flavorName == null || flavorName == "") {
Expand All @@ -102,11 +94,14 @@ android {
boolean toolsFlag = flavorName == "editor"

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")
}

def sconsTarget = supportedTargetsMap[buildType]
boolean productionBuild = buildType != "dev"
boolean storeRelease = buildType == "release"

def sconsTarget = supportedTargetsMapByFlavors[flavorName][buildType]
if (sconsTarget == null || sconsTarget == "") {
throw new GradleException("Invalid scons target: $sconsTarget")
}
Expand All @@ -126,10 +121,10 @@ android {
def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows()
? [".bat", ".cmd", ".ps1", ".exe"]
: [""])
logger.lifecycle("Looking for $sconsName executable path")
logger.debug("Looking for $sconsName executable path")
for (ext in sconsExts) {
String sconsNameExt = sconsName + ext
logger.lifecycle("Checking $sconsNameExt")
logger.debug("Checking $sconsNameExt")

sconsExecutableFile = org.gradle.internal.os.OperatingSystem.current().findInPath(sconsNameExt)
if (sconsExecutableFile != null) {
Expand All @@ -149,7 +144,7 @@ android {
if (sconsExecutableFile == null) {
throw new GradleException("Unable to find executable path for the '$sconsName' command.")
} else {
logger.lifecycle("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}")
logger.debug("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}")
}

for (String selectedAbi : selectedAbis) {
Expand All @@ -161,7 +156,7 @@ android {
def taskName = getSconsTaskName(flavorName, buildType, selectedAbi)
tasks.create(name: taskName, type: Exec) {
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.
Expand Down