#include "export_plugin.h"
#include "logo_svg.gen.h"
#include "run_icon_svg.gen.h"
#include "core/io/json.h"
#include "core/io/plist.h"
#include "core/string/translation.h"
#include "editor/editor_node.h"
#include "editor/editor_paths.h"
#include "editor/editor_string_names.h"
#include "editor/export/editor_export.h"
#include "editor/export/lipo.h"
#include "editor/export/macho.h"
#include "editor/import/resource_importer_texture_settings.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/themes/editor_scale.h"
#include "modules/modules_enabled.gen.h"
#ifdef MODULE_SVG_ENABLED
#include "modules/svg/image_loader_svg.h"
#endif
void EditorExportPlatformIOS::get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) const { … }
Vector<EditorExportPlatformIOS::ExportArchitecture> EditorExportPlatformIOS::_get_supported_architectures() const { … }
struct IconInfo { … };
static const IconInfo icon_infos[] = …;
struct APIAccessInfo { … };
static const APIAccessInfo api_info[] = …;
struct DataCollectionInfo { … };
static const DataCollectionInfo data_collect_type_info[] = …;
static const DataCollectionInfo data_collect_purpose_info[] = …;
String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const { … }
void EditorExportPlatformIOS::_notification(int p_what) { … }
bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const { … }
void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options) const { … }
void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) { … }
String EditorExportPlatformIOS::_get_additional_plist_content() { … }
String EditorExportPlatformIOS::_get_linker_flags() { … }
String EditorExportPlatformIOS::_get_cpp_code() { … }
void EditorExportPlatformIOS::_blend_and_rotate(Ref<Image> &p_dst, Ref<Image> &p_src, bool p_rot) { … }
Error EditorExportPlatformIOS::_export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir) { … }
Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) { … }
Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata) { … }
struct CodesignData { … };
Error EditorExportPlatformIOS::_codesign(String p_file, void *p_userdata) { … }
struct PbxId { … };
struct ExportLibsData { … };
bool EditorExportPlatformIOS::_archive_has_arm64(const String &p_path, uint32_t *r_cputype, uint32_t *r_cpusubtype) const { … }
int EditorExportPlatformIOS::_archive_convert_to_simulator(const String &p_path) const { … }
void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const { … }
Error EditorExportPlatformIOS::_convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const { … }
void EditorExportPlatformIOS::_add_assets_to_project(const String &p_out_dir, const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) { … }
Error EditorExportPlatformIOS::_copy_asset(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const String &p_asset, const String *p_custom_file_name, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { … }
Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) { … }
Error EditorExportPlatformIOS::_export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets) { … }
Vector<String> EditorExportPlatformIOS::_get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const { … }
Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset> &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector<IOSExportAsset> &r_exported_assets, bool p_debug) { … }
Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags) { … }
Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, BitField<EditorExportPlatform::DebugFlags> p_flags, bool p_simulator, bool p_oneclick) { … }
bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates, bool p_debug) const { … }
bool EditorExportPlatformIOS::has_valid_project_configuration(const Ref<EditorExportPreset> &p_preset, String &r_error) const { … }
int EditorExportPlatformIOS::get_options_count() const { … }
String EditorExportPlatformIOS::get_options_tooltip() const { … }
Ref<ImageTexture> EditorExportPlatformIOS::get_option_icon(int p_index) const { … }
String EditorExportPlatformIOS::get_option_label(int p_index) const { … }
String EditorExportPlatformIOS::get_option_tooltip(int p_index) const { … }
bool EditorExportPlatformIOS::is_package_name_valid(const String &p_package, String *r_error) const { … }
#ifdef MACOS_ENABLED
bool EditorExportPlatformIOS::_check_xcode_install() {
static bool xcode_found = false;
if (!xcode_found) {
Vector<String> mdfind_paths;
List<String> mdfind_args;
mdfind_args.push_back("kMDItemCFBundleIdentifier=com.apple.dt.Xcode");
String output;
Error err = OS::get_singleton()->execute("mdfind", mdfind_args, &output);
if (err == OK) {
mdfind_paths = output.split("\n");
}
for (const String &found_path : mdfind_paths) {
xcode_found = !found_path.is_empty() && DirAccess::dir_exists_absolute(found_path.strip_edges());
if (xcode_found) {
break;
}
}
}
return xcode_found;
}
void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
EditorExportPlatformIOS *ea = static_cast<EditorExportPlatformIOS *>(ud);
while (!ea->quit_request.is_set()) {
if (!ea->plugins_changed.is_set()) {
MutexLock lock(ea->plugins_lock);
Vector<PluginConfigIOS> loaded_plugins = get_plugins();
if (ea->plugins.size() != loaded_plugins.size()) {
ea->plugins_changed.set();
} else {
for (int i = 0; i < ea->plugins.size(); i++) {
if (ea->plugins[i].name != loaded_plugins[i].name || ea->plugins[i].last_updated != loaded_plugins[i].last_updated) {
ea->plugins_changed.set();
break;
}
}
}
}
Vector<Device> ldevices;
String idepl = EDITOR_GET("export/ios/ios_deploy");
if (ea->has_runnable_preset.is_set() && !idepl.is_empty()) {
String devices;
List<String> args;
args.push_back("-c");
args.push_back("-timeout");
args.push_back("1");
args.push_back("-j");
args.push_back("-u");
args.push_back("-I");
int ec = 0;
Error err = OS::get_singleton()->execute(idepl, args, &devices, &ec, true);
if (err == OK && ec == 0) {
Ref<JSON> json;
json.instantiate();
devices = "{ \"devices\":[" + devices.replace("}{", "},{") + "]}";
err = json->parse(devices);
if (err == OK) {
Dictionary data = json->get_data();
Array devices = data["devices"];
for (int i = 0; i < devices.size(); i++) {
Dictionary device_event = devices[i];
if (device_event["Event"] == "DeviceDetected") {
Dictionary device_info = device_event["Device"];
Device nd;
nd.id = device_info["DeviceIdentifier"];
nd.name = device_info["DeviceName"].operator String() + " (ios_deploy, " + ((device_event["Interface"] == "WIFI") ? "network" : "wired") + ")";
nd.wifi = device_event["Interface"] == "WIFI";
nd.use_ios_deploy = true;
nd.simulator = false;
ldevices.push_back(nd);
}
}
}
}
}
if (ea->has_runnable_preset.is_set() && _check_xcode_install() && (FileAccess::exists("/usr/bin/xcrun") || FileAccess::exists("/bin/xcrun"))) {
{
String devices;
List<String> args;
args.push_back("devicectl");
args.push_back("list");
args.push_back("devices");
args.push_back("-j");
args.push_back("-");
args.push_back("-q");
int ec = 0;
Error err = OS::get_singleton()->execute("xcrun", args, &devices, &ec, true);
if (err == OK && ec == 0) {
Ref<JSON> json;
json.instantiate();
err = json->parse(devices);
if (err == OK) {
const Dictionary &data = json->get_data();
const Dictionary &result = data["result"];
const Array &devices = result["devices"];
for (int i = 0; i < devices.size(); i++) {
const Dictionary &device_info = devices[i];
const Dictionary &conn_props = device_info["connectionProperties"];
const Dictionary &dev_props = device_info["deviceProperties"];
if (conn_props["pairingState"] == "paired" && dev_props["developerModeStatus"] == "enabled") {
Device nd;
nd.id = device_info["identifier"];
nd.name = dev_props["name"].operator String() + " (devicectl, " + ((conn_props["transportType"] == "localNetwork") ? "network" : "wired") + ")";
nd.wifi = conn_props["transportType"] == "localNetwork";
nd.simulator = false;
ldevices.push_back(nd);
}
}
}
}
}
if (ea->has_runnable_preset.is_set()) {
String devices;
List<String> args;
args.push_back("simctl");
args.push_back("list");
args.push_back("devices");
args.push_back("-j");
int ec = 0;
Error err = OS::get_singleton()->execute("xcrun", args, &devices, &ec, true);
if (err == OK && ec == 0) {
Ref<JSON> json;
json.instantiate();
err = json->parse(devices);
if (err == OK) {
const Dictionary &data = json->get_data();
const Dictionary &devices = data["devices"];
for (const Variant *key = devices.next(nullptr); key; key = devices.next(key)) {
const Array &os_devices = devices[*key];
for (int i = 0; i < os_devices.size(); i++) {
const Dictionary &device_info = os_devices[i];
if (device_info["isAvailable"].operator bool() && device_info["state"] == "Booted") {
Device nd;
nd.id = device_info["udid"];
nd.name = device_info["name"].operator String() + " (simulator)";
nd.simulator = true;
ldevices.push_back(nd);
}
}
}
}
}
}
}
{
MutexLock lock(ea->device_lock);
bool different = false;
if (ea->devices.size() != ldevices.size()) {
different = true;
} else {
for (int i = 0; i < ea->devices.size(); i++) {
if (ea->devices[i].id != ldevices[i].id) {
different = true;
break;
}
}
}
if (different) {
ea->devices = ldevices;
ea->devices_changed.set();
}
}
uint64_t sleep = 200;
uint64_t wait = 3000000;
uint64_t time = OS::get_singleton()->get_ticks_usec();
while (OS::get_singleton()->get_ticks_usec() - time < wait) {
OS::get_singleton()->delay_usec(1000 * sleep);
if (ea->quit_request.is_set()) {
break;
}
}
}
}
void EditorExportPlatformIOS::_update_preset_status() {
const int preset_count = EditorExport::get_singleton()->get_export_preset_count();
bool has_runnable = false;
for (int i = 0; i < preset_count; i++) {
const Ref<EditorExportPreset> &preset = EditorExport::get_singleton()->get_export_preset(i);
if (preset->get_platform() == this && preset->is_runnable()) {
has_runnable = true;
break;
}
}
if (has_runnable) {
has_runnable_preset.set();
} else {
has_runnable_preset.clear();
}
devices_changed.set();
}
#endif
Error EditorExportPlatformIOS::run(const Ref<EditorExportPreset> &p_preset, int p_device, BitField<EditorExportPlatform::DebugFlags> p_debug_flags) { … }
EditorExportPlatformIOS::EditorExportPlatformIOS() { … }
EditorExportPlatformIOS::~EditorExportPlatformIOS() { … }