summaryrefslogtreecommitdiffstats
path: root/platform/ios
diff options
context:
space:
mode:
Diffstat (limited to 'platform/ios')
-rw-r--r--platform/ios/SCsub64
-rw-r--r--platform/ios/app_delegate.mm8
-rw-r--r--platform/ios/detect.py8
-rw-r--r--platform/ios/display_server_ios.h14
-rw-r--r--platform/ios/display_server_ios.mm72
-rw-r--r--platform/ios/doc_classes/EditorExportPlatformIOS.xml55
-rw-r--r--platform/ios/export/export_plugin.cpp622
-rw-r--r--platform/ios/export/export_plugin.h16
-rw-r--r--platform/ios/godot_view.mm17
-rw-r--r--platform/ios/ios_terminal_logger.h45
-rw-r--r--platform/ios/ios_terminal_logger.mm74
-rw-r--r--platform/ios/key_mapping_ios.h1
-rw-r--r--platform/ios/key_mapping_ios.mm20
-rw-r--r--platform/ios/keyboard_input_view.mm8
-rw-r--r--platform/ios/os_ios.h11
-rw-r--r--platform/ios/os_ios.mm44
-rw-r--r--platform/ios/rendering_context_driver_vulkan_ios.h (renamed from platform/ios/vulkan_context_ios.h)25
-rw-r--r--platform/ios/rendering_context_driver_vulkan_ios.mm (renamed from platform/ios/vulkan_context_ios.mm)38
-rw-r--r--platform/ios/view_controller.mm10
19 files changed, 765 insertions, 387 deletions
diff --git a/platform/ios/SCsub b/platform/ios/SCsub
index 18ba6617af..5a57f3840b 100644
--- a/platform/ios/SCsub
+++ b/platform/ios/SCsub
@@ -2,6 +2,62 @@
Import("env")
+import os, json
+from platform_methods import run_in_subprocess, architectures, lipo, get_build_version, detect_mvk
+import subprocess
+import shutil
+
+
+def generate_bundle(target, source, env):
+ bin_dir = Dir("#bin").abspath
+
+ # Template bundle.
+ app_prefix = "godot." + env["platform"]
+ rel_prefix = "libgodot." + env["platform"] + "." + "template_release"
+ dbg_prefix = "libgodot." + env["platform"] + "." + "template_debug"
+ if env.dev_build:
+ app_prefix += ".dev"
+ rel_prefix += ".dev"
+ dbg_prefix += ".dev"
+ if env["precision"] == "double":
+ app_prefix += ".double"
+ rel_prefix += ".double"
+ dbg_prefix += ".double"
+
+ # Lipo template libraries.
+ rel_target_bin = lipo(bin_dir + "/" + rel_prefix, env.extra_suffix + ".a")
+ dbg_target_bin = lipo(bin_dir + "/" + dbg_prefix, env.extra_suffix + ".a")
+ rel_target_bin_sim = lipo(bin_dir + "/" + rel_prefix, ".simulator" + env.extra_suffix + ".a")
+ dbg_target_bin_sim = lipo(bin_dir + "/" + dbg_prefix, ".simulator" + env.extra_suffix + ".a")
+
+ # Assemble Xcode project bundle.
+ app_dir = Dir("#bin/ios_xcode").abspath
+ templ = Dir("#misc/dist/ios_xcode").abspath
+ if os.path.exists(app_dir):
+ shutil.rmtree(app_dir)
+ shutil.copytree(templ, app_dir)
+ if rel_target_bin != "":
+ shutil.copy(rel_target_bin, app_dir + "/libgodot.ios.release.xcframework/ios-arm64/libgodot.a")
+ if dbg_target_bin != "":
+ shutil.copy(dbg_target_bin, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64/libgodot.a")
+ if rel_target_bin_sim != "":
+ shutil.copy(
+ rel_target_bin_sim, app_dir + "/libgodot.ios.release.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
+ )
+ if dbg_target_bin_sim != "":
+ shutil.copy(
+ dbg_target_bin_sim, app_dir + "/libgodot.ios.debug.xcframework/ios-arm64_x86_64-simulator/libgodot.a"
+ )
+ mvk_path = detect_mvk(env, "ios-arm64")
+ if mvk_path != "":
+ shutil.copytree(mvk_path, app_dir + "/MoltenVK.xcframework")
+
+ # ZIP Xcode project bundle.
+ zip_dir = Dir("#bin/" + (app_prefix + env.extra_suffix).replace(".", "_")).abspath
+ shutil.make_archive(zip_dir, "zip", root_dir=app_dir)
+ shutil.rmtree(app_dir)
+
+
ios_lib = [
"godot_ios.mm",
"os_ios.mm",
@@ -9,7 +65,7 @@ ios_lib = [
"app_delegate.mm",
"view_controller.mm",
"ios.mm",
- "vulkan_context_ios.mm",
+ "rendering_context_driver_vulkan_ios.mm",
"display_server_ios.mm",
"joypad_ios.mm",
"godot_view.mm",
@@ -20,6 +76,7 @@ ios_lib = [
"device_metrics.m",
"keyboard_input_view.mm",
"key_mapping_ios.mm",
+ "ios_terminal_logger.mm",
]
env_ios = env.Clone()
@@ -41,3 +98,8 @@ def combine_libs(target=None, source=None, env=None):
combine_command = env_ios.Command("#bin/libgodot" + env_ios["LIBSUFFIX"], [ios_lib] + env_ios["LIBS"], combine_libs)
+
+if env["generate_bundle"]:
+ generate_bundle_command = env.Command("generate_bundle", [], generate_bundle)
+ command = env.AlwaysBuild(generate_bundle_command)
+ env.Depends(command, [combine_command])
diff --git a/platform/ios/app_delegate.mm b/platform/ios/app_delegate.mm
index 8a16f8fcc1..32ebf7be44 100644
--- a/platform/ios/app_delegate.mm
+++ b/platform/ios/app_delegate.mm
@@ -167,6 +167,14 @@ static ViewController *mainViewController = nil;
OS_IOS::get_singleton()->on_focus_in();
}
+- (void)applicationDidEnterBackground:(UIApplication *)application {
+ OS_IOS::get_singleton()->on_enter_background();
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application {
+ OS_IOS::get_singleton()->on_exit_background();
+}
+
- (void)dealloc {
self.window = nil;
}
diff --git a/platform/ios/detect.py b/platform/ios/detect.py
index 1f2e935946..4d6e3ae9ba 100644
--- a/platform/ios/detect.py
+++ b/platform/ios/detect.py
@@ -5,7 +5,7 @@ from methods import detect_darwin_sdk_path
from typing import TYPE_CHECKING
if TYPE_CHECKING:
- from SCons import Environment
+ from SCons.Script.SConscript import SConsEnvironment
def get_name():
@@ -23,6 +23,7 @@ def get_opts():
from SCons.Variables import BoolVariable
return [
+ ("vulkan_sdk_path", "Path to the Vulkan SDK", ""),
(
"IOS_TOOLCHAIN_PATH",
"Path to iOS toolchain",
@@ -31,6 +32,7 @@ def get_opts():
("IOS_SDK_PATH", "Path to the iOS SDK", ""),
BoolVariable("ios_simulator", "Build for iOS Simulator", False),
("ios_triple", "Triple for ios toolchain", ""),
+ BoolVariable("generate_bundle", "Generate an APP bundle after building iOS/macOS binaries", False),
]
@@ -53,7 +55,7 @@ def get_flags():
]
-def configure(env: "Environment"):
+def configure(env: "SConsEnvironment"):
# Validate arch.
supported_arches = ["x86_64", "arm64"]
if env["arch"] not in supported_arches:
@@ -153,7 +155,7 @@ def configure(env: "Environment"):
env.Append(CPPDEFINES=["IOS_ENABLED", "UNIX_ENABLED", "COREAUDIO_ENABLED"])
if env["vulkan"]:
- env.Append(CPPDEFINES=["VULKAN_ENABLED"])
+ env.Append(CPPDEFINES=["VULKAN_ENABLED", "RD_ENABLED"])
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES3_ENABLED", "GLES_SILENCE_DEPRECATION"])
diff --git a/platform/ios/display_server_ios.h b/platform/ios/display_server_ios.h
index 3d19222fa8..6f66783a47 100644
--- a/platform/ios/display_server_ios.h
+++ b/platform/ios/display_server_ios.h
@@ -39,7 +39,7 @@
#include "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
#ifdef USE_VOLK
#include <volk.h>
@@ -62,7 +62,7 @@ class DisplayServerIOS : public DisplayServer {
_THREAD_SAFE_CLASS_
#if defined(RD_ENABLED)
- ApiContextRD *context_rd = nullptr;
+ RenderingContextDriver *rendering_context = nullptr;
RenderingDevice *rendering_device = nullptr;
#endif
@@ -77,6 +77,8 @@ class DisplayServerIOS : public DisplayServer {
Callable input_event_callback;
Callable input_text_callback;
+ Callable system_theme_changed;
+
int virtual_keyboard_height = 0;
void perform_event(const Ref<InputEvent> &p_event);
@@ -109,6 +111,8 @@ public:
void send_window_event(DisplayServer::WindowEvent p_event) const;
void _window_callback(const Callable &p_callable, const Variant &p_arg) const;
+ void emit_system_theme_changed();
+
// MARK: - Input
// MARK: Touches and Apple Pencil
@@ -119,7 +123,7 @@ public:
// MARK: Keyboard
- void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed);
+ void key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location);
bool is_keyboard_active() const;
// MARK: Motion
@@ -145,6 +149,7 @@ public:
virtual bool is_dark_mode_supported() const override;
virtual bool is_dark_mode() const override;
+ virtual void set_system_theme_change_callback(const Callable &p_callable) override;
virtual Rect2i get_display_safe_area() const override;
@@ -159,8 +164,7 @@ public:
virtual Vector<DisplayServer::WindowID> get_window_list() const override;
- virtual WindowID
- get_window_at_screen_position(const Point2i &p_position) const override;
+ virtual WindowID get_window_at_screen_position(const Point2i &p_position) const override;
virtual int64_t window_get_native_handle(HandleType p_handle_type, WindowID p_window = MAIN_WINDOW_ID) const override;
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index c31f503605..ed69b91fdd 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -63,14 +63,14 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
}
#if defined(RD_ENABLED)
- context_rd = nullptr;
+ rendering_context = nullptr;
rendering_device = nullptr;
CALayer *layer = nullptr;
union {
#ifdef VULKAN_ENABLED
- VulkanContextIOS::WindowPlatformData vulkan;
+ RenderingContextDriverVulkanIOS::WindowPlatformData vulkan;
#endif
} wpd;
@@ -80,28 +80,34 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
if (!layer) {
ERR_FAIL_MSG("Failed to create iOS Vulkan rendering layer.");
}
- wpd.vulkan.layer_ptr = &layer;
- context_rd = memnew(VulkanContextIOS);
+ wpd.vulkan.layer_ptr = (CAMetalLayer *const *)&layer;
+ rendering_context = memnew(RenderingContextDriverVulkanIOS);
}
#endif
- if (context_rd) {
- if (context_rd->initialize() != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
- ERR_FAIL_MSG(vformat("Failed to initialize %s context", context_rd->get_api_name()));
+ if (rendering_context) {
+ if (rendering_context->initialize() != OK) {
+ ERR_PRINT(vformat("Failed to initialize %s context", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
+ return;
}
- Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
- if (context_rd->window_create(MAIN_WINDOW_ID, p_vsync_mode, size.width, size.height, &wpd) != OK) {
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context->window_create(MAIN_WINDOW_ID, &wpd) != OK) {
+ ERR_PRINT(vformat("Failed to create %s window.", rendering_driver));
+ memdelete(rendering_context);
+ rendering_context = nullptr;
r_error = ERR_UNAVAILABLE;
- ERR_FAIL_MSG(vformat("Failed to create %s window.", context_rd->get_api_name()));
+ return;
}
+ Size2i size = Size2i(layer.bounds.size.width, layer.bounds.size.height) * screen_get_max_scale();
+ rendering_context->window_set_size(MAIN_WINDOW_ID, size.width, size.height);
+ rendering_context->window_set_vsync_mode(MAIN_WINDOW_ID, p_vsync_mode);
+
rendering_device = memnew(RenderingDevice);
- rendering_device->initialize(context_rd);
+ rendering_device->initialize(rendering_context, MAIN_WINDOW_ID);
+ rendering_device->screen_create(MAIN_WINDOW_ID);
RendererCompositorRD::make_current();
}
@@ -130,15 +136,15 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
DisplayServerIOS::~DisplayServerIOS() {
#if defined(RD_ENABLED)
if (rendering_device) {
- rendering_device->finalize();
+ rendering_device->screen_free(MAIN_WINDOW_ID);
memdelete(rendering_device);
rendering_device = nullptr;
}
- if (context_rd) {
- context_rd->window_destroy(MAIN_WINDOW_ID);
- memdelete(context_rd);
- context_rd = nullptr;
+ if (rendering_context) {
+ rendering_context->window_destroy(MAIN_WINDOW_ID);
+ memdelete(rendering_context);
+ rendering_context = nullptr;
}
#endif
}
@@ -234,6 +240,7 @@ void DisplayServerIOS::touch_drag(int p_idx, int p_prev_x, int p_prev_y, int p_x
ev->set_tilt(p_tilt);
ev->set_position(Vector2(p_x, p_y));
ev->set_relative(Vector2(p_x - p_prev_x, p_y - p_prev_y));
+ ev->set_relative_screen_position(ev->get_relative());
perform_event(ev);
}
@@ -247,7 +254,7 @@ void DisplayServerIOS::touches_canceled(int p_idx) {
// MARK: Keyboard
-void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed) {
+void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_physical, NSInteger p_modifier, bool p_pressed, KeyLocation p_location) {
Ref<InputEventKey> ev;
ev.instantiate();
ev->set_echo(false);
@@ -270,6 +277,7 @@ void DisplayServerIOS::key(Key p_key, char32_t p_char, Key p_unshifted, Key p_ph
ev->set_key_label(p_unshifted);
ev->set_physical_keycode(p_physical);
ev->set_unicode(fix_unicode(p_char));
+ ev->set_location(p_location);
perform_event(ev);
}
@@ -379,6 +387,16 @@ bool DisplayServerIOS::is_dark_mode() const {
}
}
+void DisplayServerIOS::set_system_theme_change_callback(const Callable &p_callable) {
+ system_theme_changed = p_callable;
+}
+
+void DisplayServerIOS::emit_system_theme_changed() {
+ if (system_theme_changed.is_valid()) {
+ system_theme_changed.call();
+ }
+}
+
Rect2i DisplayServerIOS::get_display_safe_area() const {
UIEdgeInsets insets = UIEdgeInsetsZero;
UIView *view = AppDelegate.viewController.godotView;
@@ -710,8 +728,8 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
Size2i size = Size2i(viewSize.width, viewSize.height) * screen_get_max_scale();
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->window_resize(MAIN_WINDOW_ID, size.x, size.y);
+ if (rendering_context) {
+ rendering_context->window_set_size(MAIN_WINDOW_ID, size.x, size.y);
}
#endif
@@ -722,8 +740,8 @@ void DisplayServerIOS::resize_window(CGSize viewSize) {
void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- context_rd->set_vsync_mode(p_window, p_vsync_mode);
+ if (rendering_context) {
+ rendering_context->window_set_vsync_mode(p_window, p_vsync_mode);
}
#endif
}
@@ -731,8 +749,8 @@ void DisplayServerIOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mo
DisplayServer::VSyncMode DisplayServerIOS::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(RD_ENABLED)
- if (context_rd) {
- return context_rd->get_vsync_mode(p_window);
+ if (rendering_context) {
+ return rendering_context->window_get_vsync_mode(p_window);
}
#endif
return DisplayServer::VSYNC_ENABLED;
diff --git a/platform/ios/doc_classes/EditorExportPlatformIOS.xml b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
index ecae6d721e..35ef6d6a78 100644
--- a/platform/ios/doc_classes/EditorExportPlatformIOS.xml
+++ b/platform/ios/doc_classes/EditorExportPlatformIOS.xml
@@ -10,6 +10,13 @@
<link title="iOS plugins documentation index">$DOCS_URL/tutorials/platform/ios/index.html</link>
</tutorials>
<members>
+ <member name="application/additional_plist_content" type="String" setter="" getter="">
+ Additional data added to the root [code]&lt;dict&gt;[/code] section of the [url=https://developer.apple.com/documentation/bundleresources/information_property_list]Info.plist[/url] file. The value should be an XML section with pairs of key-value elements, e.g.:
+ [codeblock]
+ &lt;key&gt;key_name&lt;/key&gt;
+ &lt;string&gt;value&lt;/string&gt;
+ [/codeblock]
+ </member>
<member name="application/app_store_team_id" type="String" setter="" getter="">
Apple Team ID, unique 10-character string. To locate your Team ID check "Membership details" section in your Apple developer account dashboard, or "Organizational Unit" of your code signing certificate. See [url=https://developer.apple.com/help/account/manage-your-team/locate-your-team-id]Locate your Team ID[/url].
</member>
@@ -34,8 +41,8 @@
<member name="application/icon_interpolation" type="int" setter="" getter="">
Interpolation method used to resize application icon.
</member>
- <member name="application/launch_screens_interpolation" type="int" setter="" getter="">
- Interpolation method used to resize launch screen images.
+ <member name="application/min_ios_version" type="String" setter="" getter="">
+ Minimum version of iOS required for this application to run in the [code]major.minor.patch[/code] or [code]major.minor[/code] format, can only contain numeric characters ([code]0-9[/code]) and periods ([code].[/code]).
</member>
<member name="application/provisioning_profile_uuid_debug" type="String" setter="" getter="">
UUID of the provisioning profile. If left empty, Xcode will download or create a provisioning profile automatically. See [url=https://developer.apple.com/help/account/manage-profiles/edit-download-or-delete-profiles]Edit, download, or delete provisioning profiles[/url].
@@ -63,6 +70,14 @@
<member name="capabilities/access_wifi" type="bool" setter="" getter="">
If [code]true[/code], networking features related to Wi-Fi access are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url].
</member>
+ <member name="capabilities/performance_a12" type="bool" setter="" getter="">
+ Requires the graphics performance and features of the A12 Bionic and later chips (devices supporting all Vulkan renderer features).
+ Enabling this option limits supported devices to: iPhone XS, iPhone XR, iPad Mini (5th gen.), iPad Air (3rd gen.), iPad (8th gen) and newer.
+ </member>
+ <member name="capabilities/performance_gaming_tier" type="bool" setter="" getter="">
+ Requires the graphics performance and features of the A17 Pro and later chips.
+ Enabling this option limits supported devices to: iPhone 15 Pro and newer.
+ </member>
<member name="capabilities/push_notifications" type="bool" setter="" getter="">
If [code]true[/code], push notifications are enabled. See [url=https://developer.apple.com/support/required-device-capabilities/]Required Device Capabilities[/url].
</member>
@@ -108,39 +123,6 @@
<member name="icons/spotlight_80x80" type="String" setter="" getter="">
Spotlight icon file on iPad and iPhone (2x DPI). If left empty, it will fallback to [member ProjectSettings.application/config/icon]. See [url=https://developer.apple.com/design/human-interface-guidelines/foundations/app-icons]App icons[/url].
</member>
- <member name="landscape_launch_screens/ipad_1024x768" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="landscape_launch_screens/ipad_2048x1536" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="landscape_launch_screens/iphone_2208x1242" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="landscape_launch_screens/iphone_2436x1125" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/ipad_768x1024" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/ipad_1536x2048" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/iphone_640x960" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/iphone_640x1136" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/iphone_750x1334" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/iphone_1125x2436" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
- <member name="portrait_launch_screens/iphone_1242x2208" type="String" setter="" getter="">
- Application launch screen image file. If left empty, it will fallback to [member ProjectSettings.application/boot_splash/image].
- </member>
<member name="privacy/camera_usage_description" type="String" setter="" getter="">
A message displayed when requesting access to the device's camera (in English).
</member>
@@ -174,9 +156,6 @@
<member name="storyboard/use_custom_bg_color" type="bool" setter="" getter="">
If [code]true[/code], [member storyboard/custom_bg_color] is used as a launch screen background color, otherwise [code]application/boot_splash/bg_color[/code] project setting is used.
</member>
- <member name="storyboard/use_launch_screen_storyboard" type="bool" setter="" getter="">
- If [code]true[/code], storyboard launch screen is used instead of launch screen images.
- </member>
<member name="user_data/accessible_from_files_app" type="bool" setter="" getter="">
If [code]true[/code], the app "Documents" folder can be accessed via "Files" app. See [url=https://developer.apple.com/documentation/bundleresources/information_property_list/lssupportsopeningdocumentsinplace]LSSupportsOpeningDocumentsInPlace[/url].
</member>
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index b478759e45..ea2b23cfb9 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -34,14 +34,15 @@
#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_scale.h"
#include "editor/editor_string_names.h"
#include "editor/export/editor_export.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" // For mono and svg.
#ifdef MODULE_SVG_ENABLED
@@ -105,29 +106,6 @@ static const IconInfo icon_infos[] = {
{ PNAME("icons/notification_60x60"), "iphone", "Icon-60.png", "60", "3x", "20x20", false }
};
-struct LoadingScreenInfo {
- const char *preset_key;
- const char *export_name;
- int width = 0;
- int height = 0;
- bool rotate = false;
-};
-
-static const LoadingScreenInfo loading_screen_infos[] = {
- { PNAME("landscape_launch_screens/iphone_2436x1125"), "Default-Landscape-X.png", 2436, 1125, false },
- { PNAME("landscape_launch_screens/iphone_2208x1242"), "Default-Landscape-736h@3x.png", 2208, 1242, false },
- { PNAME("landscape_launch_screens/ipad_1024x768"), "Default-Landscape.png", 1024, 768, false },
- { PNAME("landscape_launch_screens/ipad_2048x1536"), "Default-Landscape@2x.png", 2048, 1536, false },
-
- { PNAME("portrait_launch_screens/iphone_640x960"), "Default-480h@2x.png", 640, 960, false },
- { PNAME("portrait_launch_screens/iphone_640x1136"), "Default-568h@2x.png", 640, 1136, false },
- { PNAME("portrait_launch_screens/iphone_750x1334"), "Default-667h@2x.png", 750, 1334, false },
- { PNAME("portrait_launch_screens/iphone_1125x2436"), "Default-Portrait-X.png", 1125, 2436, false },
- { PNAME("portrait_launch_screens/ipad_768x1024"), "Default-Portrait.png", 768, 1024, false },
- { PNAME("portrait_launch_screens/ipad_1536x2048"), "Default-Portrait@2x.png", 1536, 2048, false },
- { PNAME("portrait_launch_screens/iphone_1242x2208"), "Default-Portrait-736h@3x.png", 1242, 2208, false }
-};
-
String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const {
if (p_preset) {
if (p_name == "application/app_store_team_id") {
@@ -146,13 +124,15 @@ String EditorExportPlatformIOS::get_export_option_warning(const EditorExportPres
return String();
}
-bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
- if (p_preset) {
- bool sb = p_preset->get("storyboard/use_launch_screen_storyboard");
- if (!sb && p_option != "storyboard/use_launch_screen_storyboard" && p_option.begins_with("storyboard/")) {
- return false;
- }
+void EditorExportPlatformIOS::_notification(int p_what) {
+#ifdef MACOS_ENABLED
+ if (p_what == NOTIFICATION_POSTINITIALIZE) {
+ EditorExport::get_singleton()->connect_presets_runnable_updated(callable_mp(this, &EditorExportPlatformIOS::_update_preset_status));
}
+#endif
+}
+
+bool EditorExportPlatformIOS::get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const {
return true;
}
@@ -181,8 +161,11 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/short_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_ios_version"), "12.0"));
+
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/additional_plist_content", PROPERTY_HINT_MULTILINE_TEXT), ""));
+
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/icon_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
- r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/launch_screens_interpolation", PROPERTY_HINT_ENUM, "Nearest neighbor,Bilinear,Cubic,Trilinear,Lanczos"), 4));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "application/export_project_only"), false));
@@ -217,6 +200,8 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/performance_gaming_tier"), false));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/performance_a12"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_itunes_sharing"), false));
@@ -235,16 +220,11 @@ void EditorExportPlatformIOS::get_export_options(List<ExportOption> *r_options)
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, icon_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
}
}
- r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_launch_screen_storyboard"), false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "storyboard/image_scale_mode", PROPERTY_HINT_ENUM, "Same as Logo,Center,Scale to Fit,Scale to Fill,Scale"), 0));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@2x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "storyboard/custom_image@3x", PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "storyboard/use_custom_bg_color"), false));
r_options->push_back(ExportOption(PropertyInfo(Variant::COLOR, "storyboard/custom_bg_color"), Color()));
-
- for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, loading_screen_infos[i].preset_key, PROPERTY_HINT_FILE, "*.png,*.jpg,*.jpeg"), ""));
- }
}
void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug) {
@@ -262,8 +242,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
};
String dbg_sign_id = p_preset->get("application/code_sign_identity_debug").operator String().is_empty() ? "iPhone Developer" : p_preset->get("application/code_sign_identity_debug");
String rel_sign_id = p_preset->get("application/code_sign_identity_release").operator String().is_empty() ? "iPhone Distribution" : p_preset->get("application/code_sign_identity_release");
- bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer");
- bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Distribution");
+ bool dbg_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_debug", ENV_IOS_PROFILE_UUID_DEBUG).operator String().is_empty() || (dbg_sign_id != "iPhone Developer" && dbg_sign_id != "iPhone Distribution");
+ bool rel_manual = !p_preset->get_or_env("application/provisioning_profile_uuid_release", ENV_IOS_PROFILE_UUID_RELEASE).operator String().is_empty() || (rel_sign_id != "iPhone Developer" && rel_sign_id != "iPhone Distribution");
String str;
String strnew;
str.parse_utf8((const char *)pfile.ptr(), pfile.size());
@@ -287,6 +267,8 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
strnew += lines[i].replace("$short_version", p_preset->get_version("application/short_version")) + "\n";
} else if (lines[i].find("$version") != -1) {
strnew += lines[i].replace("$version", p_preset->get_version("application/version")) + "\n";
+ } else if (lines[i].find("$min_version") != -1) {
+ strnew += lines[i].replace("$min_version", p_preset->get("application/min_ios_version")) + "\n";
} else if (lines[i].find("$signature") != -1) {
strnew += lines[i].replace("$signature", p_preset->get("application/signature")) + "\n";
} else if (lines[i].find("$team_id") != -1) {
@@ -359,7 +341,12 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) {
capabilities_list.push_back("wifi");
}
-
+ if ((bool)p_preset->get("capabilities/performance_gaming_tier") && !capabilities_list.has("iphone-performance-gaming-tier")) {
+ capabilities_list.push_back("iphone-performance-gaming-tier");
+ }
+ if ((bool)p_preset->get("capabilities/performance_a12") && !capabilities_list.has("iphone-ipad-minimum-performance-a12")) {
+ capabilities_list.push_back("iphone-ipad-minimum-performance-a12");
+ }
for (int idx = 0; idx < capabilities_list.size(); idx++) {
capabilities += "<string>" + capabilities_list[idx] + "</string>\n";
}
@@ -413,29 +400,20 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref<EditorExportPreset> &p_
String description = p_preset->get("privacy/photolibrary_usage_description");
strnew += lines[i].replace("$photolibrary_usage_description", description) + "\n";
} else if (lines[i].find("$plist_launch_screen_name") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>" : "";
+ String value = "<key>UILaunchStoryboardName</key>\n<string>Launch Screen</string>";
strnew += lines[i].replace("$plist_launch_screen_name", value) + "\n";
} else if (lines[i].find("$pbx_launch_screen_file_reference") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };" : "";
+ String value = "90DD2D9D24B36E8000717FE1 = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = \"Launch Screen.storyboard\"; sourceTree = \"<group>\"; };";
strnew += lines[i].replace("$pbx_launch_screen_file_reference", value) + "\n";
} else if (lines[i].find("$pbx_launch_screen_copy_files") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */," : "";
+ String value = "90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */,";
strnew += lines[i].replace("$pbx_launch_screen_copy_files", value) + "\n";
} else if (lines[i].find("$pbx_launch_screen_build_phase") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */," : "";
+ String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */,";
strnew += lines[i].replace("$pbx_launch_screen_build_phase", value) + "\n";
} else if (lines[i].find("$pbx_launch_screen_build_reference") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };" : "";
+ String value = "90DD2D9E24B36E8000717FE1 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 90DD2D9D24B36E8000717FE1 /* Launch Screen.storyboard */; };";
strnew += lines[i].replace("$pbx_launch_screen_build_reference", value) + "\n";
- } else if (lines[i].find("$pbx_launch_image_usage_setting") != -1) {
- bool is_on = p_preset->get("storyboard/use_launch_screen_storyboard");
- String value = is_on ? "" : "ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;";
- strnew += lines[i].replace("$pbx_launch_image_usage_setting", value) + "\n";
} else if (lines[i].find("$launch_screen_image_mode") != -1) {
int image_scale_mode = p_preset->get("storyboard/image_scale_mode");
String value;
@@ -783,94 +761,6 @@ Error EditorExportPlatformIOS::_export_loading_screen_file(const Ref<EditorExpor
return OK;
}
-Error EditorExportPlatformIOS::_export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir) {
- Ref<DirAccess> da = DirAccess::open(p_dest_dir);
- ERR_FAIL_COND_V_MSG(da.is_null(), ERR_CANT_OPEN, "Cannot open directory '" + p_dest_dir + "'.");
-
- for (uint64_t i = 0; i < sizeof(loading_screen_infos) / sizeof(loading_screen_infos[0]); ++i) {
- LoadingScreenInfo info = loading_screen_infos[i];
- String loading_screen_file = p_preset->get(info.preset_key);
-
- Color boot_bg_color = GLOBAL_GET("application/boot_splash/bg_color");
- String boot_logo_path = GLOBAL_GET("application/boot_splash/image");
- bool boot_logo_scale = GLOBAL_GET("application/boot_splash/fullsize");
-
- if (loading_screen_file.size() > 0) {
- // Load custom loading screens, and resize if required.
- Ref<Image> img = memnew(Image);
- Error err = ImageLoader::load_image(loading_screen_file, img);
- if (err != OK) {
- ERR_PRINT("Invalid loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "'.");
- return ERR_UNCONFIGURED;
- }
- if (img->get_width() != info.width || img->get_height() != info.height) {
- WARN_PRINT("Loading screen (" + String(info.preset_key) + "): '" + loading_screen_file + "' has incorrect size (" + String::num_int64(img->get_width()) + "x" + String::num_int64(img->get_height()) + ") and was automatically resized to " + String::num_int64(info.width) + "x" + String::num_int64(info.height) + ".");
- float aspect_ratio = (float)img->get_width() / (float)img->get_height();
- if (boot_logo_scale) {
- if (info.height * aspect_ratio <= info.width) {
- img->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- } else {
- img->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- }
- }
- Ref<Image> new_img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
- new_img->fill(boot_bg_color);
- _blend_and_rotate(new_img, img, false);
- err = new_img->save_png(p_dest_dir + info.export_name);
- } else {
- err = da->copy(loading_screen_file, p_dest_dir + info.export_name);
- }
- if (err) {
- String err_str = String("Failed to export loading screen (") + info.preset_key + ") from path '" + loading_screen_file + "'.";
- ERR_PRINT(err_str.utf8().get_data());
- return err;
- }
- } else {
- // Generate loading screen from the splash screen
- Ref<Image> img = Image::create_empty(info.width, info.height, false, Image::FORMAT_RGBA8);
- img->fill(boot_bg_color);
-
- Ref<Image> img_bs;
-
- if (boot_logo_path.length() > 0) {
- img_bs = Ref<Image>(memnew(Image));
- ImageLoader::load_image(boot_logo_path, img_bs);
- }
- if (!img_bs.is_valid()) {
- img_bs = Ref<Image>(memnew(Image(boot_splash_png)));
- }
- if (img_bs.is_valid()) {
- float aspect_ratio = (float)img_bs->get_width() / (float)img_bs->get_height();
- if (info.rotate) {
- if (boot_logo_scale) {
- if (info.width * aspect_ratio <= info.height) {
- img_bs->resize(info.width * aspect_ratio, info.width, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- } else {
- img_bs->resize(info.height, info.height / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- }
- }
- } else {
- if (boot_logo_scale) {
- if (info.height * aspect_ratio <= info.width) {
- img_bs->resize(info.height * aspect_ratio, info.height, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- } else {
- img_bs->resize(info.width, info.width / aspect_ratio, (Image::Interpolation)(p_preset->get("application/launch_screens_interpolation").operator int()));
- }
- }
- }
- _blend_and_rotate(img, img_bs, info.rotate);
- }
- Error err = img->save_png(p_dest_dir + info.export_name);
- if (err) {
- String err_str = String("Failed to export loading screen (") + info.preset_key + ") from splash screen.";
- WARN_PRINT(err_str.utf8().get_data());
- }
- }
- }
-
- return OK;
-}
-
Error EditorExportPlatformIOS::_walk_dir_recursive(Ref<DirAccess> &p_da, FileHandler p_handler, void *p_userdata) {
Vector<String> dirs;
String current_dir = p_da->get_current_dir();
@@ -986,7 +876,189 @@ struct ExportLibsData {
String dest_dir;
};
-void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets) {
+void EditorExportPlatformIOS::_check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const {
+ Ref<PList> plist;
+ plist.instantiate();
+ plist->load_file(p_path.path_join("Info.plist"));
+ Ref<PListNode> root_node = plist->get_root();
+ if (root_node.is_null()) {
+ return;
+ }
+ Dictionary root = root_node->get_value();
+ if (!root.has("AvailableLibraries")) {
+ return;
+ }
+ Ref<PListNode> libs_node = root["AvailableLibraries"];
+ if (libs_node.is_null()) {
+ return;
+ }
+ Array libs = libs_node->get_value();
+ r_total_libs = libs.size();
+ for (int j = 0; j < libs.size(); j++) {
+ Ref<PListNode> lib_node = libs[j];
+ if (lib_node.is_null()) {
+ return;
+ }
+ Dictionary lib = lib_node->get_value();
+ if (lib.has("BinaryPath")) {
+ Ref<PListNode> path_node = lib["BinaryPath"];
+ if (path_node.is_valid()) {
+ String path = path_node->get_value();
+ if (path.ends_with(".a")) {
+ r_static_libs++;
+ }
+ if (path.ends_with(".dylib")) {
+ r_dylibs++;
+ }
+ if (path.ends_with(".framework")) {
+ r_frameworks++;
+ }
+ }
+ }
+ }
+}
+
+Error EditorExportPlatformIOS::_convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const {
+ print_line("Converting to .framework", p_source, " -> ", p_destination);
+
+ Ref<DirAccess> da = DirAccess::create_for_path(p_source);
+ if (da.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+
+ Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (filesystem_da.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+
+ if (!filesystem_da->dir_exists(p_destination)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(p_destination);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
+ }
+
+ String asset = p_source.ends_with("/") ? p_source.left(p_source.length() - 1) : p_source;
+ if (asset.ends_with(".xcframework")) {
+ Ref<PList> plist;
+ plist.instantiate();
+ plist->load_file(p_source.path_join("Info.plist"));
+ Ref<PListNode> root_node = plist->get_root();
+ if (root_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Dictionary root = root_node->get_value();
+ if (!root.has("AvailableLibraries")) {
+ return ERR_CANT_OPEN;
+ }
+ Ref<PListNode> libs_node = root["AvailableLibraries"];
+ if (libs_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Array libs = libs_node->get_value();
+ for (int j = 0; j < libs.size(); j++) {
+ Ref<PListNode> lib_node = libs[j];
+ if (lib_node.is_null()) {
+ return ERR_CANT_OPEN;
+ }
+ Dictionary lib = lib_node->get_value();
+ if (lib.has("BinaryPath") && lib.has("LibraryPath") && lib.has("LibraryIdentifier")) {
+ Ref<PListNode> bpath_node = lib["BinaryPath"];
+ Ref<PListNode> lpath_node = lib["LibraryPath"];
+ Ref<PListNode> lid_node = lib["LibraryIdentifier"];
+ if (bpath_node.is_valid() && lpath_node.is_valid() && lid_node.is_valid()) {
+ String binary_path = bpath_node->get_value();
+ String library_identifier = lid_node->get_value();
+
+ String file_name = binary_path.get_basename().get_file();
+ String framework_name = file_name + ".framework";
+
+ bpath_node->data_string = framework_name.utf8();
+ lpath_node->data_string = framework_name.utf8();
+ if (!filesystem_da->dir_exists(p_destination.path_join(library_identifier))) {
+ filesystem_da->make_dir_recursive(p_destination.path_join(library_identifier));
+ }
+ _convert_to_framework(p_source.path_join(library_identifier).path_join(binary_path), p_destination.path_join(library_identifier).path_join(framework_name), p_id);
+ if (lib.has("DebugSymbolsPath")) {
+ Ref<PListNode> dpath_node = lib["DebugSymbolsPath"];
+ if (dpath_node.is_valid()) {
+ String dpath = dpath_node->get_value();
+ if (da->dir_exists(p_source.path_join(library_identifier).path_join(dpath))) {
+ da->copy_dir(p_source.path_join(library_identifier).path_join(dpath), p_destination.path_join(library_identifier).path_join("dSYMs"));
+ }
+ }
+ }
+ }
+ }
+ }
+ String info_plist = plist->save_text();
+
+ Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(info_plist);
+ }
+ } else {
+ String file_name = p_destination.get_basename().get_file();
+ String framework_name = file_name + ".framework";
+
+ da->copy(p_source, p_destination.path_join(file_name));
+
+ // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
+ {
+ List<String> install_name_args;
+ install_name_args.push_back("-id");
+ install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
+ install_name_args.push_back(p_destination.path_join(file_name));
+
+ OS::get_singleton()->execute("install_name_tool", install_name_args);
+ }
+
+ // Creating Info.plist
+ {
+ String lib_clean_name = file_name;
+ for (int i = 0; i < lib_clean_name.length(); i++) {
+ if (!is_ascii_alphanumeric_char(lib_clean_name[i]) && lib_clean_name[i] != '.' && lib_clean_name[i] != '-') {
+ lib_clean_name[i] = '-';
+ }
+ }
+ String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
+ "<plist version=\"1.0\">\n"
+ " <dict>\n"
+ " <key>CFBundleShortVersionString</key>\n"
+ " <string>1.0</string>\n"
+ " <key>CFBundleIdentifier</key>\n"
+ " <string>$id.framework.$cl_name</string>\n"
+ " <key>CFBundleName</key>\n"
+ " <string>$name</string>\n"
+ " <key>CFBundleExecutable</key>\n"
+ " <string>$name</string>\n"
+ " <key>DTPlatformName</key>\n"
+ " <string>iphoneos</string>\n"
+ " <key>CFBundleInfoDictionaryVersion</key>\n"
+ " <string>6.0</string>\n"
+ " <key>CFBundleVersion</key>\n"
+ " <string>1</string>\n"
+ " <key>CFBundlePackageType</key>\n"
+ " <string>FMWK</string>\n"
+ " <key>MinimumOSVersion</key>\n"
+ " <string>12.0</string>\n"
+ " </dict>\n"
+ "</plist>";
+
+ String info_plist = info_plist_format.replace("$id", p_id).replace("$name", file_name).replace("$cl_name", lib_clean_name);
+
+ Ref<FileAccess> f = FileAccess::open(p_destination.path_join("Info.plist"), FileAccess::WRITE);
+ if (f.is_valid()) {
+ f->store_string(info_plist);
+ }
+ }
+ }
+
+ return OK;
+}
+
+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) {
// that is just a random number, we just need Godot IDs not to clash with
// existing IDs in the project.
PbxId current_id = { 0x58938401, 0, 0 };
@@ -1011,7 +1083,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
String type;
if (asset.exported_path.ends_with(".framework")) {
- if (asset.should_embed) {
+ int total_libs = 0;
+ int static_libs = 0;
+ int dylibs = 0;
+ int frameworks = 0;
+ _check_xcframework_content(p_out_dir.path_join(asset.exported_path), total_libs, static_libs, dylibs, frameworks);
+ if (asset.should_embed && (static_libs != total_libs)) {
additional_asset_info_format += "$framework_id = {isa = PBXBuildFile; fileRef = $ref_id; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };\n";
framework_id = (++current_id).str();
pbx_embeded_frameworks += framework_id + ",\n";
@@ -1074,12 +1151,12 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref<EditorExportPrese
}
}
-Error EditorExportPlatformIOS::_copy_asset(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::_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) {
String binary_name = p_out_dir.get_file().get_basename();
Ref<DirAccess> da = DirAccess::create_for_path(p_asset);
if (da.is_null()) {
- ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + ".");
+ ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open directory: " + p_asset + ".");
}
bool file_exists = da->file_exists(p_asset);
bool dir_exists = da->dir_exists(p_asset);
@@ -1093,7 +1170,8 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
String destination;
String asset_path;
- bool create_framework = false;
+ Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
if (p_is_framework && asset.ends_with(".dylib")) {
// For iOS we need to turn .dylib into .framework
@@ -1113,10 +1191,23 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
asset_path = asset_path.path_join(framework_name);
destination_dir = p_out_dir.path_join(asset_path);
destination = destination_dir.path_join(file_name);
- create_framework = true;
- } else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) {
- asset_path = String("dylibs").path_join(base_dir);
+ // Convert to framework and copy.
+ Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier"));
+ if (err) {
+ return err;
+ }
+ } else if (p_is_framework && asset.ends_with(".xcframework")) {
+ // For iOS we need to turn .dylib inside .xcframework
+ // into .framework to be able to send application to AppStore
+
+ int total_libs = 0;
+ int static_libs = 0;
+ int dylibs = 0;
+ int frameworks = 0;
+ _check_xcframework_content(p_asset, total_libs, static_libs, dylibs, frameworks);
+
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
if (!p_custom_file_name) {
@@ -1128,8 +1219,29 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
asset_path = asset_path.path_join(file_name);
destination_dir = p_out_dir.path_join(asset_path);
destination = destination_dir;
- } else {
- asset_path = base_dir;
+
+ if (dylibs > 0) {
+ // Convert to framework and copy.
+ Error err = _convert_to_framework(p_asset, destination, p_preset->get("application/bundle_identifier"));
+ if (err) {
+ return err;
+ }
+ } else {
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
+ }
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ }
+ } else if (p_is_framework && asset.ends_with(".framework")) {
+ // Framework.
+ asset_path = String("dylibs").path_join(base_dir);
String file_name;
@@ -1139,99 +1251,67 @@ Error EditorExportPlatformIOS::_copy_asset(const String &p_out_dir, const String
file_name = *p_custom_file_name;
}
- destination_dir = p_out_dir.path_join(asset_path);
asset_path = asset_path.path_join(file_name);
- destination = p_out_dir.path_join(asset_path);
- }
-
- Ref<DirAccess> filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- ERR_FAIL_COND_V_MSG(filesystem_da.is_null(), ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'.");
+ destination_dir = p_out_dir.path_join(asset_path);
+ destination = destination_dir;
- if (!filesystem_da->dir_exists(destination_dir)) {
- Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
- if (make_dir_err) {
- return make_dir_err;
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
+ }
}
- }
-
- Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
- if (err) {
- return err;
- }
- if (asset_path.ends_with("/")) {
- asset_path = asset_path.left(asset_path.length() - 1);
- }
- IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
- r_exported_assets.push_back(exported_asset);
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ } else {
+ // Unknown resource.
+ asset_path = base_dir;
- if (create_framework) {
String file_name;
if (!p_custom_file_name) {
- file_name = p_asset.get_basename().get_file();
+ file_name = p_asset.get_file();
} else {
file_name = *p_custom_file_name;
}
- String framework_name = file_name + ".framework";
-
- // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib
- {
- List<String> install_name_args;
- install_name_args.push_back("-id");
- install_name_args.push_back(String("@rpath").path_join(framework_name).path_join(file_name));
- install_name_args.push_back(destination);
-
- OS::get_singleton()->execute("install_name_tool", install_name_args);
- }
-
- // Creating Info.plist
- {
- String info_plist_format = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
- "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n"
- "<plist version=\"1.0\">\n"
- "<dict>\n"
- "<key>CFBundleShortVersionString</key>\n"
- "<string>1.0</string>\n"
- "<key>CFBundleIdentifier</key>\n"
- "<string>com.gdextension.framework.$name</string>\n"
- "<key>CFBundleName</key>\n"
- "<string>$name</string>\n"
- "<key>CFBundleExecutable</key>\n"
- "<string>$name</string>\n"
- "<key>DTPlatformName</key>\n"
- "<string>iphoneos</string>\n"
- "<key>CFBundleInfoDictionaryVersion</key>\n"
- "<string>6.0</string>\n"
- "<key>CFBundleVersion</key>\n"
- "<string>1</string>\n"
- "<key>CFBundlePackageType</key>\n"
- "<string>FMWK</string>\n"
- "<key>MinimumOSVersion</key>\n"
- "<string>10.0</string>\n"
- "</dict>\n"
- "</plist>";
-
- String info_plist = info_plist_format.replace("$name", file_name);
+ destination_dir = p_out_dir.path_join(asset_path);
+ asset_path = asset_path.path_join(file_name);
+ destination = p_out_dir.path_join(asset_path);
- Ref<FileAccess> f = FileAccess::open(destination_dir.path_join("Info.plist"), FileAccess::WRITE);
- if (f.is_valid()) {
- f->store_string(info_plist);
+ // Copy as is.
+ if (!filesystem_da->dir_exists(destination_dir)) {
+ Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir);
+ if (make_dir_err) {
+ return make_dir_err;
}
}
+ Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination);
+ if (err) {
+ return err;
+ }
+ }
+
+ if (asset_path.ends_with("/")) {
+ asset_path = asset_path.left(asset_path.length() - 1);
}
+ IOSExportAsset exported_asset = { binary_name.path_join(asset_path), p_is_framework, p_should_embed };
+ r_exported_assets.push_back(exported_asset);
return OK;
}
-Error EditorExportPlatformIOS::_export_additional_assets(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<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets) {
for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) {
- String asset = p_assets[f_idx];
+ const String &asset = p_assets[f_idx];
if (asset.begins_with("res://")) {
- Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
+ Error err = _copy_asset(p_preset, p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
} else if (ProjectSettings::get_singleton()->localize_path(asset).begins_with("res://")) {
- Error err = _copy_asset(p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets);
+ Error err = _copy_asset(p_preset, p_out_dir, ProjectSettings::get_singleton()->localize_path(asset), nullptr, p_is_framework, p_should_embed, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
} else {
// either SDK-builtin or already a part of the export template
@@ -1243,26 +1323,26 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
return OK;
}
-Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, 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<Ref<EditorExportPlugin>> export_plugins = EditorExport::get_singleton()->get_export_plugins();
for (int i = 0; i < export_plugins.size(); i++) {
Vector<String> linked_frameworks = export_plugins[i]->get_ios_frameworks();
- Error err = _export_additional_assets(p_out_dir, linked_frameworks, true, false, r_exported_assets);
+ Error err = _export_additional_assets(p_preset, p_out_dir, linked_frameworks, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> embedded_frameworks = export_plugins[i]->get_ios_embedded_frameworks();
- err = _export_additional_assets(p_out_dir, embedded_frameworks, true, true, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, embedded_frameworks, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> project_static_libs = export_plugins[i]->get_ios_project_static_libs();
for (int j = 0; j < project_static_libs.size(); j++) {
project_static_libs.write[j] = project_static_libs[j].get_file(); // Only the file name as it's copied to the project
}
- err = _export_additional_assets(p_out_dir, project_static_libs, true, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, project_static_libs, true, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
Vector<String> ios_bundle_files = export_plugins[i]->get_ios_bundle_files();
- err = _export_additional_assets(p_out_dir, ios_bundle_files, false, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, p_out_dir, ios_bundle_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err, err);
}
@@ -1270,7 +1350,7 @@ Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir
for (int i = 0; i < p_libraries.size(); ++i) {
library_paths.push_back(p_libraries[i].path);
}
- Error err = _export_additional_assets(p_out_dir, library_paths, true, true, r_exported_assets);
+ Error err = _export_additional_assets(p_preset, p_out_dir, library_paths, true, true, r_exported_assets);
ERR_FAIL_COND_V(err, err);
return OK;
@@ -1315,7 +1395,7 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
String plugin_binary_result_file = plugin.binary.get_file();
// We shouldn't embed .xcframework that contains static libraries.
// Static libraries are not embedded anyway.
- err = _copy_asset(dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
+ err = _copy_asset(p_preset, dest_dir, plugin_main_binary, &plugin_binary_result_file, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Adding dependencies.
@@ -1440,15 +1520,15 @@ Error EditorExportPlatformIOS::_export_ios_plugins(const Ref<EditorExportPreset>
// Export files
{
// Export linked plugin dependency
- err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_linked_dependencies, true, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export embedded plugin dependency
- err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
// Export plugin files
- err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets);
+ err = _export_additional_assets(p_preset, dest_dir, plugin_files, false, false, r_exported_assets);
ERR_FAIL_COND_V(err != OK, err);
}
@@ -1619,6 +1699,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
false
};
+ config_data.plist_content += p_preset->get("application/additional_plist_content").operator String() + "\n";
+
Vector<IOSExportAsset> assets;
Ref<DirAccess> tmp_app_path = DirAccess::create_for_path(dest_dir);
@@ -1824,9 +1906,6 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
}
{
- bool use_storyboard = p_preset->get("storyboard/use_launch_screen_storyboard");
-
- String launch_image_path = binary_dir + "/Images.xcassets/LaunchImage.launchimage/";
String splash_image_path = binary_dir + "/Images.xcassets/SplashImage.imageset/";
Ref<DirAccess> launch_screen_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
@@ -1835,30 +1914,11 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
return ERR_CANT_CREATE;
}
- if (use_storyboard) {
- print_line("Using Launch Storyboard");
-
- if (launch_screen_da->change_dir(launch_image_path) == OK) {
- launch_screen_da->erase_contents_recursive();
- launch_screen_da->remove(launch_image_path);
- }
+ print_line("Exporting launch screen storyboard");
- err = _export_loading_screen_file(p_preset, splash_image_path);
+ err = _export_loading_screen_file(p_preset, splash_image_path);
+ if (err != OK) {
add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), splash_image_path, err));
- } else {
- print_line("Using Launch Images");
-
- const String launch_screen_path = binary_dir + "/Launch Screen.storyboard";
-
- launch_screen_da->remove(launch_screen_path);
-
- if (launch_screen_da->change_dir(splash_image_path) == OK) {
- launch_screen_da->erase_contents_recursive();
- launch_screen_da->remove(splash_image_path);
- }
-
- err = _export_loading_screen_images(p_preset, launch_image_path);
- add_message(EXPORT_MESSAGE_ERROR, TTR("Export"), vformat(TTR("Failed to create a file at path \"%s\" with code %d."), launch_image_path, err));
}
}
@@ -1867,8 +1927,8 @@ Error EditorExportPlatformIOS::_export_project_helper(const Ref<EditorExportPres
}
print_line("Exporting additional assets");
- _export_additional_assets(binary_dir, libraries, assets);
- _add_assets_to_project(p_preset, project_file_data, assets);
+ _export_additional_assets(p_preset, binary_dir, libraries, assets);
+ _add_assets_to_project(dest_dir, p_preset, project_file_data, assets);
String project_file_name = binary_dir + ".xcodeproj/project.pbxproj";
{
Ref<FileAccess> f = FileAccess::open(project_file_name, FileAccess::WRITE);
@@ -2010,6 +2070,26 @@ bool EditorExportPlatformIOS::has_valid_export_configuration(const Ref<EditorExp
valid = dvalid || rvalid;
r_missing_templates = !valid;
+ const String &additional_plist_content = p_preset->get("application/additional_plist_content");
+ if (!additional_plist_content.is_empty()) {
+ const String &plist = vformat("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
+ "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">"
+ "<plist version=\"1.0\">"
+ "<dict>\n"
+ "%s\n"
+ "</dict>\n"
+ "</plist>\n",
+ additional_plist_content);
+
+ String plist_err;
+ Ref<PList> plist_parser;
+ plist_parser.instantiate();
+ if (!plist_parser->load_string(plist, plist_err)) {
+ err += TTR("Invalid additional PList content: ") + plist_err + "\n";
+ valid = false;
+ }
+ }
+
if (!err.is_empty()) {
r_error = err;
}
@@ -2162,7 +2242,7 @@ void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
// Enum real devices (via ios_deploy, pre Xcode 15).
String idepl = EDITOR_GET("export/ios/ios_deploy");
- if (!idepl.is_empty()) {
+ if (ea->has_runnable_preset.is_set() && !idepl.is_empty()) {
String devices;
List<String> args;
args.push_back("-c");
@@ -2200,7 +2280,7 @@ void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
}
// Enum simulators.
- if (_check_xcode_install() && (FileAccess::exists("/usr/bin/xcrun") || FileAccess::exists("/bin/xcrun"))) {
+ if (ea->has_runnable_preset.is_set() && _check_xcode_install() && (FileAccess::exists("/usr/bin/xcrun") || FileAccess::exists("/bin/xcrun"))) {
{
String devices;
List<String> args;
@@ -2238,7 +2318,7 @@ void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
}
// Enum simulators.
- {
+ if (ea->has_runnable_preset.is_set()) {
String devices;
List<String> args;
args.push_back("simctl");
@@ -2307,6 +2387,25 @@ void EditorExportPlatformIOS::_check_for_changes_poll_thread(void *ud) {
}
}
}
+
+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();
+ }
+}
#endif
Error EditorExportPlatformIOS::run(const Ref<EditorExportPreset> &p_preset, int p_device, int p_debug_flags) {
@@ -2571,6 +2670,7 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() {
plugins_changed.set();
devices_changed.set();
#ifdef MACOS_ENABLED
+ _update_preset_status();
check_for_changes_thread.start(_check_for_changes_poll_thread, this);
#endif
}
diff --git a/platform/ios/export/export_plugin.h b/platform/ios/export/export_plugin.h
index fd2243bcda..197f27da76 100644
--- a/platform/ios/export/export_plugin.h
+++ b/platform/ios/export/export_plugin.h
@@ -81,9 +81,11 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
#ifdef MACOS_ENABLED
Thread check_for_changes_thread;
SafeFlag quit_request;
+ SafeFlag has_runnable_preset;
static bool _check_xcode_install();
static void _check_for_changes_poll_thread(void *ud);
+ void _update_preset_status();
#endif
typedef Error (*FileHandler)(String p_file, void *p_userdata);
@@ -127,17 +129,19 @@ class EditorExportPlatformIOS : public EditorExportPlatform {
String _get_linker_flags();
String _get_cpp_code();
void _fix_config_file(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &pfile, const IOSConfigData &p_config, bool p_debug);
- Error _export_loading_screen_images(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
Error _export_loading_screen_file(const Ref<EditorExportPreset> &p_preset, const String &p_dest_dir);
Error _export_icons(const Ref<EditorExportPreset> &p_preset, const String &p_iconset_dir);
Vector<ExportArchitecture> _get_supported_architectures() const;
Vector<String> _get_preset_architectures(const Ref<EditorExportPreset> &p_preset) const;
- void _add_assets_to_project(const Ref<EditorExportPreset> &p_preset, Vector<uint8_t> &p_project_data, const Vector<IOSExportAsset> &p_additional_assets);
- Error _export_additional_assets(const String &p_out_dir, const Vector<String> &p_assets, bool p_is_framework, bool p_should_embed, Vector<IOSExportAsset> &r_exported_assets);
- Error _copy_asset(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 _export_additional_assets(const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
+ void _check_xcframework_content(const String &p_path, int &r_total_libs, int &r_static_libs, int &r_dylibs, int &r_frameworks) const;
+ Error _convert_to_framework(const String &p_source, const String &p_destination, const String &p_id) const;
+
+ void _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 _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 _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 _export_additional_assets(const Ref<EditorExportPreset> &p_preset, const String &p_out_dir, const Vector<SharedObject> &p_libraries, Vector<IOSExportAsset> &r_exported_assets);
Error _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 _export_project_helper(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags, bool p_simulator, bool p_oneclick);
@@ -150,6 +154,8 @@ protected:
virtual bool get_export_option_visibility(const EditorExportPreset *p_preset, const String &p_option) const override;
virtual String get_export_option_warning(const EditorExportPreset *p_preset, const StringName &p_name) const override;
+ void _notification(int p_what);
+
public:
virtual String get_name() const override { return "iOS"; }
virtual String get_os_name() const override { return "iOS"; }
diff --git a/platform/ios/godot_view.mm b/platform/ios/godot_view.mm
index ff8a4f8921..4b87863fc5 100644
--- a/platform/ios/godot_view.mm
+++ b/platform/ios/godot_view.mm
@@ -167,6 +167,23 @@ static const float earth_gravity = 9.80665;
}
}
+- (void)system_theme_changed {
+ DisplayServerIOS *ds = (DisplayServerIOS *)DisplayServer::get_singleton();
+ if (ds) {
+ ds->emit_system_theme_changed();
+ }
+}
+
+- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection {
+ if (@available(iOS 13.0, *)) {
+ [super traitCollectionDidChange:previousTraitCollection];
+
+ if ([UITraitCollection currentTraitCollection].userInterfaceStyle != previousTraitCollection.userInterfaceStyle) {
+ [self system_theme_changed];
+ }
+ }
+}
+
- (void)stopRendering {
if (!self.isActive) {
return;
diff --git a/platform/ios/ios_terminal_logger.h b/platform/ios/ios_terminal_logger.h
new file mode 100644
index 0000000000..7f0bc37a07
--- /dev/null
+++ b/platform/ios/ios_terminal_logger.h
@@ -0,0 +1,45 @@
+/**************************************************************************/
+/* ios_terminal_logger.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef IOS_TERMINAL_LOGGER_H
+#define IOS_TERMINAL_LOGGER_H
+
+#ifdef IOS_ENABLED
+
+#include "core/io/logger.h"
+
+class IOSTerminalLogger : public StdLogger {
+public:
+ virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify = false, ErrorType p_type = ERR_ERROR) override;
+};
+
+#endif // IOS_ENABLED
+
+#endif // IOS_TERMINAL_LOGGER_H
diff --git a/platform/ios/ios_terminal_logger.mm b/platform/ios/ios_terminal_logger.mm
new file mode 100644
index 0000000000..b4c9821cdc
--- /dev/null
+++ b/platform/ios/ios_terminal_logger.mm
@@ -0,0 +1,74 @@
+/**************************************************************************/
+/* ios_terminal_logger.mm */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "ios_terminal_logger.h"
+
+#ifdef IOS_ENABLED
+
+#include <os/log.h>
+
+void IOSTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, bool p_editor_notify, ErrorType p_type) {
+ if (!should_log(true)) {
+ return;
+ }
+
+ const char *err_details;
+ if (p_rationale && p_rationale[0]) {
+ err_details = p_rationale;
+ } else {
+ err_details = p_code;
+ }
+
+ switch (p_type) {
+ case ERR_WARNING:
+ os_log_info(OS_LOG_DEFAULT,
+ "WARNING: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_SCRIPT:
+ os_log_error(OS_LOG_DEFAULT,
+ "SCRIPT ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_SHADER:
+ os_log_error(OS_LOG_DEFAULT,
+ "SHADER ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ case ERR_ERROR:
+ default:
+ os_log_error(OS_LOG_DEFAULT,
+ "ERROR: %{public}s\nat: %{public}s (%{public}s:%i)",
+ err_details, p_function, p_file, p_line);
+ break;
+ }
+}
+
+#endif // IOS_ENABLED
diff --git a/platform/ios/key_mapping_ios.h b/platform/ios/key_mapping_ios.h
index 6cc61175bb..8874da3024 100644
--- a/platform/ios/key_mapping_ios.h
+++ b/platform/ios/key_mapping_ios.h
@@ -41,6 +41,7 @@ class KeyMappingIOS {
public:
static void initialize();
static Key remap_key(CFIndex p_keycode);
+ static KeyLocation key_location(CFIndex p_keycode);
};
#endif // KEY_MAPPING_IOS_H
diff --git a/platform/ios/key_mapping_ios.mm b/platform/ios/key_mapping_ios.mm
index d2c84884d1..61f28aa84b 100644
--- a/platform/ios/key_mapping_ios.mm
+++ b/platform/ios/key_mapping_ios.mm
@@ -38,6 +38,7 @@ struct HashMapHasherKeys {
};
HashMap<CFIndex, Key, HashMapHasherKeys> keyusage_map;
+HashMap<CFIndex, KeyLocation, HashMapHasherKeys> location_map;
void KeyMappingIOS::initialize() {
if (@available(iOS 13.4, *)) {
@@ -172,6 +173,15 @@ void KeyMappingIOS::initialize() {
keyusage_map[0x029D] = Key::GLOBE; // "Globe" key on smart connector / Mac keyboard.
keyusage_map[UIKeyboardHIDUsageKeyboardLANG1] = Key::JIS_EISU;
keyusage_map[UIKeyboardHIDUsageKeyboardLANG2] = Key::JIS_KANA;
+
+ location_map[UIKeyboardHIDUsageKeyboardLeftAlt] = KeyLocation::LEFT;
+ location_map[UIKeyboardHIDUsageKeyboardRightAlt] = KeyLocation::RIGHT;
+ location_map[UIKeyboardHIDUsageKeyboardLeftControl] = KeyLocation::LEFT;
+ location_map[UIKeyboardHIDUsageKeyboardRightControl] = KeyLocation::RIGHT;
+ location_map[UIKeyboardHIDUsageKeyboardLeftShift] = KeyLocation::LEFT;
+ location_map[UIKeyboardHIDUsageKeyboardRightShift] = KeyLocation::RIGHT;
+ location_map[UIKeyboardHIDUsageKeyboardLeftGUI] = KeyLocation::LEFT;
+ location_map[UIKeyboardHIDUsageKeyboardRightGUI] = KeyLocation::RIGHT;
}
}
@@ -184,3 +194,13 @@ Key KeyMappingIOS::remap_key(CFIndex p_keycode) {
}
return Key::NONE;
}
+
+KeyLocation KeyMappingIOS::key_location(CFIndex p_keycode) {
+ if (@available(iOS 13.4, *)) {
+ const KeyLocation *location = location_map.getptr(p_keycode);
+ if (location) {
+ return *location;
+ }
+ }
+ return KeyLocation::UNSPECIFIED;
+}
diff --git a/platform/ios/keyboard_input_view.mm b/platform/ios/keyboard_input_view.mm
index bc6eb63ed5..8b614662b7 100644
--- a/platform/ios/keyboard_input_view.mm
+++ b/platform/ios/keyboard_input_view.mm
@@ -116,8 +116,8 @@
- (void)deleteText:(NSInteger)charactersToDelete {
for (int i = 0; i < charactersToDelete; i++) {
- DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true);
- DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false);
+ DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
+ DisplayServerIOS::get_singleton()->key(Key::BACKSPACE, 0, Key::BACKSPACE, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
}
}
@@ -137,8 +137,8 @@
key = Key::SPACE;
}
- DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true);
- DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false);
+ DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, true, KeyLocation::UNSPECIFIED);
+ DisplayServerIOS::get_singleton()->key(key, character, key, Key::NONE, 0, false, KeyLocation::UNSPECIFIED);
}
}
diff --git a/platform/ios/os_ios.h b/platform/ios/os_ios.h
index 06724d763f..10ecd08a89 100644
--- a/platform/ios/os_ios.h
+++ b/platform/ios/os_ios.h
@@ -45,7 +45,7 @@
#include "servers/rendering/rendering_device.h"
#if defined(VULKAN_ENABLED)
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
#endif
#endif
@@ -103,16 +103,16 @@ public:
virtual Vector<String> get_system_font_path_for_text(const String &p_font_name, const String &p_text, const String &p_locale = String(), const String &p_script = String(), int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
- virtual Error open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
+ virtual Error open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path = false, String *r_resolved_path = nullptr) override;
virtual Error close_dynamic_library(void *p_library_handle) override;
- virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional = false) override;
+ virtual Error get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional = false) override;
virtual String get_name() const override;
virtual String get_distribution_name() const override;
virtual String get_version() const override;
virtual String get_model_name() const override;
- virtual Error shell_open(String p_uri) override;
+ virtual Error shell_open(const String &p_uri) override;
virtual String get_user_data_dir() const override;
@@ -129,6 +129,9 @@ public:
void on_focus_out();
void on_focus_in();
+
+ void on_enter_background();
+ void on_exit_background();
};
#endif // IOS_ENABLED
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index a646705305..23614af366 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -35,6 +35,7 @@
#import "app_delegate.h"
#import "display_server_ios.h"
#import "godot_view.h"
+#import "ios_terminal_logger.h"
#import "view_controller.h"
#include "core/config/project_settings.h"
@@ -105,12 +106,7 @@ OS_IOS::OS_IOS() {
main_loop = nullptr;
Vector<Logger *> loggers;
- loggers.push_back(memnew(SyslogLogger));
-#ifdef DEBUG_ENABLED
- // it seems iOS app's stdout/stderr is only obtainable if you launch it from
- // Xcode
- loggers.push_back(memnew(StdLogger));
-#endif
+ loggers.push_back(memnew(IOSTerminalLogger));
_set_logger(memnew(CompositeLogger(loggers)));
AudioDriverManager::add_driver(&audio_driver);
@@ -223,7 +219,7 @@ _FORCE_INLINE_ String OS_IOS::get_framework_executable(const String &p_path) {
return p_path;
}
-Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
+Error OS_IOS::open_dynamic_library(const String &p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
if (p_path.length() == 0) {
// Static xcframework.
p_library_handle = RTLD_SELF;
@@ -257,6 +253,8 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle,
path = get_framework_executable(get_executable_path().get_base_dir().path_join("Frameworks").path_join(p_path.get_file().get_basename() + ".framework"));
}
+ ERR_FAIL_COND_V(!FileAccess::exists(path), ERR_FILE_NOT_FOUND);
+
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
@@ -274,7 +272,7 @@ Error OS_IOS::close_dynamic_library(void *p_library_handle) {
return OS_Unix::close_dynamic_library(p_library_handle);
}
-Error OS_IOS::get_dynamic_library_symbol_handle(void *p_library_handle, const String p_name, void *&p_symbol_handle, bool p_optional) {
+Error OS_IOS::get_dynamic_library_symbol_handle(void *p_library_handle, const String &p_name, void *&p_symbol_handle, bool p_optional) {
if (p_library_handle == RTLD_SELF) {
void **ptr = OS_IOS::dynamic_symbol_lookup_table.getptr(p_name);
if (ptr) {
@@ -307,7 +305,7 @@ String OS_IOS::get_model_name() const {
return OS_Unix::get_model_name();
}
-Error OS_IOS::shell_open(String p_uri) {
+Error OS_IOS::shell_open(const String &p_uri) {
NSString *urlPath = [[NSString alloc] initWithUTF8String:p_uri.utf8().get_data()];
NSURL *url = [NSURL URLWithString:urlPath];
@@ -603,6 +601,10 @@ void OS_IOS::on_focus_out() {
DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_OUT);
}
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_OUT);
+ }
+
[AppDelegate.viewController.godotView stopRendering];
audio_driver.stop();
@@ -617,10 +619,34 @@ void OS_IOS::on_focus_in() {
DisplayServerIOS::get_singleton()->send_window_event(DisplayServer::WINDOW_EVENT_FOCUS_IN);
}
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_FOCUS_IN);
+ }
+
[AppDelegate.viewController.godotView startRendering];
audio_driver.start();
}
}
+void OS_IOS::on_enter_background() {
+ // Do not check for is_focused, because on_focus_out will always be fired first by applicationWillResignActive.
+
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_PAUSED);
+ }
+
+ on_focus_out();
+}
+
+void OS_IOS::on_exit_background() {
+ if (!is_focused) {
+ on_focus_in();
+
+ if (OS::get_singleton()->get_main_loop()) {
+ OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_APPLICATION_RESUMED);
+ }
+ }
+}
+
#endif // IOS_ENABLED
diff --git a/platform/ios/vulkan_context_ios.h b/platform/ios/rendering_context_driver_vulkan_ios.h
index cdc8b618af..dc85ff738d 100644
--- a/platform/ios/vulkan_context_ios.h
+++ b/platform/ios/rendering_context_driver_vulkan_ios.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_ios.h */
+/* rendering_context_driver_vulkan_ios.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,28 +28,31 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef VULKAN_CONTEXT_IOS_H
-#define VULKAN_CONTEXT_IOS_H
+#ifndef RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H
+#define RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H
#ifdef VULKAN_ENABLED
-#include "drivers/vulkan/vulkan_context.h"
+#include "drivers/vulkan/rendering_context_driver_vulkan.h"
-#import <UIKit/UIKit.h>
+#import <QuartzCore/CAMetalLayer.h>
-class VulkanContextIOS : public VulkanContext {
+class RenderingContextDriverVulkanIOS : public RenderingContextDriverVulkan {
+private:
virtual const char *_get_platform_surface_extension() const override final;
+protected:
+ SurfaceID surface_create(const void *p_platform_data) override final;
+
public:
struct WindowPlatformData {
- CALayer *const *layer_ptr;
+ CAMetalLayer *const *layer_ptr;
};
- virtual Error window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) override final;
- VulkanContextIOS();
- ~VulkanContextIOS();
+ RenderingContextDriverVulkanIOS();
+ ~RenderingContextDriverVulkanIOS();
};
#endif // VULKAN_ENABLED
-#endif // VULKAN_CONTEXT_IOS_H
+#endif // RENDERING_CONTEXT_DRIVER_VULKAN_IOS_H
diff --git a/platform/ios/vulkan_context_ios.mm b/platform/ios/rendering_context_driver_vulkan_ios.mm
index 014e05f2e6..6a6af1bc41 100644
--- a/platform/ios/vulkan_context_ios.mm
+++ b/platform/ios/rendering_context_driver_vulkan_ios.mm
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* vulkan_context_ios.mm */
+/* rendering_context_driver_vulkan_ios.mm */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,36 +28,42 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#import "vulkan_context_ios.h"
+#import "rendering_context_driver_vulkan_ios.h"
#ifdef VULKAN_ENABLED
#ifdef USE_VOLK
#include <volk.h>
#else
-#include <vulkan/vulkan.h>
+#include <vulkan/vulkan_metal.h>
#endif
-const char *VulkanContextIOS::_get_platform_surface_extension() const {
- return VK_MVK_IOS_SURFACE_EXTENSION_NAME;
+const char *RenderingContextDriverVulkanIOS::_get_platform_surface_extension() const {
+ return VK_EXT_METAL_SURFACE_EXTENSION_NAME;
}
-Error VulkanContextIOS::window_create(DisplayServer::WindowID p_window_id, DisplayServer::VSyncMode p_vsync_mode, int p_width, int p_height, const void *p_platform_data) {
- const WindowPlatformData *wpd = (const WindowPlatformData *)p_platform_data;
+RenderingContextDriver::SurfaceID RenderingContextDriverVulkanIOS::surface_create(const void *p_platform_data) {
+ const WindowPlatformData *wpd = (const WindowPlatformData *)(p_platform_data);
- VkIOSSurfaceCreateInfoMVK createInfo = {};
- createInfo.sType = VK_STRUCTURE_TYPE_IOS_SURFACE_CREATE_INFO_MVK;
- createInfo.pView = (__bridge const void *)(*wpd->layer_ptr);
+ VkMetalSurfaceCreateInfoEXT create_info = {};
+ create_info.sType = VK_STRUCTURE_TYPE_METAL_SURFACE_CREATE_INFO_EXT;
+ create_info.pLayer = *wpd->layer_ptr;
- VkSurfaceKHR surface = VK_NULL_HANDLE;
- VkResult err = vkCreateIOSSurfaceMVK(get_instance(), &createInfo, nullptr, &surface);
- ERR_FAIL_COND_V(err, ERR_CANT_CREATE);
+ VkSurfaceKHR vk_surface = VK_NULL_HANDLE;
+ VkResult err = vkCreateMetalSurfaceEXT(instance_get(), &create_info, nullptr, &vk_surface);
+ ERR_FAIL_COND_V(err != VK_SUCCESS, SurfaceID());
- return _window_create(p_window_id, p_vsync_mode, surface, p_width, p_height);
+ Surface *surface = memnew(Surface);
+ surface->vk_surface = vk_surface;
+ return SurfaceID(surface);
}
-VulkanContextIOS::VulkanContextIOS() {}
+RenderingContextDriverVulkanIOS::RenderingContextDriverVulkanIOS() {
+ // Does nothing.
+}
-VulkanContextIOS::~VulkanContextIOS() {}
+RenderingContextDriverVulkanIOS::~RenderingContextDriverVulkanIOS() {
+ // Does nothing.
+}
#endif // VULKAN_ENABLED
diff --git a/platform/ios/view_controller.mm b/platform/ios/view_controller.mm
index 1f55670b68..6f6c04c2c8 100644
--- a/platform/ios/view_controller.mm
+++ b/platform/ios/view_controller.mm
@@ -78,13 +78,15 @@
us = u32lbl[0];
}
+ KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
+
if (!u32text.is_empty() && !u32text.begins_with("UIKey")) {
for (int i = 0; i < u32text.length(); i++) {
const char32_t c = u32text[i];
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true);
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), c, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
}
} else {
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true);
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, true, location);
}
}
}
@@ -110,7 +112,9 @@
us = u32lbl[0];
}
- DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false);
+ KeyLocation location = KeyMappingIOS::key_location(press.key.keyCode);
+
+ DisplayServerIOS::get_singleton()->key(fix_keycode(us, key), 0, fix_key_label(us, key), key, press.key.modifierFlags, false, location);
}
}
}