Quellcode durchsuchen

Merge pull request #74583 from m4gr3d/setup_play_store_builds_3x

[3.x] Update the gradle build tasks to generate play store builds.
Rémi Verschelde vor 2 Jahren
Ursprung
Commit
e5e73e7068

+ 4 - 1
platform/android/SCsub

@@ -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"
 

+ 1 - 0
platform/android/detect.py

@@ -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),
     ]
 
 

+ 1 - 1
platform/android/java/app/config.gradle

@@ -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

+ 50 - 26
platform/android/java/build.gradle

@@ -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'
     }
 }
 
@@ -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"],
+        "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).
@@ -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()
@@ -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)
                 }
@@ -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()
@@ -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')
 }
 
 /**
@@ -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"
         }
     }
 
@@ -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)
 }
 
 /**

+ 65 - 26
platform/android/java/editor/build.gradle

@@ -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 {
@@ -45,6 +90,7 @@ android {
         targetSdkVersion versions.targetSdk
 
         missingDimensionStrategy 'products', 'editor'
+        setProperty("archivesBaseName", "android_editor")
     }
 
     compileOptions {
@@ -56,6 +102,15 @@ android {
         jvmTarget = versions.javaVersion
     }
 
+    signingConfigs {
+        release {
+            storeFile getGodotKeystoreFile()
+            storePassword getGodotSigningPassword()
+            keyAlias getGodotKeyAlias()
+            keyPassword getGodotSigningPassword()
+        }
+    }
+
     buildTypes {
         dev {
             initWith debug
@@ -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
+            }
         }
     }
 
@@ -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"
-        }
-    }
 }

+ 4 - 0
platform/android/java/editor/src/debug/res/values/strings.xml

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

+ 10 - 15
platform/android/java/lib/build.gradle

@@ -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 == "") {
@@ -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")
         }
@@ -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) {
@@ -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) {
@@ -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.