This is a tutorial of sorts, but unlike several of the tutorials on this website, it isn’t about making a game mechanic or project. Instead, it’s about a neat way to easily test and develop Godot apps on iOS, Android, or really any platform Godot supports, without needing to rebuild an entire project each time. Let’s jump right in!
This tutorial is written for Godot 3.X. While this method will likely work for Godot 4.0 as well, and potentially future editions of Godot past 4.0, it has not been tested!
Also, this tutorial is written assuming the reader has some Godot experience. That is not to say beginners cannot follow along though, it just isn’t as well explained as a beginner tutorial. This tutorial is written a little more quickly than some of my other tutorials.
The technique we’ll use for easy testing is actually a Godot supported feature, and in part is doable thanks to the way Godot projects are packaged and processed by the built executable.
When you export a Godot executable for desktop platforms for mobile, what Godot does is two fold:
- It gathers the executable and required data from the export templates, project settings, and puts it all together so that when you launch the game, it correctly loads.
- It bundles your game into a
.pckfile and places this
.pckfile in a location where the Godot executable knows where to find it. Then when the game is launched, this file is read and used for executing everything in the game.
This second step, bundling your game into a
.pck file, is the key! By loading
.pck files at runtime in a controlled and expected way, we can make an app for iOS and Android (as well as any platform Godot supports with file access) to dynamically load a
.pck file we give it outside of the bundled app itself. This allows us to make our game on platforms like Windows, export a
.pck file of the project, and as long as all the settings are correct, we can then drop the resulting
.pck file onto an iOS or Android device and test it without needing to recompile the app or anything!
Especially if you have a Windows machine but iOS devices (like I do), this can make it possible for you to develop and prototype iOS apps easily and without requiring a Mac device more than twice!
Because we are loading
.pck files, which can contain anything, there is a chance that if you load
.pck files that you will load dangerous projects. This is intended ONLY for development and is not recommended to use in production! I’ll cover this a bit more later, but wanted to make sure I was upfront with this now, as there is a potential security risk.
Now, there are a few limitations of this method we need to be aware of:
- We must use the same Godot version as the app we built. If the app on iOS or Android was built using Godot 3.4-stable, then we HAVE to use Godot 3.4-stable when generating the
.pckfiles it will load.
- The project settings cannot be modified once the iOS or Android app is built. You can use whatever project settings you want on your desktop machine when building the project and it’s
.pckfiles, but when you export and load the
.pck, the project settings of the iOS or Android app will be used not the ones from the
- This is especially important for input actions, autoload scripts, and anything else you can set in the project settings! The project settings are fixed once the iOS or Android app is built unless you rebuild the app.
- You can only use GDScript for scripting! This is because C# is compiled ahead of time for iOS (and Android?) and therefore requires a Mac.
- You have to download the export templates for iOS or Android and export the
.pckfile using that export template. This will be shown more in detail further below.
- There is no Godot debugger support! If your project crashes or has an error, there is no way to know what the issue was without writing your own debugging code you can see while running the project itself.
- Any limitations of
.pckfiles that are normally imposed (file size limits, file location conflicts, etc) are still present.
There are several things you can do though with
.pck files that are simply not possible or difficult to do otherwise:
- You can load any and all normal Godot assets like expected: 3D Meshes, Textures, Sprites, Scripts, Animations, Scenes, Audio, Music, etc.
- This is especially useful, as many files cannot normally be imported at runtime, like 3D meshes and scenes, without significant workarounds.
- You can use the Godot editor to setup your scene and code like normal, no custom tooling or anything required beyond the app itself.
- Because this method works on how Godot functions fundamentally, support for this method and it’s code is really solid
- Any advantages of
.pckfiles that I may have missed
So, let’s jump right in. First, we will need to make a loader project that we can deploy on iOS or Android that will load the
.pck files we give it. Let’s work on that first.
PCK Loader Project
First, download the following project: DOWNLOAD LINK
This project has a basic setup and all the code we’ll need to load the
.pck files. We’ll go over the code in just a second, but first open the project up using Godot 3 on the desktop platform of your choice. Once open, go ahead and take a look at the
Loader.tscn file in
Because of how PCK files are loaded, it’s extra important to keep a good folder structure for your project and the loader, as any files that have the same name and are stored in the same location relative to
res:// will be ignored when loaded dynamically, potentially causing issues. For this reason, all of the files for the project loader are in a folder called
res://Loader_Resources as it’s unlikely for any project to have the same folder name.
The scene is pretty simple, just a couple buttons and labels. One button is for loading the PCK files, while another is for making a default config file, which is how we’ll tell the project which PCK files to load and which to ignore. Finally, the label on top is the name of the project, while the label on bottom is a status label that can help us if something in the loading process goes wrong.
Let’s look at the only script needed for the loader:
Loader.gd. Go ahead and open it up and you should find something like this:
var status_label : Label;
var load_button : Button;
var default_button : Button;
load_button = get_node("VBoxContainer/HBoxContainer/Load_Button");
load_button.connect("pressed", self, "on_load_pressed");
default_button = get_node("VBoxContainer/HBoxContainer/Make_Default_Button");
default_button.connect("pressed", self, "on_make_default_pressed");
status_label = get_node("VBoxContainer/Status");
status_label.text = "Status:"
var dir = Directory.new();
if (dir.dir_exists("user://") == false):
status_label.text += "\nMade user folder";
status_label.text += "\nFound user folder";
# make the load folder
if (dir.dir_exists("user://load") == false):
status_label.text += " - Made load folder";
status_label.text += " - Found load folder";
status_label.text = "status:";
# Get the start scene
var startScenePath = "";
var startConfig = ConfigFile.new();
var file_obj = File.new();
if (file_obj.file_exists("user://config.cfg") == true):
status_label.text += "\nFound config.cfg";
status_label.text += "\nCould not find config.cfg";
var startError = startConfig.load("user://config.cfg");
if (startError != OK):
print ("Error - could not load start config!");
status_label.text += "\nCould not load config.cfg";
startScenePath = startConfig.get_value("Settings", "Launch_Scene", "res://main.tscn");
# Load the PCK file(s)
var pck_files_loaded = 0;
var pck_file_obj = File.new();
if (startConfig.has_section("PCK_Files") == true):
var file_keys = startConfig.get_section_keys("PCK_Files");
for key in file_keys:
var file_location = "user://load/" + startConfig.get_value("PCK_Files", key, null);
if (file_location != null):
if (pck_file_obj.file_exists(file_location) == true):
pck_files_loaded += 1;
status_label.text += "\nCould not find PCK with name: " + startConfig.get_value("PCK_Files", key, "<missing>");
if (pck_files_loaded > 0):
status_label.text += "\nLoaded PCK files! Changing scene...";
status_label.text += "\nLoad fail: Could not find ANY PCK files!"
# Load the start scene
if (pck_file_obj.file_exists(startScenePath) == true):
# give it a 1/4 second
status_label.text += "\nCould not find start scene: " + startScenePath;
status_label.text = "status:";
var startConfig = ConfigFile.new();
startConfig.set_value("Settings", "Launch_Scene", "res://Main.tscn");
startConfig.set_value("PCK_Files", "Main", "Main.pck");
status_label.text += "\nMade default config";
That’s all the code for the project! Let’s quickly go through the code and the important parts:
_ready function is pretty simple, mostly just getting the nodes and assigning them to their respective class variables. We also connect the pressed signals for the buttons to their respective functions, so it executes when the button is pressed. The only thing really to note is line
18 , where we call
make_project_folder_if_not_exist . This is required because, by default, if we try to access a folder to see if a file exists, but the folder does not exist, then we get a crash. To avoid this, we call the
make_project_folder_if_not_exist function in
_ready so it’s for sure present.
make_project_folder_if_not_exist function makes a new Directory object and then checks to see if the
user:// folder exists or not. On desktop platforms, this folder is made automatically when the game is first launched, but on iOS (and maybe Android?) this folder does not exist by default, so we need to make it ourselves. If the folder does not exist, then we call the
make_dir_recursive function and add text to the status label so we know it was made.
Likewise, we repeat this process for the
user://load folder, which is where we are going to store the actual
.pck files. Using
user://load to hold the pck files is a style choice I made, simply because I wanted to have all the PCK files in one place without the config file (described in detail below) also in the same folder.
Next, let’s skip the
on_load_pressed function for just a second and look at the
on_make_default_pressed function instead. This function will be called whenever the make default PCK config button is pressed by the user.
First, the function resets the status and makes a new ConfigFile object. The ConfigFile object is a really handy class that allows us to store data in a text-based file, and is the same class used for the Godot project settings. What is nice about it is that it supports sections, and these sections then have key-value pairs for data, similar to a dictionary. While we could use JSON here, I find the simplicity of the ConfigFile API to be useful for quickly getting everything implemented.
Once we make the ConfigFile, we store two values. The first value is in the
Settings section and is called
Launch_Scene. This value points to a scene under
res:// (in this case
res://Main.tscn). This setting is going to tell the PCK loader project which file to try and change to once it’s loaded all the PCK files we have given it. What is important to note here is that we want to use
res:// and point it to a scene with the same path as it would have if we were using
get_tree().change_scene("res://path_here"), because when we load a
.pck file, all it’s resources get dumped into
Next, we make a section called
PCK_Files and with a key-value pair called
Main.pck. The names here are actually optional, what is important is the
PCK_Files section. Any PCK files we have, we’ll store them in this
PCK_Files section where the value of each key-value pair is the path to the PCK file relative to
user://load (the key in the key-value pair is ignored).
For example, with a key-value pair of
Main.pck , the loader is going to try and load a PCK file called
Main.pck in the
user://loader/ folder. The file path it will use is
user://loader/Main.pck and that is where it will expect the file to be. Don’t worry if it’s a little confusing, I’ll walk through it soon when we load our first
After setting the default key-value pairs, we save the ConfigFile at
Finally, we set the status to inform the user that we have made the default config file.
Finally, let’s look at the
on_load_pressed function. This function is called whenever the load PCK button is pressed and is where all the magic happens.
First, we clear the status label, and this is important because we’ll use the status label on each step to say whether the step was successful, or whether there was an error. Since we do not have the Godot debugger or anything like that at runtime, this label is the only way to know if something went wrong.
The code is broken down into two parts, loading the ConfigFile and start scene, and loading the PCK files.
For loading the PCK file, we first make a variable that will store the path to the start scene and make a new ConfigFile. Then, we need to make a File object to see if a file exists at
user://config.cfg, which is where we save the ConfigFile by default and where the project expects it to be. If the file exists, we note it’s existence in the status label. If the file does NOT exist, then we note it’s absence and return so we do not execute any further code.
Once we have confirmed the file exists at
user://config.cfg, we then load it using the
load function in the ConfigFile we made earlier. We store the error and check to see if the load was not OK. If the load was not OK, then we note this in the status label and return.
If the load did return a code of OK, then we get the
Launch_Scene key-value pair in the
Settings section and cache it for later.
That covers lines
59, which is for getting the ConfigFile and start scene. Let’s look at lines
80 next, which loads the PCK files.
First, we make a variable to track how many PCK files we have loaded. While not strictly required, this will allow us to know if we haven’t loaded any PCK files. Next, we make another File object so we can check if the PCK files in the
PCK_Files section of the ConfigFile exist.
We could optimize this a bit by reusing the File object that we used for checking if the ConfigFile exists, but for readability, I opted to use a new File object
Next we check to see if the
PCK_Files section exists and if it does, we get all the keys for all the key-value pairs in the
PCK_Files section. Then we loop through each of the key-value pairs using a for loop. In each loop, we construct the file location at
user://load/ and check if thefile exists. If it does, then we call
ProjectSettings.load_resource_pack, which will load the PCK file and dump all it’s resources in
res://. Then we add one to the variable for tracking the number of PCK files loaded, so we know at least one PCK file has been loaded. If the check to see if the PCK file exists fails, then we add an error label to the status text so we know which PCK file failed to load. We then do this for each PCK file in the
After we have looped through all PCK files, we check to see if we have loaded more than once PCK file. If we have, then we add some text to the status label to inform the user we have loaded the PCK files and will be changing scenes. If the PCK file count is zero though, then we add some text to the status label to inform the user no PCK files were load and return to stop executing the rest of the function.
Next, let’s look at lines
90. First, we check to see if the starter scene that we loaded from the PCK file exists. If it does, then we yield for 1/4 of a second so the user can read the status label if they need, and then call
get_tree().change_scene and pass the starter scene we cached from the ConfigFile. If the cached start scene does not exist when we check for it, then we add some text to the status label to inform the user the starter scene could not be found.
That’s all the code! If it’s a little confusing, please do not hesitate to reach out on the Godot Community Forums or on Twitter and I’ll do my best to explain (@TwistedTwigleg is my account on both).
Next, let’s look at what we’ll need to do for exporting the project. I’ll be showing the steps for exporting for iOS, as that’s what I’m using, but the same steps should be similar for Android or other platforms.
First, go to “Project” on the top right and then click “Export” from the drop down. This will bring up the project export configurations. If you have not already, go ahead and download the export templates by clicking the red text at the bottom of the export configurations window.
Next, click the “Add” near the top middle of the export configurations window and select iOS. This is going to bring up a bunch of settings, several of which are required to be filled in. First, on the “App Store Team ID” property, input your app store team ID or something like
12345, as we can configure this later through XCode if needed.
Then, scroll down to the identifier and set it to something like
com.username.pckloader . The name isn’t super important, it just needs to be unique and in the same general format as the example.
Next is a very important step that is optional for exporting to iOS, but required for the PCK loader project to work. Scroll down and under the user data section, make sure the
Accessible From Files App and
Accessible from iTunes Sharing checkboxes are both enabled! Without this, we cannot make a folder in the
user:// directory nor load PCK files at runtime.
Once that is done, keep scrolling down until you get to required icons. Go ahead and click the little folder icon to open the file browser. Then set the icons to the icons in the
Loader_Resources folder, matching each file size to the correct icon file. For example,
Iphone 120 X 120 needs
Okay, now you should be ready to export. Go ahead and set the ExportPath (just below the Runnable toggle) to whatever folder you want to export and then click the “Export Project” button on the bottom of the export configuration window. Confirm the export location and press “Save”.
This will generate an XCode project for you, assuming there was no errors during export. You can check for errors by looking at the Output panel in the Godot editor. If you are on a Mac, you may get errors if your team ID isn’t set correctly, but it should still generate the XCode project.
Now that you have an XCode project, this is where you must have a Mac computer for the next step. This is the only time you will need a Mac computer though! If you do not have a Mac on hand, there are services online where you can temporarily rent a Mac, or if you know someone with a Mac, you can ask them to build the app for you. The building of the PCK loader is a just a one time thing.
Thankfully, the process is pretty simple once you have a Mac setup and ready. The exact process varies a bit and I do not have a Mac with my while writing to have an exact set of steps, but here’s the general outline of what needs to be done.
Download and install XCode if you do not already have it, and then navigate to the XCode project exported by Godot. Once it has opened up, go ahead and navigate to the app settings and set the Team to your Apple account. You can use a free apple account for development as long as it’s only on your device, you just cannot upload to the App store through a free account. After you have set the team, this should change the App Store Team ID automatically and handle the code signing, so it can compile the XCode project.
Next, you need to plug in your iOS device and tell it to “Trust this computer” so you can upload the iOS app to the device. (Not sure on the exact process for this for online services). Once you have trusted the Mac, you should be able to set the build output to build on the plugged-in iOS device. Once the device name shows up on the top left-ish of the XCode window, go ahead and press the compile button (looks like a play button). This will start the compiling process and it should compile and deploy the app successfully onto your iOS device!
If you are getting compiling errors, I would highly recommend doing some quick Google searches on the errors and the export process for iOS from Godot! It may be I missed a step or incorrectly explained something.
Also, if you get a crash when running the app using the Mono version of Godot and this project, especially if the crash log shows something wrong with the GDNative Mono module, you may need to add a dummy C# Script, as I found that fixed the crash. To do this, open the Godot project up again, add a C# script to one of the nodes, do not change anything from the built-in template, and then export the XCode project again using the steps above. Then if you compile the app on XCode, it should no longer have the Mono errors.
Once the app is successfully compiled, it should look something like this on your iOS device!
If you have got to this point on your iOS device, then you are done! Now you no longer need a Mac computer and can start developing iOS apps without a Mac computer!
You will still need a Mac computer to deploy your app onto the App store however! Again, this method is ONLY for development purposes, it is not intended for use in a released app.
Now, let’s load a sample PCK file to make sure it works. Go ahead and download the following PCK file, which is a slightly modified version of the MultiTouch demo from the Godot demo repository, but with a 3D model of an onion by Lassi Kaukonen on SketchFab to show that 3D mesh and texture loading works.
The Onion model used is made by Lassi Kaukonen and is licensed under CC BY 4.0, which you can find here: https://creativecommons.org/licenses/by/4.0/
Once downloaded, you will see the zip contains two files: A
.pck file called
Main.pck and a
config.cfg file. If you open the config.cfg file, you can see it mentions a PCK file called
Main.pck, and the start scene of
res://Main.tscn. This is the main scene of the MultiTouch demo, and is the correct name for the PCK, so it should work as expected.
To get these files on your device, there is a few ways to do it. Again, I will write this for iOS, but it should also work for Android with little to no modifications.
The first way is to email yourself the files. You can zip both files up and send them to an email address that the iOS device is connected to. Then you can download the files and go to the Files app. Select both files and click the arrow to see “Locations” and select “On My iPad/iPhone”. Select “On My iPad/iPhone” and navigate to the “iOS_PCK_Loader_Project” folder. Click the folder to open it and paste the files there. It may ask you if you want to replace “config.cfg” and if it does, hit “replace” to replace the file with the new one. Then move the
Main.pck file into the
load subfolder. When done, it should look something like this:
(I initially called the project “IOS_Test_PCK_Loader_Project” as I was not sure if it was going to work – the download project is correctly name)
Then go into the app and press the load PCK file. If done correctly, you should see four onions which you can rotate by moving your finger around!
The other way is a little simpler and doesn’t require using your email, however it only works on Windows and Mac. Install iTunes on your Windows or Mac device. Once iTunes is installed, plug in your device and tell it to trust the computer. Open up iTunes and click the little device icon once it shows up:
Then from the options on the left side, select “File Transfer”. This will change the window to show the apps you have installed. Scroll down until you find the “iOS_PCK_Loader_Project” and select it. Then drag and drop the
config.cfg files into the window. When done, it should look something like this:
Finally, go into the Files app on your device, press the arrow icon on the top left, select “On My iPad/iPhone” and then navigate to the “iOS_PCK_Loader_Project” folder. Once in the folder, drag and drop “Main.pck” into the
load subfolder. When done, it should look something like this:
Then go into the app and press the load PCK file! If done correctly, you will see the four onions which you can rotate!
Now of course, you are not limited to just being able to upload the PCK file I provided, you can load any PCK file that has been exported for iOS! This makes development MUCH easier and because it is running natively, whatever performance it has is directly representative of the performance you can expect if you built the project using XCode instead of exporting a PCK file and loading it in the PCK loader.
However, I should note that not all PCK files will work. For the PCK loader to work correctly, the PCK file you are loading HAS to be exported with iOS in mind. To do this, make sure you have the export templates for Godot installed, and in the export configuration settings make an iOS configuration. similar to when you exported for the Mac.
Like before, set the app store team ID to something like
1234 and set the identifier to something like
com.placeholder.example and set the export icons to a valid image (it doesn’t matter which, we won’t be using them). Once that is all done, you should be able to export. However, instead of pressing “Export Project”, instead hit “Export PCK/Zip”. This will bring up a file select box so you can select where the export will go. Make sure to have the extension set to
.pck ,as the PCK loader project cannot load zip files.
Then you can press
Save and navigate to the PCK file it exported. Then you can follow the process above to get the PCK file on your device! You may need to modify the
Config.cfg file if you have named your PCK file something other than
Main.pck and your opening scene is not called
Main.tscn. If so, just download the config file (either from the link above or from your device after making the default one using the button), and open the file up with a text editor. Then you can change the values to point to whatever you need!
(A little test app I’ve been working on to validate the PCK loader workflow – it isn’t finished or available for download at this time but the development process is working great!)
That concludes this little tutorial of sorts! This really makes developing on iOS and Android both faster and easier. Especially for me, I was looking to find a way to develop on iOS easily without having to rely on a Mac for every single build (I primarily use Windows) and this solution is a great way around it. It is actually faster to export the PCK file and get it onto the iOS device through iTunes than it is to build the XCode project, at least for me, so it’s a win in speed as well.
Another nice thing with this setup is that it allows those without access to a Mac to build iOS apps more easily, as long as you can have someone build the PCK loader and/or rent a Mac temporarily to build the PCK loader app. Again, this will not let you deploy the app on the app store, you will need an Apple computer for that, but you can develop the majority of the app using the PCK loader and then just use a Mac for the final releasing steps.