Skip to content

Commit 11a1230

Browse files
committed
Add support for exporting Meta's prebuilt apks
1 parent bb01430 commit 11a1230

File tree

19 files changed

+324823
-37
lines changed

19 files changed

+324823
-37
lines changed

.github/workflows/build-addon-on-push.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,8 @@ jobs:
9898
- name: Create extension library
9999
run: |
100100
cd godot_meta_toolkit
101-
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} build_profile=thirdparty/godot_cpp_build_profile/build_profile.json
102-
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }} build_profile=thirdparty/godot_cpp_build_profile/build_profile.json
101+
scons platform=${{ matrix.platform }} target=template_debug ${{ matrix.flags }} custom_api_file=thirdparty/godot_cpp_gdextension_api/extension_api.json build_profile=thirdparty/godot_cpp_build_profile/build_profile.json
102+
scons platform=${{ matrix.platform }} target=template_release ${{ matrix.flags }} custom_api_file=thirdparty/godot_cpp_gdextension_api/extension_api.json build_profile=thirdparty/godot_cpp_build_profile/build_profile.json
103103
cd ..
104104
- name: Save Godot build cache
105105
uses: ./godot_meta_toolkit/thirdparty/godot-cpp/.github/actions/godot-cache-save
@@ -124,6 +124,7 @@ jobs:
124124
uses: actions/checkout@v4
125125
with:
126126
path: godot_meta_toolkit
127+
submodules: recursive
127128
- name: Download all workflow run artifacts
128129
uses: actions/download-artifact@v4
129130
- name: Download Meta Platform SDK
@@ -141,6 +142,13 @@ jobs:
141142
distribution: "adopt"
142143
- name: Validate Gradle wrapper
143144
uses: gradle/actions/wrapper-validation@v3
145+
- name: Set up Python (for SCons)
146+
uses: actions/setup-python@v5
147+
with:
148+
python-version: "3.x"
149+
- name: Install scons
150+
run: |
151+
python -m pip install scons==4.0.0
144152
- name: Copy Android binaries
145153
run: |
146154
mkdir -p godot_meta_toolkit/toolkit/src/main/libs/debug/arm64-v8a/arm64-v8a
@@ -152,6 +160,9 @@ jobs:
152160
run: |
153161
cd godot_meta_toolkit
154162
./gradlew build
163+
scons --directory=thirdparty/godot platform=android target=template_debug arch=arm64
164+
scons --directory=thirdparty/godot platform=android target=template_release arch=arm64
165+
./gradlew generatePrebuiltApks
155166
cd ..
156167
- name: Create Godot Meta Toolkit Addon
157168
run: |

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "thirdparty/godot-cpp"]
22
path = thirdparty/godot-cpp
33
url = https://github.com/godotengine/godot-cpp
4+
[submodule "thirdparty/godot"]
5+
path = thirdparty/godot
6+
url = https://github.com/godotengine/godot.git

build.gradle

Lines changed: 215 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,30 @@ plugins {}
1818

1919
apply from: 'config.gradle'
2020

21+
ext {
22+
addonPrebuiltDir = "demo/addons/godot_meta_toolkit/.build_template/prebuilt"
23+
24+
godotDir = "thirdparty/godot"
25+
godotJavaDir = "${godotDir}/platform/android/java/"
26+
27+
godotAppStandardManifestDir = "${godotJavaDir}/app/src/standard/"
28+
godotAppOutputDir = "${godotJavaDir}/app/build/outputs/apk/standard/"
29+
30+
toolkitAarOutputDir = "toolkit/build/outputs/aar/"
31+
toolkitDebugAar = "${toolkitAarOutputDir}/godot_meta_toolkit-debug.aar"
32+
toolkitReleaseAar = "${toolkitAarOutputDir}/godot_meta_toolkit-release.aar"
33+
}
34+
2135
task clean(type: Delete) {
2236
delete rootProject.buildDir
2337

2438
// Delete the bin directory for the 'godot_meta_toolkit' addon
2539
delete("demo/addons/godot_meta_toolkit/.bin")
2640

41+
dependsOn 'cleanPrebuiltApks'
42+
43+
dependsOn 'cleanScons'
44+
2745
dependsOn ':toolkit:clean'
2846
}
2947

@@ -39,10 +57,19 @@ task buildToolkit {
3957
}
4058

4159
/**
42-
* Build the scons artifacts for the project
60+
* Generate the addon by building the 'toolkit' module and the prebuilt apks.
4361
*/
44-
task buildSconsArtifacts {
45-
// Find scons' executable path
62+
task generateAddon {
63+
dependsOn buildToolkit
64+
65+
// Generate the prebuilt apks
66+
dependsOn ':generatePrebuiltApks'
67+
}
68+
69+
/*
70+
* Find scons executable path
71+
*/
72+
def getSconsExecutableFile() {
4673
File sconsExecutableFile = null
4774
def sconsName = "scons"
4875
def sconsExts = (org.gradle.internal.os.OperatingSystem.current().isWindows()
@@ -66,40 +93,206 @@ task buildSconsArtifacts {
6693
}
6794
}
6895

96+
return sconsExecutableFile
97+
}
98+
99+
/**
100+
* Utility method to create common scons tasks for use by other tasks.
101+
*/
102+
def createSconsTasks(File sconsExecutableFile, boolean clean) {
103+
def defaultArgs = [
104+
"--directory=.",
105+
"custom_api_file=thirdparty/godot_cpp_gdextension_api/extension_api.json",
106+
"build_profile=thirdparty/godot_cpp_build_profile/build_profile.json",
107+
]
108+
109+
if (clean) {
110+
defaultArgs << "-c"
111+
}
112+
113+
def taskPrefix = (clean ? "clean" : "build")
114+
115+
// Android.
116+
tasks.create(name: "${taskPrefix}GodotMetaToolkitAndroidArm64Debug", type: Exec) {
117+
executable sconsExecutableFile.absolutePath
118+
args defaultArgs + ["platform=android", "target=template_debug", "arch=arm64"]
119+
}
120+
tasks.create(name: "${taskPrefix}GodotMetaToolkitAndroidArm64Release", type: Exec) {
121+
executable sconsExecutableFile.absolutePath
122+
args defaultArgs + ["platform=android", "target=template_release", "arch=arm64"]
123+
}
124+
125+
// Desktop.
126+
tasks.create(name: "${taskPrefix}GodotMetaToolkitDesktopDebug", type: Exec) {
127+
executable sconsExecutableFile.absolutePath
128+
args defaultArgs + ["target=template_debug"]
129+
}
130+
tasks.create(name: "${taskPrefix}GodotMetaToolkitDesktopRelease", type: Exec) {
131+
executable sconsExecutableFile.absolutePath
132+
args defaultArgs + ["target=template_release"]
133+
}
134+
}
135+
136+
/**
137+
* Build the scons artifacts for the project
138+
*/
139+
task buildSconsArtifacts {
140+
File sconsExecutableFile = getSconsExecutableFile()
141+
69142
// Using `doFirst` so the exception doesn't happen until this task actually runs.
70143
doFirst {
71144
if (sconsExecutableFile == null) {
72-
throw new GradleException("Unable to find executable path for the '$sconsName' command.")
145+
throw new GradleException("Unable to find executable path for the 'scons' command.")
73146
} else {
74-
logger.debug("Found executable path for $sconsName: ${sconsExecutableFile.absolutePath}")
147+
logger.debug("Found executable path for scons: ${sconsExecutableFile.absolutePath}")
75148
}
76149
}
77150

78151
if (sconsExecutableFile != null) {
79-
// Build the GDExtension library for Android.
80-
tasks.create(name: "buildGodotMetaToolkitAndroidArm64Debug", type: Exec) {
81-
executable sconsExecutableFile.absolutePath
82-
args "--directory=.", "platform=android", "target=template_debug", "arch=arm64", "build_profile=thirdparty/godot_cpp_build_profile/build_profile.json"
83-
}
84-
tasks.create(name: "buildGodotMetaToolkitAndroidArm64Release", type: Exec) {
85-
executable sconsExecutableFile.absolutePath
86-
args "--directory=.", "platform=android", "target=template_release", "arch=arm64", "build_profile=thirdparty/godot_cpp_build_profile/build_profile.json"
87-
}
152+
createSconsTasks(sconsExecutableFile, false)
88153

154+
// Android.
89155
dependsOn 'buildGodotMetaToolkitAndroidArm64Debug'
90156
dependsOn 'buildGodotMetaToolkitAndroidArm64Release'
91157

92-
// Build the GDExtension library for desktop.
93-
tasks.create(name: "buildGodotMetaToolkitDesktopDebug", type: Exec) {
158+
// Desktop.
159+
dependsOn 'buildGodotMetaToolkitDesktopDebug'
160+
dependsOn 'buildGodotMetaToolkitDesktopRelease'
161+
}
162+
}
163+
164+
/**
165+
* Scons clean for the project
166+
*/
167+
task cleanScons {
168+
File sconsExecutableFile = getSconsExecutableFile()
169+
170+
// Using `doFirst` so the exception doesn't happen until this task actually runs.
171+
doFirst {
172+
if (sconsExecutableFile == null) {
173+
throw new GradleException("Unable to find executable path for the 'scons' command.")
174+
} else {
175+
logger.debug("Found executable path for scons: ${sconsExecutableFile.absolutePath}")
176+
}
177+
}
178+
179+
if (sconsExecutableFile != null) {
180+
createSconsTasks(sconsExecutableFile, true)
181+
182+
// Android.
183+
dependsOn 'cleanGodotMetaToolkitAndroidArm64Debug'
184+
dependsOn 'cleanGodotMetaToolkitAndroidArm64Release'
185+
186+
// Desktop.
187+
dependsOn 'cleanGodotMetaToolkitDesktopDebug'
188+
dependsOn 'cleanGodotMetaToolkitDesktopRelease'
189+
}
190+
}
191+
192+
/**
193+
* Cleans the generated prebuilt apks.
194+
*/
195+
task cleanPrebuiltApks(type: Delete) {
196+
def gradlewExecutablePath = "./gradlew" + (org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : "")
197+
File gradlewExecutable = file(gradlewExecutablePath)
198+
199+
doFirst {
200+
if (!gradlewExecutable.exists()) {
201+
throw new GradleException("Unable to find executable path for the 'gradlew' script.")
202+
}
203+
}
204+
205+
delete(godotAppStandardManifestDir)
206+
207+
delete(addonPrebuiltDir)
208+
209+
tasks.create(name: "cleanGodot", type: Exec) {
210+
executable gradlewExecutable.absolutePath
211+
args "-p", godotJavaDir, "clean"
212+
}
213+
dependsOn 'cleanGodot'
214+
}
215+
216+
/**
217+
* Copy the prebuilt manifest to the Godot::app module. The manifest contains additional meta-data
218+
* that this plugin modifies at export time based on the project configuration.
219+
*/
220+
task copyPrebuiltManifestToGodotApp(type: Copy) {
221+
// Copy the prebuilt manifest
222+
file(godotAppStandardManifestDir).mkdirs()
223+
224+
from "./prebuilt/AndroidManifest.xml"
225+
into "./thirdparty/godot/platform/android/java/app/src/standard/"
226+
}
227+
228+
/**
229+
* Copy the generated prebuilt apks to the addon directory.
230+
*/
231+
task copyPrebuiltApksToAddon(type: Copy) {
232+
from godotAppOutputDir
233+
into addonPrebuiltDir
234+
include '**/*.apk'
235+
}
236+
237+
/**
238+
* Generate the prebuilt apks.
239+
*/
240+
task generatePrebuiltApks() {
241+
def gradlewExecutablePath = "./gradlew" + (org.gradle.internal.os.OperatingSystem.current().isWindows() ? ".bat" : "")
242+
File gradlewExecutable = file(gradlewExecutablePath)
243+
244+
File sconsExecutableFile = getSconsExecutableFile()
245+
246+
doFirst {
247+
if (!gradlewExecutable.exists()) {
248+
throw new GradleException("Unable to find executable path for the 'gradlew' script.")
249+
}
250+
}
251+
252+
if (sconsExecutableFile != null && sconsExecutableFile.exists()) {
253+
tasks.create(name: "buildGodotAndroidArm64Debug", type: Exec) {
94254
executable sconsExecutableFile.absolutePath
95-
args "--directory=.", "target=template_debug", "build_profile=thirdparty/godot_cpp_build_profile/build_profile.json"
255+
args "--directory=${godotDir}", "platform=android", "target=template_debug", "arch=arm64"
96256
}
97-
tasks.create(name: "buildGodotMetaToolkitDesktopRelease", type: Exec) {
257+
258+
tasks.create(name: "buildGodotAndroidArm64Release", type: Exec) {
98259
executable sconsExecutableFile.absolutePath
99-
args "--directory=.", "target=template_release", "build_profile=thirdparty/godot_cpp_build_profile/build_profile.json"
260+
args "--directory=${godotDir}", "platform=android", "target=template_release", "arch=arm64"
100261
}
262+
}
101263

102-
dependsOn 'buildGodotMetaToolkitDesktopDebug'
103-
dependsOn 'buildGodotMetaToolkitDesktopRelease'
264+
tasks.create(name: "assemblePrebuiltDebugApk", type: Exec) {
265+
dependsOn 'copyPrebuiltManifestToGodotApp'
266+
dependsOn ':toolkit:assembleDebug'
267+
268+
if (sconsExecutableFile != null && sconsExecutableFile.exists()) {
269+
dependsOn 'buildGodotAndroidArm64Debug'
270+
}
271+
executable gradlewExecutable.absolutePath
272+
args "-p",
273+
godotJavaDir,
274+
":app:assembleStandardDebug",
275+
"-Pplugins_remote_binaries=org.godotengine:godot-openxr-vendors-meta:$versions.openxrVendorsVersion",
276+
"-Pplugins_local_binaries=${file(toolkitDebugAar).absolutePath}"
277+
}
278+
279+
tasks.create(name: "assemblePrebuiltReleaseApk", type: Exec) {
280+
dependsOn 'copyPrebuiltManifestToGodotApp'
281+
dependsOn ':toolkit:assembleRelease'
282+
283+
if (sconsExecutableFile != null && sconsExecutableFile.exists()) {
284+
dependsOn 'buildGodotAndroidArm64Release'
285+
}
286+
executable gradlewExecutable.absolutePath
287+
args "-p",
288+
godotJavaDir,
289+
":app:assembleStandardRelease",
290+
"-Pplugins_remote_binaries=org.godotengine:godot-openxr-vendors-meta:$versions.openxrVendorsVersion",
291+
"-Pplugins_local_binaries=${file(toolkitReleaseAar).absolutePath}"
104292
}
105-
}
293+
294+
dependsOn 'assemblePrebuiltDebugApk'
295+
dependsOn 'assemblePrebuiltReleaseApk'
296+
297+
finalizedBy 'copyPrebuiltApksToAddon'
298+
}

config.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ ext {
66
targetSdk : 34,
77
javaVersion : JavaVersion.VERSION_17,
88
kotlinVersion : '1.9.20',
9-
ndkVersion : '23.2.8568313'
9+
ndkVersion : '23.2.8568313',
10+
openxrVendorsVersion : '3.1.2-stable'
1011
]
1112

1213
libraries = [
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
.bin/
2+
.build_template/
23
build/
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://c355gwn2kxs6b

demo/main.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://cyo458tqe4b40

demo/main.tscn

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[gd_scene load_steps=17 format=3 uid="uid://c0ol8en13wpk3"]
22

3-
[ext_resource type="Script" path="res://main.gd" id="1_t3hrc"]
4-
[ext_resource type="Script" path="res://raycast.gd" id="2_5nsls"]
3+
[ext_resource type="Script" uid="uid://cyo458tqe4b40" path="res://main.gd" id="1_t3hrc"]
4+
[ext_resource type="Script" uid="uid://7u8mv76m1kkw" path="res://raycast.gd" id="2_5nsls"]
55
[ext_resource type="Texture2D" uid="uid://cmm67scocnrpg" path="res://icon.svg" id="3_qj576"]
66

77
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_h1cjv"]

demo/project.godot

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ config_version=5
1212

1313
config/name="Godot Meta Toolkit Demo"
1414
run/main_scene="res://main.tscn"
15-
config/features=PackedStringArray("4.3", "GL Compatibility")
15+
config/features=PackedStringArray("4.4", "GL Compatibility")
1616
config/icon="res://icon.svg"
1717

18+
[debug]
19+
20+
settings/stdout/verbose_stdout=true
21+
1822
[rendering]
1923

2024
renderer/rendering_method="gl_compatibility"

demo/raycast.gd.uid

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
uid://7u8mv76m1kkw

0 commit comments

Comments
 (0)