From f17aad663b4555ebfae1318ef8a17ce6bc7c53d5 Mon Sep 17 00:00:00 2001 From: Anish Mishra Date: Fri, 10 Oct 2025 17:37:15 +0530 Subject: [PATCH] Automate Play Store uploads for the Android Editor (#128) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Rémi Verschelde --- .gitignore | 1 + build-android/playstore_upload_script.py | 72 ++++++++++++++++++++++++ build-android/upload-playstore.sh | 21 +++++++ config.sh.in | 3 + publish-release.sh | 9 +++ 5 files changed, 106 insertions(+) create mode 100644 build-android/playstore_upload_script.py create mode 100755 build-android/upload-playstore.sh diff --git a/.gitignore b/.gitignore index 75e025f..4577565 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ config.sh *.jks *.pfx *.pkcs12 +/*.json # Generated by build scripts angle/ diff --git a/build-android/playstore_upload_script.py b/build-android/playstore_upload_script.py new file mode 100644 index 0000000..923eff6 --- /dev/null +++ b/build-android/playstore_upload_script.py @@ -0,0 +1,72 @@ +import sys, socket +from google.oauth2 import service_account +from googleapiclient.discovery import build + +PACKAGE_NAME = "org.godotengine.editor.v4" +TRACK = "alpha" +RELEASE_NAME = "Automated Release" +RELEASE_NOTES = "Automated closed testing release" + +def main(aab_path, nds_path, key_path): + scopes = ["https://www.googleapis.com/auth/androidpublisher"] + credentials = service_account.Credentials.from_service_account_file(key_path, scopes=scopes) + initial_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(900) + service = build("androidpublisher", "v3", credentials=credentials) + + print("Creating a new edit") + edit_request = service.edits().insert(body={}, packageName=PACKAGE_NAME) + edit = edit_request.execute() + edit_id = edit["id"] + + print(f"Uploading {aab_path}") + upload_request = service.edits().bundles().upload( + editId=edit_id, + packageName=PACKAGE_NAME, + media_body=aab_path, + media_mime_type="application/octet-stream" + ) + bundle_response = upload_request.execute() + version_code = bundle_response["versionCode"] + print(f"Uploaded AAB with versionCode: {version_code}") + + print(f"Uploading native debug symbols {nds_path}") + service.edits().deobfuscationfiles().upload( + editId=edit_id, + packageName=PACKAGE_NAME, + apkVersionCode=version_code, + deobfuscationFileType="nativeCode", + media_body=nds_path, + media_mime_type="application/octet-stream" + ).execute() + + print(f"Assigning version {version_code} to {TRACK} track") + service.edits().tracks().update( + editId=edit_id, + packageName=PACKAGE_NAME, + track=TRACK, + body={ + "releases": [{ + "name": f"{RELEASE_NAME} v{version_code}", + "versionCodes": [str(version_code)], + "status": "completed", + "releaseNotes": [{ + "language": "en-US", + "text": RELEASE_NOTES + }] + }] + } + ).execute() + + service.edits().commit(editId=edit_id, packageName=PACKAGE_NAME).execute() + print("Release uploaded and published successfully!") + socket.setdefaulttimeout(initial_timeout) + +if __name__ == "__main__": + if len(sys.argv) != 4: + print("Usage: python3 upload_playstore.py ") + sys.exit(1) + aab_path = sys.argv[1] + nds_path = sys.argv[2] + key_path = sys.argv[3] + main(aab_path, nds_path, key_path) diff --git a/build-android/upload-playstore.sh b/build-android/upload-playstore.sh new file mode 100755 index 0000000..0d2f40d --- /dev/null +++ b/build-android/upload-playstore.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +BASEDIR="$(pwd)" + +source ${BASEDIR}/config.sh + +VENV_DIR="${BASEDIR}/venv" +PYTHON_SCRIPT="${BASEDIR}/build-android/playstore_upload_script.py" +AAB_FILE="${BASEDIR}/out/android/tools/android_editor.aab" +NDS_FILE="${BASEDIR}/out/android/tools/android_editor_native_debug_symbols.zip" +JSON_KEY_FILE="${BASEDIR}/${GODOT_ANDROID_UPLOAD_JSON_KEY}" + +echo "Creating virtual environment" +rm -rf "$VENV_DIR" +python3 -m venv "$VENV_DIR" +source "$VENV_DIR/bin/activate" + +echo "Installing google-api-python-client" +pip install --upgrade google-api-python-client + +python3 "$PYTHON_SCRIPT" "$AAB_FILE" "$NDS_FILE" "$JSON_KEY_FILE" diff --git a/config.sh.in b/config.sh.in index 1cd1676..f149f1a 100644 --- a/config.sh.in +++ b/config.sh.in @@ -98,3 +98,6 @@ export GODOT_ANDROID_SIGN_KEYSTORE='' export GODOT_ANDROID_KEYSTORE_ALIAS='' # Password for the key used for signing the release build export GODOT_ANDROID_SIGN_PASSWORD='' +# Google Cloud Service Account JSON key with access to Play Console upload permissions +# (View app information + Release apps to production and/or testing.) +export GODOT_ANDROID_UPLOAD_JSON_KEY='' diff --git a/publish-release.sh b/publish-release.sh index 22a8e5e..2a5198a 100755 --- a/publish-release.sh +++ b/publish-release.sh @@ -176,6 +176,15 @@ else echo "Disabling NuGet package publishing as config.sh does not define the required data (NUGET_SOURCE, NUGET_API_KEY), or dotnet can't be found in PATH." fi +# Godot Android Editor + +if [ -d "deps/playstore_key.json" ]; then + echo "Publishing Android Editor to PlayStore..." + sh build-android/upload-playstore.sh +else + echo "Disabling Android Editor publishing as deps/playstore_key.json doesn't exist." +fi + # Godot Android library if [ -d "deps/keystore" ]; then