From 30783d57ccf6f368f21a84e408f56b86d05cba2b Mon Sep 17 00:00:00 2001 From: Sergey Minakov Date: Thu, 13 Aug 2020 18:24:39 +0300 Subject: [PATCH 1/4] iOS Modules: separate main platform code from modules Moved previously builtin modules 'GameCenter', 'AppStore', 'iCloud' to separate modules to be represented as plugin. Modified 'ARKit' and 'Camera' to not be builtin into engine and work as plugin. Changed platform code so it's not affected by the move. Modified Xcode project file to remove parameters that doesn't make any effect. Added basic '.gdip' plugin config file. --- .../godot_ios.xcodeproj/project.pbxproj | 75 ------------------- modules/SCsub | 9 ++- modules/arkit/arkit.gdip | 18 +++++ .../{register_types.cpp => arkit_module.cpp} | 4 +- .../{register_types.h => arkit_module.h} | 2 +- modules/camera/SCsub | 12 +-- modules/camera/config.py | 2 +- modules/camera/register_types.cpp | 6 -- modules/camera_iphone/SCsub | 15 ++++ modules/camera_iphone/camera.gdip | 18 +++++ .../{camera => camera_iphone}/camera_ios.h | 0 .../{camera => camera_iphone}/camera_ios.mm | 0 modules/camera_iphone/camera_module.cpp | 40 ++++++++++ modules/camera_iphone/camera_module.h | 32 ++++++++ modules/camera_iphone/config.py | 6 ++ modules/gamecenter/SCsub | 15 ++++ modules/gamecenter/config.py | 6 ++ .../gamecenter}/game_center.h | 4 - .../gamecenter}/game_center.mm | 37 ++++----- modules/gamecenter/game_center_delegate.h | 35 +++++++++ modules/gamecenter/game_center_delegate.mm | 45 +++++++++++ modules/gamecenter/game_center_module.cpp | 48 ++++++++++++ modules/gamecenter/game_center_module.h | 32 ++++++++ modules/gamecenter/gamecenter.gdip | 17 +++++ modules/icloud/SCsub | 15 ++++ modules/icloud/config.py | 6 ++ modules/icloud/icloud.gdip | 17 +++++ {platform/iphone => modules/icloud}/icloud.h | 4 - {platform/iphone => modules/icloud}/icloud.mm | 14 +--- modules/icloud/icloud_module.cpp | 48 ++++++++++++ modules/icloud/icloud_module.h | 32 ++++++++ modules/inappstore/SCsub | 15 ++++ modules/inappstore/config.py | 6 ++ .../inappstore}/in_app_store.h | 4 - .../inappstore}/in_app_store.mm | 4 - modules/inappstore/in_app_store_module.cpp | 48 ++++++++++++ modules/inappstore/in_app_store_module.h | 32 ++++++++ modules/inappstore/inappstore.gdip | 17 +++++ platform/iphone/SCsub | 3 - platform/iphone/app_delegate.mm | 1 + platform/iphone/detect.py | 15 ---- platform/iphone/os_iphone.h | 12 --- platform/iphone/os_iphone.mm | 33 -------- platform/iphone/view_controller.h | 3 +- platform/iphone/view_controller.mm | 11 +-- 45 files changed, 594 insertions(+), 224 deletions(-) create mode 100644 modules/arkit/arkit.gdip rename modules/arkit/{register_types.cpp => arkit_module.cpp} (96%) rename modules/arkit/{register_types.h => arkit_module.h} (97%) create mode 100644 modules/camera_iphone/SCsub create mode 100644 modules/camera_iphone/camera.gdip rename modules/{camera => camera_iphone}/camera_ios.h (100%) rename modules/{camera => camera_iphone}/camera_ios.mm (100%) create mode 100644 modules/camera_iphone/camera_module.cpp create mode 100644 modules/camera_iphone/camera_module.h create mode 100644 modules/camera_iphone/config.py create mode 100644 modules/gamecenter/SCsub create mode 100644 modules/gamecenter/config.py rename {platform/iphone => modules/gamecenter}/game_center.h (98%) rename {platform/iphone => modules/gamecenter}/game_center.mm (95%) create mode 100644 modules/gamecenter/game_center_delegate.h create mode 100644 modules/gamecenter/game_center_delegate.mm create mode 100644 modules/gamecenter/game_center_module.cpp create mode 100644 modules/gamecenter/game_center_module.h create mode 100644 modules/gamecenter/gamecenter.gdip create mode 100644 modules/icloud/SCsub create mode 100644 modules/icloud/config.py create mode 100644 modules/icloud/icloud.gdip rename {platform/iphone => modules/icloud}/icloud.h (98%) rename {platform/iphone => modules/icloud}/icloud.mm (98%) create mode 100644 modules/icloud/icloud_module.cpp create mode 100644 modules/icloud/icloud_module.h create mode 100644 modules/inappstore/SCsub create mode 100644 modules/inappstore/config.py rename {platform/iphone => modules/inappstore}/in_app_store.h (99%) rename {platform/iphone => modules/inappstore}/in_app_store.mm (99%) create mode 100644 modules/inappstore/in_app_store_module.cpp create mode 100644 modules/inappstore/in_app_store_module.h create mode 100644 modules/inappstore/inappstore.gdip diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index d8da520ed718..c46f64834a49 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -153,81 +153,6 @@ DevelopmentTeam = $team_id; ProvisioningStyle = Automatic; SystemCapabilities = { - com.apple.AccessWiFi = { - enabled = $access_wifi; - }; - com.apple.ApplePay = { - enabled = 0; - }; - com.apple.ApplicationGroups.iOS = { - enabled = 0; - }; - com.apple.AutoFillCredentialProvider = { - enabled = 0; - }; - com.apple.BackgroundModes = { - enabled = 0; - }; - com.apple.ClassKit = { - enabled = 0; - }; - com.apple.DataProtection = { - enabled = 0; - }; - com.apple.GameCenter.iOS = { - enabled = $game_center; - }; - com.apple.HealthKit = { - enabled = 0; - }; - com.apple.HomeKit = { - enabled = 0; - }; - com.apple.HotspotConfiguration = { - enabled = 0; - }; - com.apple.InAppPurchase = { - enabled = $in_app_purchases; - }; - com.apple.InterAppAudio = { - enabled = 0; - }; - com.apple.Keychain = { - enabled = 0; - }; - com.apple.Maps.iOS = { - enabled = 0; - }; - com.apple.Multipath = { - enabled = 0; - }; - com.apple.NearFieldCommunicationTagReading = { - enabled = 0; - }; - com.apple.NetworkExtensions.iOS = { - enabled = 0; - }; - com.apple.Push = { - enabled = $push_notifications; - }; - com.apple.SafariKeychain = { - enabled = 0; - }; - com.apple.Siri = { - enabled = 0; - }; - com.apple.VPNLite = { - enabled = 0; - }; - com.apple.WAC = { - enabled = 0; - }; - com.apple.Wallet = { - enabled = 0; - }; - com.apple.iCloud = { - enabled = 0; - }; }; }; }; diff --git a/modules/SCsub b/modules/SCsub index edfc4ed9c69e..24598f4b28bd 100644 --- a/modules/SCsub +++ b/modules/SCsub @@ -47,7 +47,14 @@ for name, path in env.module_list.items(): # Some modules are not linked automatically but can be enabled optionally # on iOS, so we handle those specially. - if env["platform"] == "iphone" and name in ["arkit", "camera"]: + if env["platform"] == "iphone" and name in [ + "arkit", + "camera", + "camera_iphone", + "gamecenter", + "inappstore", + "icloud", + ]: continue lib = env_modules.add_library("module_%s" % name, env.modules_sources) diff --git a/modules/arkit/arkit.gdip b/modules/arkit/arkit.gdip new file mode 100644 index 000000000000..22c0a07e2644 --- /dev/null +++ b/modules/arkit/arkit.gdip @@ -0,0 +1,18 @@ +[config] +name="ARKit" +binary="arkit_lib.a" + +initialization="register_arkit_types" +deinitialization="unregister_arkit_types" + +[dependencies] +linked=[] +embedded=[] +system=["AVFoundation.framework", "ARKit.framework"] + +capabilities=["arkit"] + +files=[] + +[plist] +NSCameraUsageDescription="Device camera is used for some functionality" diff --git a/modules/arkit/register_types.cpp b/modules/arkit/arkit_module.cpp similarity index 96% rename from modules/arkit/register_types.cpp rename to modules/arkit/arkit_module.cpp index 91069ab364bf..87ee3b87a50b 100644 --- a/modules/arkit/register_types.cpp +++ b/modules/arkit/arkit_module.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.cpp */ +/* arkit_module.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "register_types.h" +#include "arkit_module.h" #include "arkit_interface.h" diff --git a/modules/arkit/register_types.h b/modules/arkit/arkit_module.h similarity index 97% rename from modules/arkit/register_types.h rename to modules/arkit/arkit_module.h index f8939a1e3f97..8aa8175ed5ee 100644 --- a/modules/arkit/register_types.h +++ b/modules/arkit/arkit_module.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* register_types.h */ +/* arkit_module.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ diff --git a/modules/camera/SCsub b/modules/camera/SCsub index 631a65bde2b6..de97724d09dd 100644 --- a/modules/camera/SCsub +++ b/modules/camera/SCsub @@ -5,17 +5,7 @@ Import("env_modules") env_camera = env_modules.Clone() -if env["platform"] == "iphone": - # (iOS) Enable module support - env_camera.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) - - # (iOS) Build as separate static library - modules_sources = [] - env_camera.add_source_files(modules_sources, "register_types.cpp") - env_camera.add_source_files(modules_sources, "camera_ios.mm") - mod_lib = env_modules.add_library("#bin/libgodot_camera_module" + env["LIBSUFFIX"], modules_sources) - -elif env["platform"] == "windows": +if env["platform"] == "windows": env_camera.add_source_files(env.modules_sources, "register_types.cpp") env_camera.add_source_files(env.modules_sources, "camera_win.cpp") diff --git a/modules/camera/config.py b/modules/camera/config.py index 87d754274195..8a22751aa7b8 100644 --- a/modules/camera/config.py +++ b/modules/camera/config.py @@ -1,5 +1,5 @@ def can_build(env, platform): - return platform == "iphone" or platform == "osx" or platform == "windows" + return platform == "osx" or platform == "windows" def configure(env): diff --git a/modules/camera/register_types.cpp b/modules/camera/register_types.cpp index 3b6c91691413..9479310a13d6 100644 --- a/modules/camera/register_types.cpp +++ b/modules/camera/register_types.cpp @@ -33,9 +33,6 @@ #if defined(WINDOWS_ENABLED) #include "camera_win.h" #endif -#if defined(IPHONE_ENABLED) -#include "camera_ios.h" -#endif #if defined(OSX_ENABLED) #include "camera_osx.h" #endif @@ -44,9 +41,6 @@ void register_camera_types() { #if defined(WINDOWS_ENABLED) CameraServer::make_default(); #endif -#if defined(IPHONE_ENABLED) - CameraServer::make_default(); -#endif #if defined(OSX_ENABLED) CameraServer::make_default(); #endif diff --git a/modules/camera_iphone/SCsub b/modules/camera_iphone/SCsub new file mode 100644 index 000000000000..0a37d9a6f53a --- /dev/null +++ b/modules/camera_iphone/SCsub @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_camera = env_modules.Clone() + +# (iOS) Enable module support +env_camera.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) + +# (iOS) Build as separate static library +modules_sources = [] +env_camera.add_source_files(modules_sources, "*.cpp") +env_camera.add_source_files(modules_sources, "*.mm") +mod_lib = env_modules.add_library("#bin/libgodot_camera_module" + env["LIBSUFFIX"], modules_sources) diff --git a/modules/camera_iphone/camera.gdip b/modules/camera_iphone/camera.gdip new file mode 100644 index 000000000000..09017b8d27d7 --- /dev/null +++ b/modules/camera_iphone/camera.gdip @@ -0,0 +1,18 @@ +[config] +name="Camera" +binary="camera_lib.a" + +initialization="register_camera_types" +deinitialization="unregister_camera_types" + +[dependencies] +linked=[] +embedded=[] +system=["AVFoundation.framework"] + +capabilities=[] + +files=[] + +[plist] +NSCameraUsageDescription="Device camera is used for some functionality" diff --git a/modules/camera/camera_ios.h b/modules/camera_iphone/camera_ios.h similarity index 100% rename from modules/camera/camera_ios.h rename to modules/camera_iphone/camera_ios.h diff --git a/modules/camera/camera_ios.mm b/modules/camera_iphone/camera_ios.mm similarity index 100% rename from modules/camera/camera_ios.mm rename to modules/camera_iphone/camera_ios.mm diff --git a/modules/camera_iphone/camera_module.cpp b/modules/camera_iphone/camera_module.cpp new file mode 100644 index 000000000000..f3d00be20456 --- /dev/null +++ b/modules/camera_iphone/camera_module.cpp @@ -0,0 +1,40 @@ +/*************************************************************************/ +/* camera_module.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "camera_module.h" + +#include "camera_ios.h" + +void register_camera_types() { + CameraServer::make_default(); +} + +void unregister_camera_types() { +} diff --git a/modules/camera_iphone/camera_module.h b/modules/camera_iphone/camera_module.h new file mode 100644 index 000000000000..d123071a70a0 --- /dev/null +++ b/modules/camera_iphone/camera_module.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* camera_module.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +void register_camera_types(); +void unregister_camera_types(); diff --git a/modules/camera_iphone/config.py b/modules/camera_iphone/config.py new file mode 100644 index 000000000000..e68603fc93bc --- /dev/null +++ b/modules/camera_iphone/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return platform == "iphone" + + +def configure(env): + pass diff --git a/modules/gamecenter/SCsub b/modules/gamecenter/SCsub new file mode 100644 index 000000000000..72fbf7ab0e55 --- /dev/null +++ b/modules/gamecenter/SCsub @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_gamecenter = env_modules.Clone() + +# (iOS) Enable module support +env_gamecenter.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) + +# (iOS) Build as separate static library +modules_sources = [] +env_gamecenter.add_source_files(modules_sources, "*.cpp") +env_gamecenter.add_source_files(modules_sources, "*.mm") +mod_lib = env_modules.add_library("#bin/libgodot_gamecenter_module" + env["LIBSUFFIX"], modules_sources) diff --git a/modules/gamecenter/config.py b/modules/gamecenter/config.py new file mode 100644 index 000000000000..e68603fc93bc --- /dev/null +++ b/modules/gamecenter/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return platform == "iphone" + + +def configure(env): + pass diff --git a/platform/iphone/game_center.h b/modules/gamecenter/game_center.h similarity index 98% rename from platform/iphone/game_center.h rename to modules/gamecenter/game_center.h index cbfd616e5611..76fd295460c4 100644 --- a/platform/iphone/game_center.h +++ b/modules/gamecenter/game_center.h @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef GAME_CENTER_ENABLED - #ifndef GAME_CENTER_H #define GAME_CENTER_H @@ -71,5 +69,3 @@ class GameCenter : public Object { }; #endif - -#endif diff --git a/platform/iphone/game_center.mm b/modules/gamecenter/game_center.mm similarity index 95% rename from platform/iphone/game_center.mm rename to modules/gamecenter/game_center.mm index 0f8c0100c3bc..114f639a3271 100644 --- a/platform/iphone/game_center.mm +++ b/modules/gamecenter/game_center.mm @@ -28,28 +28,15 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef GAME_CENTER_ENABLED - #include "game_center.h" +#import "platform/iphone/app_delegate.h" -#ifdef __IPHONE_9_0 - -#import -extern "C" { - -#else - -extern "C" { +#import "game_center_delegate.h" +#import "platform/iphone/view_controller.h" #import -#endif - -#import "app_delegate.h" -}; - -#import "view_controller.h" - GameCenter *GameCenter::instance = NULL; +GodotGameCenterDelegate *gameCenterDelegate = nil; void GameCenter::_bind_methods() { ClassDB::bind_method(D_METHOD("authenticate"), &GameCenter::authenticate); @@ -76,7 +63,7 @@ GKLocalPlayer *player = [GKLocalPlayer localPlayer]; ERR_FAIL_COND_V(![player respondsToSelector:@selector(authenticateHandler)], ERR_UNAVAILABLE); - ViewController *root_controller = (ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; + UIViewController *root_controller = [[UIApplication sharedApplication] delegate].window.rootViewController; ERR_FAIL_COND_V(!root_controller, FAILED); // This handler is called several times. First when the view needs to be shown, then again @@ -305,10 +292,10 @@ GKGameCenterViewController *controller = [[GKGameCenterViewController alloc] init]; ERR_FAIL_COND_V(!controller, FAILED); - ViewController *root_controller = (ViewController *)((AppDelegate *)[[UIApplication sharedApplication] delegate]).window.rootViewController; + UIViewController *root_controller = [[UIApplication sharedApplication] delegate].window.rootViewController; ERR_FAIL_COND_V(!root_controller, FAILED); - controller.gameCenterDelegate = root_controller; + controller.gameCenterDelegate = gameCenterDelegate; controller.viewState = view_state; if (view_state == GKGameCenterViewControllerStateLeaderboards) { controller.leaderboardIdentifier = nil; @@ -382,8 +369,12 @@ ERR_FAIL_COND(instance != NULL); instance = this; authenticated = false; -}; -GameCenter::~GameCenter() {} + gameCenterDelegate = [[GodotGameCenterDelegate alloc] init]; +}; -#endif +GameCenter::~GameCenter() { + if (gameCenterDelegate) { + gameCenterDelegate = nil; + } +} diff --git a/modules/gamecenter/game_center_delegate.h b/modules/gamecenter/game_center_delegate.h new file mode 100644 index 000000000000..1b7025f9157e --- /dev/null +++ b/modules/gamecenter/game_center_delegate.h @@ -0,0 +1,35 @@ +/*************************************************************************/ +/* game_center_delegate.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#import + +@interface GodotGameCenterDelegate : NSObject + +@end diff --git a/modules/gamecenter/game_center_delegate.mm b/modules/gamecenter/game_center_delegate.mm new file mode 100644 index 000000000000..9a10c439c611 --- /dev/null +++ b/modules/gamecenter/game_center_delegate.mm @@ -0,0 +1,45 @@ +/*************************************************************************/ +/* game_center_delegate.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +#import "game_center_delegate.h" + +#include "game_center.h" + +@implementation GodotGameCenterDelegate + +- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { + //[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone + if (GameCenter::get_singleton()) { + GameCenter::get_singleton()->game_center_closed(); + } + [gameCenterViewController dismissViewControllerAnimated:YES completion:nil]; +} + +@end diff --git a/modules/gamecenter/game_center_module.cpp b/modules/gamecenter/game_center_module.cpp new file mode 100644 index 000000000000..6c5157345f38 --- /dev/null +++ b/modules/gamecenter/game_center_module.cpp @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* game_center_module.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "game_center_module.h" + +#include "core/config/engine.h" + +#include "game_center.h" + +GameCenter *game_center; + +void register_gamecenter_types() { + game_center = memnew(GameCenter); + Engine::get_singleton()->add_singleton(Engine::Singleton("GameCenter", game_center)); +} + +void unregister_gamecenter_types() { + if (game_center) { + memdelete(game_center); + } +} diff --git a/modules/gamecenter/game_center_module.h b/modules/gamecenter/game_center_module.h new file mode 100644 index 000000000000..8da3ae02ee4c --- /dev/null +++ b/modules/gamecenter/game_center_module.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* game_center_module.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +void register_gamecenter_types(); +void unregister_gamecenter_types(); diff --git a/modules/gamecenter/gamecenter.gdip b/modules/gamecenter/gamecenter.gdip new file mode 100644 index 000000000000..eb44effbddd1 --- /dev/null +++ b/modules/gamecenter/gamecenter.gdip @@ -0,0 +1,17 @@ +[config] +name="GameCenter" +binary="gamecenter_lib.a" + +initialization="register_gamecenter_types" +deinitialization="unregister_gamecenter_types" + +[dependencies] +linked=[] +embedded=[] +system=["GameKit.framework"] + +capabilities=["gamekit"] + +files=[] + +[plist] diff --git a/modules/icloud/SCsub b/modules/icloud/SCsub new file mode 100644 index 000000000000..805a48460035 --- /dev/null +++ b/modules/icloud/SCsub @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_icloud = env_modules.Clone() + +# (iOS) Enable module support +env_icloud.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) + +# (iOS) Build as separate static library +modules_sources = [] +env_icloud.add_source_files(modules_sources, "*.cpp") +env_icloud.add_source_files(modules_sources, "*.mm") +mod_lib = env_modules.add_library("#bin/libgodot_icloud_module" + env["LIBSUFFIX"], modules_sources) diff --git a/modules/icloud/config.py b/modules/icloud/config.py new file mode 100644 index 000000000000..e68603fc93bc --- /dev/null +++ b/modules/icloud/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return platform == "iphone" + + +def configure(env): + pass diff --git a/modules/icloud/icloud.gdip b/modules/icloud/icloud.gdip new file mode 100644 index 000000000000..9f81be8a346a --- /dev/null +++ b/modules/icloud/icloud.gdip @@ -0,0 +1,17 @@ +[config] +name="iCloud" +binary="icloud_lib.a" + +initialization="register_icloud_types" +deinitialization="unregister_icloud_types" + +[dependencies] +linked=[] +embedded=[] +system=[] + +capabilities=[] + +files=[] + +[plist] diff --git a/platform/iphone/icloud.h b/modules/icloud/icloud.h similarity index 98% rename from platform/iphone/icloud.h rename to modules/icloud/icloud.h index 5f59abdfc0bb..35eede0bf9ef 100644 --- a/platform/iphone/icloud.h +++ b/modules/icloud/icloud.h @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef ICLOUD_ENABLED - #ifndef ICLOUD_H #define ICLOUD_H @@ -60,5 +58,3 @@ class ICloud : public Object { }; #endif - -#endif diff --git a/platform/iphone/icloud.mm b/modules/icloud/icloud.mm similarity index 98% rename from platform/iphone/icloud.mm rename to modules/icloud/icloud.mm index 3d8134988347..8a8ddbefe968 100644 --- a/platform/iphone/icloud.mm +++ b/modules/icloud/icloud.mm @@ -28,22 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef ICLOUD_ENABLED - #include "icloud.h" -#ifndef __IPHONE_9_0 -extern "C" { -#endif - -#import "app_delegate.h" +#import "platform/iphone/app_delegate.h" #import -#ifndef __IPHONE_9_0 -}; -#endif - ICloud *ICloud::instance = NULL; void ICloud::_bind_methods() { @@ -353,5 +343,3 @@ Variant nsobject_to_variant(NSObject *object) { } ICloud::~ICloud() {} - -#endif diff --git a/modules/icloud/icloud_module.cpp b/modules/icloud/icloud_module.cpp new file mode 100644 index 000000000000..43fdc7d45ed6 --- /dev/null +++ b/modules/icloud/icloud_module.cpp @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* icloud_module.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "icloud_module.h" + +#include "core/config/engine.h" + +#include "icloud.h" + +ICloud *icloud; + +void register_icloud_types() { + icloud = memnew(ICloud); + Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud)); +} + +void unregister_icloud_types() { + if (icloud) { + memdelete(icloud); + } +} diff --git a/modules/icloud/icloud_module.h b/modules/icloud/icloud_module.h new file mode 100644 index 000000000000..7fd057525ea8 --- /dev/null +++ b/modules/icloud/icloud_module.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* icloud_module.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +void register_icloud_types(); +void unregister_icloud_types(); diff --git a/modules/inappstore/SCsub b/modules/inappstore/SCsub new file mode 100644 index 000000000000..cee6a256d5e5 --- /dev/null +++ b/modules/inappstore/SCsub @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +Import("env") +Import("env_modules") + +env_inappstore = env_modules.Clone() + +# (iOS) Enable module support +env_inappstore.Append(CCFLAGS=["-fmodules", "-fcxx-modules"]) + +# (iOS) Build as separate static library +modules_sources = [] +env_inappstore.add_source_files(modules_sources, "*.cpp") +env_inappstore.add_source_files(modules_sources, "*.mm") +mod_lib = env_modules.add_library("#bin/libgodot_inappstore_module" + env["LIBSUFFIX"], modules_sources) diff --git a/modules/inappstore/config.py b/modules/inappstore/config.py new file mode 100644 index 000000000000..e68603fc93bc --- /dev/null +++ b/modules/inappstore/config.py @@ -0,0 +1,6 @@ +def can_build(env, platform): + return platform == "iphone" + + +def configure(env): + pass diff --git a/platform/iphone/in_app_store.h b/modules/inappstore/in_app_store.h similarity index 99% rename from platform/iphone/in_app_store.h rename to modules/inappstore/in_app_store.h index 85075e4e2038..c8e5d17cec62 100644 --- a/platform/iphone/in_app_store.h +++ b/modules/inappstore/in_app_store.h @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef STOREKIT_ENABLED - #ifndef IN_APP_STORE_H #define IN_APP_STORE_H @@ -77,5 +75,3 @@ class InAppStore : public Object { }; #endif - -#endif diff --git a/platform/iphone/in_app_store.mm b/modules/inappstore/in_app_store.mm similarity index 99% rename from platform/iphone/in_app_store.mm rename to modules/inappstore/in_app_store.mm index 3eec9dae693a..62977318c191 100644 --- a/platform/iphone/in_app_store.mm +++ b/modules/inappstore/in_app_store.mm @@ -28,8 +28,6 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef STOREKIT_ENABLED - #include "in_app_store.h" #import @@ -411,5 +409,3 @@ - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)tran [[SKPaymentQueue defaultQueue] removeTransactionObserver:transactions_observer]; transactions_observer = nil; } - -#endif diff --git a/modules/inappstore/in_app_store_module.cpp b/modules/inappstore/in_app_store_module.cpp new file mode 100644 index 000000000000..039bdd4f83a7 --- /dev/null +++ b/modules/inappstore/in_app_store_module.cpp @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* in_app_store_module.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 "in_app_store_module.h" + +#include "core/config/engine.h" + +#include "in_app_store.h" + +InAppStore *store_kit; + +void register_inappstore_types() { + store_kit = memnew(InAppStore); + Engine::get_singleton()->add_singleton(Engine::Singleton("InAppStore", store_kit)); +} + +void unregister_inappstore_types() { + if (store_kit) { + memdelete(store_kit); + } +} diff --git a/modules/inappstore/in_app_store_module.h b/modules/inappstore/in_app_store_module.h new file mode 100644 index 000000000000..44673e58bcd4 --- /dev/null +++ b/modules/inappstore/in_app_store_module.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* in_app_store_module.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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. */ +/*************************************************************************/ + +void register_inappstore_types(); +void unregister_inappstore_types(); diff --git a/modules/inappstore/inappstore.gdip b/modules/inappstore/inappstore.gdip new file mode 100644 index 000000000000..7a5efb8ad396 --- /dev/null +++ b/modules/inappstore/inappstore.gdip @@ -0,0 +1,17 @@ +[config] +name="InAppStore" +binary="inappstore_lib.a" + +initialization="register_inappstore_types" +deinitialization="unregister_inappstore_types" + +[dependencies] +linked=[] +embedded=[] +system=["StoreKit.framework"] + +capabilities=[] + +files=[] + +[plist] diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index 1dd37dabe579..0a558f8e3db5 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -8,9 +8,6 @@ iphone_lib = [ "main.m", "app_delegate.mm", "view_controller.mm", - "game_center.mm", - "in_app_store.mm", - "icloud.mm", "ios.mm", "vulkan_context_iphone.mm", "display_server_iphone.mm", diff --git a/platform/iphone/app_delegate.mm b/platform/iphone/app_delegate.mm index c9891309fea2..c1942e77dd60 100644 --- a/platform/iphone/app_delegate.mm +++ b/platform/iphone/app_delegate.mm @@ -36,6 +36,7 @@ #include "os_iphone.h" #import "view_controller.h" +#import #import #define kRenderingFrequency 60 diff --git a/platform/iphone/detect.py b/platform/iphone/detect.py index ab453c353fe2..0456458326b9 100644 --- a/platform/iphone/detect.py +++ b/platform/iphone/detect.py @@ -35,9 +35,6 @@ def get_opts(): " validation layers)", False, ), - BoolVariable("game_center", "Support for game center", True), - BoolVariable("store_kit", "Support for in-app store", True), - BoolVariable("icloud", "Support for iCloud", True), BoolVariable("ios_exceptions", "Enable exceptions", False), ("ios_triple", "Triple for ios toolchain", ""), ] @@ -222,18 +219,6 @@ def configure(env): ] ) - # Feature options - if env["game_center"]: - env.Append(CPPDEFINES=["GAME_CENTER_ENABLED"]) - env.Append(LINKFLAGS=["-framework", "GameKit"]) - - if env["store_kit"]: - env.Append(CPPDEFINES=["STOREKIT_ENABLED"]) - env.Append(LINKFLAGS=["-framework", "StoreKit"]) - - if env["icloud"]: - env.Append(CPPDEFINES=["ICLOUD_ENABLED"]) - env.Prepend( CPPPATH=[ "$IPHONESDK/usr/include", diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index c6f95869ee0c..f0854cf98b69 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -35,9 +35,6 @@ #include "drivers/coreaudio/audio_driver_coreaudio.h" #include "drivers/unix/os_unix.h" -#include "game_center.h" -#include "icloud.h" -#include "in_app_store.h" #include "ios.h" #include "joypad_iphone.h" #include "servers/audio_server.h" @@ -55,15 +52,6 @@ class OSIPhone : public OS_Unix { AudioDriverCoreAudio audio_driver; -#ifdef GAME_CENTER_ENABLED - GameCenter *game_center; -#endif -#ifdef STOREKIT_ENABLED - InAppStore *store_kit; -#endif -#ifdef ICLOUD_ENABLED - ICloud *icloud; -#endif iOS *ios; JoypadIPhone *joypad_iphone; diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index 32e9dda92bf2..a749ac7e06a7 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -125,21 +125,6 @@ void register_dynamic_symbol(char *name, void *address) { } void OSIPhone::initialize_modules() { -#ifdef GAME_CENTER_ENABLED - game_center = memnew(GameCenter); - Engine::get_singleton()->add_singleton(Engine::Singleton("GameCenter", game_center)); -#endif - -#ifdef STOREKIT_ENABLED - store_kit = memnew(InAppStore); - Engine::get_singleton()->add_singleton(Engine::Singleton("InAppStore", store_kit)); -#endif - -#ifdef ICLOUD_ENABLED - icloud = memnew(ICloud); - Engine::get_singleton()->add_singleton(Engine::Singleton("ICloud", icloud)); -#endif - ios = memnew(iOS); Engine::get_singleton()->add_singleton(Engine::Singleton("iOS", ios)); @@ -154,24 +139,6 @@ void register_dynamic_symbol(char *name, void *address) { if (ios) { memdelete(ios); } - -#ifdef GAME_CENTER_ENABLED - if (game_center) { - memdelete(game_center); - } -#endif - -#ifdef STOREKIT_ENABLED - if (store_kit) { - memdelete(store_kit); - } -#endif - -#ifdef ICLOUD_ENABLED - if (icloud) { - memdelete(icloud); - } -#endif } void OSIPhone::set_main_loop(MainLoop *p_main_loop) { diff --git a/platform/iphone/view_controller.h b/platform/iphone/view_controller.h index b0b31ae377c7..2cc4e4c38883 100644 --- a/platform/iphone/view_controller.h +++ b/platform/iphone/view_controller.h @@ -28,13 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#import #import @class GodotView; @class GodotNativeVideoView; -@interface ViewController : UIViewController +@interface ViewController : UIViewController @property(nonatomic, readonly, strong) GodotView *godotView; @property(nonatomic, readonly, strong) GodotNativeVideoView *videoView; diff --git a/platform/iphone/view_controller.mm b/platform/iphone/view_controller.mm index e11eff423b24..5d18a72be12b 100644 --- a/platform/iphone/view_controller.mm +++ b/platform/iphone/view_controller.mm @@ -36,6 +36,7 @@ #import "native_video_view.h" #include "os_iphone.h" +#import #import @interface ViewController () @@ -214,14 +215,4 @@ - (BOOL)playVideoAtPath:(NSString *)filePath volume:(float)videoVolume audio:(NS } } -// MARK: Delegates - -#ifdef GAME_CENTER_ENABLED -- (void)gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController { - //[gameCenterViewController dismissViewControllerAnimated:YES completion:^{GameCenter::get_singleton()->game_center_closed();}];//version for signaling when overlay is completely gone - GameCenter::get_singleton()->game_center_closed(); - [gameCenterViewController dismissViewControllerAnimated:YES completion:nil]; -} -#endif - @end From 70f492082e5a63db0f10127f379388abd80d766f Mon Sep 17 00:00:00 2001 From: Sergey Minakov Date: Thu, 13 Aug 2020 18:30:54 +0300 Subject: [PATCH 2/4] iOS: change platform code to support plugins --- platform/iphone/os_iphone.h | 3 +++ platform/iphone/os_iphone.mm | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/platform/iphone/os_iphone.h b/platform/iphone/os_iphone.h index f0854cf98b69..04a0a478d5db 100644 --- a/platform/iphone/os_iphone.h +++ b/platform/iphone/os_iphone.h @@ -45,6 +45,9 @@ #include "platform/iphone/vulkan_context_iphone.h" #endif +extern void godot_ios_plugins_initialize(); +extern void godot_ios_plugins_deinitialize(); + class OSIPhone : public OS_Unix { private: static HashMap dynamic_symbol_lookup_table; diff --git a/platform/iphone/os_iphone.mm b/platform/iphone/os_iphone.mm index a749ac7e06a7..b87e6f37a031 100644 --- a/platform/iphone/os_iphone.mm +++ b/platform/iphone/os_iphone.mm @@ -139,9 +139,13 @@ void register_dynamic_symbol(char *name, void *address) { if (ios) { memdelete(ios); } + + godot_ios_plugins_deinitialize(); } void OSIPhone::set_main_loop(MainLoop *p_main_loop) { + godot_ios_plugins_initialize(); + main_loop = p_main_loop; if (main_loop) { From 1f94a59859e3be74009aa12cf4dcdb25cb5a6c2f Mon Sep 17 00:00:00 2001 From: Sergey Minakov Date: Thu, 13 Aug 2020 18:33:41 +0300 Subject: [PATCH 3/4] iOS Export: export modification to support plugins Added plugin configuration. Export options now use plugins that could be enabled/disabled. Plugin changes are observed at runtime. --- .../godot_ios.xcodeproj/project.pbxproj | 4 +- platform/iphone/export/export.cpp | 394 ++++++++++++++---- platform/iphone/plugin/godot_plugin_config.h | 238 +++++++++++ 3 files changed, 558 insertions(+), 78 deletions(-) create mode 100644 platform/iphone/plugin/godot_plugin_config.h diff --git a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj index c46f64834a49..bd2188325987 100644 --- a/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj +++ b/misc/dist/ios_xcode/godot_ios.xcodeproj/project.pbxproj @@ -318,7 +318,7 @@ ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)", + "$(PROJECT_DIR)/**", ); PRODUCT_BUNDLE_IDENTIFIER = $bundle_identifier; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -348,7 +348,7 @@ ); LIBRARY_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)", + "$(PROJECT_DIR)/**", ); PRODUCT_BUNDLE_IDENTIFIER = $bundle_identifier; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index cf46883b92a1..7cca0f390d12 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -43,6 +43,7 @@ #include "editor/editor_settings.h" #include "main/splash.gen.h" #include "platform/iphone/logo.gen.h" +#include "platform/iphone/plugin/godot_plugin_config.h" #include "string.h" #include @@ -54,6 +55,13 @@ class EditorExportPlatformIOS : public EditorExportPlatform { Ref logo; + // Plugins + volatile bool plugins_changed; + Thread *check_for_changes_thread; + volatile bool quit_request; + Mutex plugins_lock; + Vector plugins; + typedef Error (*FileHandler)(String p_file, void *p_userdata); static Error _walk_dir_recursive(DirAccess *p_da, FileHandler p_handler, void *p_userdata); static Error _codesign(String p_file, void *p_userdata); @@ -70,6 +78,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { String modules_fileref; String modules_buildphase; String modules_buildgrp; + Vector capabilities; }; struct ExportArchitecture { String name; @@ -103,6 +112,7 @@ class EditorExportPlatformIOS : public EditorExportPlatform { void _add_assets_to_project(const Ref &p_preset, Vector &p_project_data, const Vector &p_additional_assets); Error _export_additional_assets(const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets); Error _export_additional_assets(const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets); + Error _export_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets); bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { String pname = p_package; @@ -127,6 +137,40 @@ class EditorExportPlatformIOS : public EditorExportPlatform { return true; } + static void _check_for_changes_poll_thread(void *ud) { + EditorExportPlatformIOS *ea = (EditorExportPlatformIOS *)ud; + + while (!ea->quit_request) { + // Nothing to do if we already know the plugins have changed. + if (!ea->plugins_changed) { + MutexLock lock(ea->plugins_lock); + + Vector loaded_plugins = get_plugins(); + + if (ea->plugins.size() != loaded_plugins.size()) { + ea->plugins_changed = true; + } 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 = true; + break; + } + } + } + } + + 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(300000); + + if (ea->quit_request) { + break; + } + } + } + } + protected: virtual void get_preset_features(const Ref &p_preset, List *r_features) override; virtual void get_export_options(List *r_options) override; @@ -136,13 +180,21 @@ class EditorExportPlatformIOS : public EditorExportPlatform { virtual String get_os_name() const override { return "iOS"; } virtual Ref get_logo() const override { return logo; } + virtual bool should_update_export_options() override { + bool export_options_changed = plugins_changed; + if (export_options_changed) { + // don't clear unless we're reporting true, to avoid race + plugins_changed = false; + } + return export_options_changed; + } + virtual List get_binary_extensions(const Ref &p_preset) const override { List list; list.push_back("ipa"); return list; } virtual Error export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags = 0) override; - virtual void add_module_code(const Ref &p_preset, IOSConfigData &p_config_data, const String &p_name, const String &p_fid, const String &p_gid); virtual bool can_export(const Ref &p_preset, String &r_error, bool &r_missing_templates) const override; @@ -156,6 +208,85 @@ class EditorExportPlatformIOS : public EditorExportPlatform { EditorExportPlatformIOS(); ~EditorExportPlatformIOS(); + + /// List the gdip files in the directory specified by the p_path parameter. + static Vector list_plugin_config_files(const String &p_path, bool p_check_directories) { + Vector dir_files; + DirAccessRef da = DirAccess::open(p_path); + if (da) { + da->list_dir_begin(); + while (true) { + String file = da->get_next(); + if (file.empty()) { + break; + } + + if (file == "." || file == "..") { + continue; + } + + if (da->current_is_hidden()) { + continue; + } + + if (da->current_is_dir()) { + if (p_check_directories) { + Vector directory_files = list_plugin_config_files(p_path.plus_file(file), false); + for (int i = 0; i < directory_files.size(); ++i) { + dir_files.push_back(file.plus_file(directory_files[i])); + } + } + + continue; + } + + if (file.ends_with(PLUGIN_CONFIG_EXT)) { + dir_files.push_back(file); + } + } + da->list_dir_end(); + } + + return dir_files; + } + + static Vector get_plugins() { + Vector loaded_plugins; + + String plugins_dir = ProjectSettings::get_singleton()->get_resource_path().plus_file("ios/plugins"); + + if (DirAccess::exists(plugins_dir)) { + Vector plugins_filenames = list_plugin_config_files(plugins_dir, true); + + if (!plugins_filenames.empty()) { + Ref config_file = memnew(ConfigFile); + for (int i = 0; i < plugins_filenames.size(); i++) { + PluginConfig config = load_plugin_config(config_file, plugins_dir.plus_file(plugins_filenames[i])); + if (config.valid_config) { + loaded_plugins.push_back(config); + } else { + print_error("Invalid plugin config file " + plugins_filenames[i]); + } + } + } + } + + return loaded_plugins; + } + + static Vector get_enabled_plugins(const Ref &p_presets) { + Vector enabled_plugins; + Vector all_plugins = get_plugins(); + for (int i = 0; i < all_plugins.size(); i++) { + PluginConfig plugin = all_plugins[i]; + bool enabled = p_presets->get("plugins/" + plugin.name); + if (enabled) { + enabled_plugins.push_back(plugin); + } + } + + return enabled_plugins; + } }; void EditorExportPlatformIOS::get_preset_features(const Ref &p_preset, List *r_features) { @@ -224,12 +355,16 @@ void EditorExportPlatformIOS::get_export_options(List *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/version"), "1.0")); r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/arkit"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/camera"), false)); + Vector found_plugins = get_plugins(); + + for (int i = 0; i < found_plugins.size(); i++) { + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "plugins/" + found_plugins[i].name), false)); + } + + plugins_changed = false; + plugins = found_plugins; r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/access_wifi"), false)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/game_center"), true)); - r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/in_app_purchases"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "capabilities/push_notifications"), false)); r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "user_data/accessible_from_files_app"), false)); @@ -345,18 +480,6 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ strnew += lines[i].replace("$docs_in_place", ((bool)p_preset->get("user_data/accessible_from_files_app")) ? "" : "") + "\n"; } else if (lines[i].find("$docs_sharing") != -1) { strnew += lines[i].replace("$docs_sharing", ((bool)p_preset->get("user_data/accessible_from_itunes_sharing")) ? "" : "") + "\n"; - } else if (lines[i].find("$access_wifi") != -1) { - bool is_on = p_preset->get("capabilities/access_wifi"); - strnew += lines[i].replace("$access_wifi", is_on ? "1" : "0") + "\n"; - } else if (lines[i].find("$game_center") != -1) { - bool is_on = p_preset->get("capabilities/game_center"); - strnew += lines[i].replace("$game_center", is_on ? "1" : "0") + "\n"; - } else if (lines[i].find("$in_app_purchases") != -1) { - bool is_on = p_preset->get("capabilities/in_app_purchases"); - strnew += lines[i].replace("$in_app_purchases", is_on ? "1" : "0") + "\n"; - } else if (lines[i].find("$push_notifications") != -1) { - bool is_on = p_preset->get("capabilities/push_notifications"); - strnew += lines[i].replace("$push_notifications", is_on ? "1" : "0") + "\n"; } else if (lines[i].find("$entitlements_push_notifications") != -1) { bool is_on = p_preset->get("capabilities/push_notifications"); strnew += lines[i].replace("$entitlements_push_notifications", is_on ? "aps-environmentdevelopment" : "") + "\n"; @@ -366,15 +489,14 @@ void EditorExportPlatformIOS::_fix_config_file(const Ref &p_ // I've removed armv7 as we can run on 64bit only devices // Note that capabilities listed here are requirements for the app to be installed. // They don't enable anything. + Vector capabilities_list = p_config.capabilities; - if ((bool)p_preset->get("capabilities/arkit")) { - capabilities += "arkit\n"; - } - if ((bool)p_preset->get("capabilities/game_center")) { - capabilities += "gamekit\n"; + if ((bool)p_preset->get("capabilities/access_wifi") && !capabilities_list.has("wifi")) { + capabilities_list.push_back("wifi"); } - if ((bool)p_preset->get("capabilities/access_wifi")) { - capabilities += "wifi\n"; + + for (int idx = 0; idx < capabilities_list.size(); idx++) { + capabilities += "" + capabilities_list[idx] + "\n"; } strnew += lines[i].replace("$required_device_capabilities", capabilities); @@ -984,28 +1106,6 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Refget("capabilities/arkit")) { - String build_id = (++current_id).str(); - String ref_id = (++current_id).str(); - - if (pbx_frameworks_build.length() > 0) { - pbx_frameworks_build += ",\n"; - pbx_frameworks_refs += ",\n"; - } - - pbx_frameworks_build += build_id; - pbx_frameworks_refs += ref_id; - - Dictionary format_dict; - format_dict["build_id"] = build_id; - format_dict["ref_id"] = ref_id; - format_dict["name"] = "ARKit.framework"; - format_dict["file_path"] = "System/Library/Frameworks/ARKit.framework"; - format_dict["file_type"] = "wrapper.framework"; - pbx_files += file_info_format.format(format_dict, "$_"); - } - String str = String::utf8((const char *)p_project_data.ptr(), p_project_data.size()); str = str.replace("$additional_pbx_files", pbx_files); str = str.replace("$additional_pbx_frameworks_build", pbx_frameworks_build); @@ -1202,20 +1302,165 @@ Vector EditorExportPlatformIOS::_get_preset_architectures(const Ref &p_preset, EditorExportPlatformIOS::IOSConfigData &p_config_data, const String &p_name, const String &p_fid, const String &p_gid) { - if ((bool)p_preset->get("capabilities/" + p_name)) { - //add module static library - print_line("ADDING MODULE: " + p_name); +Error EditorExportPlatformIOS::_export_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets) { + String plugin_definition_cpp_code; + String plugin_initialization_cpp_code; + String plugin_deinitialization_cpp_code; - p_config_data.modules_buildfile += p_gid + " /* libgodot_" + p_name + "_module.a in Frameworks */ = {isa = PBXBuildFile; fileRef = " + p_fid + " /* libgodot_" + p_name + "_module.a */; };\n\t\t"; - p_config_data.modules_fileref += p_fid + " /* libgodot_" + p_name + "_module.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = godot_" + p_name + "_module ; path = \"libgodot_" + p_name + "_module.a\"; sourceTree = \"\"; };\n\t\t"; - p_config_data.modules_buildphase += p_gid + " /* libgodot_" + p_name + "_module.a */,\n\t\t\t\t"; - p_config_data.modules_buildgrp += p_fid + " /* libgodot_" + p_name + "_module.a */,\n\t\t\t\t"; - } else { - //add stub function for disabled module - p_config_data.cpp_code += "void register_" + p_name + "_types() { /*stub*/ };\n"; - p_config_data.cpp_code += "void unregister_" + p_name + "_types() { /*stub*/ };\n"; + Vector plugin_libraries; + Vector plugin_linked_dependencies; + Vector plugin_embedded_dependencies; + Vector plugin_files; + + Vector enabled_plugins = get_enabled_plugins(p_preset); + + Vector added_linked_dependenciy_names; + Vector added_embedded_dependenciy_names; + HashMap plist_values; + + for (int i = 0; i < enabled_plugins.size(); i++) { + PluginConfig plugin = enabled_plugins[i]; + + // Adding plugin binary. + plugin_libraries.push_back(plugin.binary); + + // Adding dependencies. + // Use separate container for names to check for duplicates. + for (int j = 0; j < plugin.linked_dependencies.size(); j++) { + String dependency = plugin.linked_dependencies[j]; + String name = dependency.get_file(); + + if (added_linked_dependenciy_names.has(name)) { + continue; + } + + added_linked_dependenciy_names.push_back(name); + plugin_linked_dependencies.push_back(dependency); + } + + for (int j = 0; j < plugin.system_dependencies.size(); j++) { + String dependency = plugin.system_dependencies[j]; + String name = dependency.get_file(); + + if (added_linked_dependenciy_names.has(name)) { + continue; + } + + added_linked_dependenciy_names.push_back(name); + plugin_linked_dependencies.push_back(dependency); + } + + for (int j = 0; j < plugin.embedded_dependencies.size(); j++) { + String dependency = plugin.embedded_dependencies[j]; + String name = dependency.get_file(); + + if (added_embedded_dependenciy_names.has(name)) { + continue; + } + + added_embedded_dependenciy_names.push_back(name); + plugin_embedded_dependencies.push_back(dependency); + } + + plugin_files.append_array(plugin.files_to_copy); + + // Capabilities + // Also checking for duplicates. + for (int j = 0; j < plugin.capabilities.size(); j++) { + String capability = plugin.capabilities[j]; + + if (p_config_data.capabilities.has(capability)) { + continue; + } + + p_config_data.capabilities.push_back(capability); + } + + // Plist + // Using hash map container to remove duplicates + const String *K = nullptr; + + while ((K = plugin.plist.next(K))) { + String key = *K; + String value = plugin.plist[key]; + + if (key.empty() || value.empty()) { + continue; + } + + plist_values[key] = value; + } + + // CPP Code + String definition_comment = "// Plugin: " + plugin.name + "\n"; + String initialization_method = plugin.initialization_method + "();\n"; + String deinitialization_method = plugin.deinitialization_method + "();\n"; + + plugin_definition_cpp_code += definition_comment + + "extern void " + initialization_method + + "extern void " + deinitialization_method + "\n"; + + plugin_initialization_cpp_code += "\t" + initialization_method; + plugin_deinitialization_cpp_code += "\t" + deinitialization_method; } + + // Updating `Info.plist` + { + const String *K = nullptr; + while ((K = plist_values.next(K))) { + String key = *K; + String value = plist_values[key]; + + if (key.empty() || value.empty()) { + continue; + } + + p_config_data.plist_content += "" + key + "" + value + "\n"; + } + } + + // Export files + { + // Export plugin libraries + Error err = _export_additional_assets(dest_dir, plugin_libraries, true, true, r_exported_assets); + ERR_FAIL_COND_V(err, err); + + // Export linked plugin dependency + err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); + ERR_FAIL_COND_V(err, err); + + // Export embedded plugin dependency + err = _export_additional_assets(dest_dir, plugin_embedded_dependencies, true, true, r_exported_assets); + ERR_FAIL_COND_V(err, err); + + // Export plugin files + err = _export_additional_assets(dest_dir, plugin_files, false, false, r_exported_assets); + ERR_FAIL_COND_V(err, err); + } + + // Update CPP + { + Dictionary plugin_format; + plugin_format["definition"] = plugin_definition_cpp_code; + plugin_format["initialization"] = plugin_initialization_cpp_code; + plugin_format["deinitialization"] = plugin_deinitialization_cpp_code; + + String plugin_cpp_code = "\n// Godot Plugins\n" + "void godot_ios_plugins_initialize();\n" + "void godot_ios_plugins_deinitialize();\n" + "// Exported Plugins\n\n" + "$definition" + "// Use Plugins\n" + "void godot_ios_plugins_initialize() {\n" + "$initialization" + "}\n\n" + "void godot_ios_plugins_deinitialize() {\n" + "$deinitialization" + "}\n"; + + p_config_data.cpp_code += plugin_cpp_code.format(plugin_format, "$_"); + } + return OK; } Error EditorExportPlatformIOS::export_project(const Ref &p_preset, bool p_debug, const String &p_path, int p_flags) { @@ -1324,9 +1569,12 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p "", "", "", - "" + "", + Vector() }; + Vector assets; + DirAccess *tmp_app_path = DirAccess::create_for_path(dest_dir); ERR_FAIL_COND_V(!tmp_app_path, ERR_CANT_CREATE); @@ -1339,8 +1587,8 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p return ERR_CANT_OPEN; } - add_module_code(p_preset, config_data, "arkit", "F9B95E6E2391205500AF0000", "F9C95E812391205C00BF0000"); - add_module_code(p_preset, config_data, "camera", "F9B95E6E2391205500AF0001", "F9C95E812391205C00BF0001"); + err = _export_plugins(p_preset, config_data, dest_dir + binary_name, assets); + ERR_FAIL_COND_V(err, err); //export rest of the files int ret = unzGoToFirstFile(src_pkg_zip); @@ -1382,21 +1630,8 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p is_execute = true; #endif file = "godot_ios.a"; - } else if (file.begins_with("libgodot_arkit")) { - if ((bool)p_preset->get("capabilities/arkit") && file.ends_with(String(p_debug ? "debug" : "release") + ".fat.a")) { - file = "libgodot_arkit_module.a"; - } else { - ret = unzGoToNextFile(src_pkg_zip); - continue; //ignore! - } - } else if (file.begins_with("libgodot_camera")) { - if ((bool)p_preset->get("capabilities/camera") && file.ends_with(String(p_debug ? "debug" : "release") + ".fat.a")) { - file = "libgodot_camera_module.a"; - } else { - ret = unzGoToNextFile(src_pkg_zip); - continue; //ignore! - } } + if (file == project_file) { project_file_data = data; } @@ -1530,7 +1765,6 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p } print_line("Exporting additional assets"); - Vector assets; _export_additional_assets(dest_dir + binary_name, libraries, assets); _add_assets_to_project(p_preset, project_file_data, assets); String project_file_name = dest_dir + binary_name + ".xcodeproj/project.pbxproj"; @@ -1665,9 +1899,17 @@ EditorExportPlatformIOS::EditorExportPlatformIOS() { Ref img = memnew(Image(_iphone_logo)); logo.instance(); logo->create_from_image(img); + + plugins_changed = true; + quit_request = false; + + check_for_changes_thread = Thread::create(_check_for_changes_poll_thread, this); } EditorExportPlatformIOS::~EditorExportPlatformIOS() { + quit_request = true; + Thread::wait_to_finish(check_for_changes_thread); + memdelete(check_for_changes_thread); } void register_iphone_exporter() { diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h new file mode 100644 index 000000000000..4d7297d5b8b8 --- /dev/null +++ b/platform/iphone/plugin/godot_plugin_config.h @@ -0,0 +1,238 @@ +/*************************************************************************/ +/* godot_plugin_config.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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 GODOT_PLUGIN_CONFIG_H +#define GODOT_PLUGIN_CONFIG_H + +#include "core/error/error_list.h" +#include "core/io/config_file.h" +#include "core/string/ustring.h" + +static const char *PLUGIN_CONFIG_EXT = ".gdip"; + +static const char *CONFIG_SECTION = "config"; +static const char *CONFIG_NAME_KEY = "name"; +static const char *CONFIG_BINARY_KEY = "binary"; +static const char *CONFIG_INITIALIZE_KEY = "initialization"; +static const char *CONFIG_DEINITIALIZE_KEY = "deinitialization"; + +static const char *DEPENDENCIES_SECTION = "dependencies"; +static const char *DEPENDENCIES_LINKED_KEY = "linked"; +static const char *DEPENDENCIES_EMBEDDED_KEY = "embedded"; +static const char *DEPENDENCIES_SYSTEM_KEY = "system"; +static const char *DEPENDENCIES_CAPABILITIES_KEY = "capabilities"; +static const char *DEPENDENCIES_FILES_KEY = "files"; + +static const char *PLIST_SECTION = "plist"; + +/* + The `config` section and fields are required and defined as follow: +- **name**: name of the plugin +- **binary**: path to static `.a` library + +The `dependencies` and fields are optional. +- **linked**: dependencies that should only be linked. +- **embedded**: dependencies that should be linked and embedded into application. +- **system**: system dependencies that should be linked. +- **capabilities**: capabilities that would be used for `UIRequiredDeviceCapabilities` options in Info.plist file. +- **files**: files that would be copied into application + +The `plist` section are optional. +- **key**: key and value that would be added in Info.plist file. + */ + +struct PluginConfig { + // Set to true when the config file is properly loaded. + bool valid_config = false; + // Unix timestamp of last change to this plugin. + uint64_t last_updated = 0; + + // Required config section + String name; + String binary; + String initialization_method; + String deinitialization_method; + + // Optional dependencies section + Vector linked_dependencies; + Vector embedded_dependencies; + Vector system_dependencies; + + Vector files_to_copy; + Vector capabilities; + + // Optional plist section + // Supports only string types for now + HashMap plist; +}; + +static inline String resolve_local_dependency_path(String plugin_config_dir, String dependency_path) { + String absolute_path; + + if (dependency_path.empty()) { + return absolute_path; + } + + if (dependency_path.is_abs_path()) { + return dependency_path; + } + + String res_path = ProjectSettings::get_singleton()->globalize_path("res://"); + absolute_path = plugin_config_dir.plus_file(dependency_path); + + return absolute_path.replace(res_path, "res://"); +} + +static inline String resolve_system_dependency_path(String dependency_path) { + String absolute_path; + + if (dependency_path.empty()) { + return absolute_path; + } + + if (dependency_path.is_abs_path()) { + return dependency_path; + } + + String system_path = "/System/Library/Frameworks"; + + return system_path.plus_file(dependency_path); +} + +static inline Vector resolve_local_dependencies(String plugin_config_dir, Vector p_paths) { + Vector paths; + + for (int i = 0; i < p_paths.size(); i++) { + String path = resolve_local_dependency_path(plugin_config_dir, p_paths[i]); + + if (path.empty()) { + continue; + } + + paths.push_back(path); + } + + return paths; +} + +static inline Vector resolve_system_dependencies(Vector p_paths) { + Vector paths; + + for (int i = 0; i < p_paths.size(); i++) { + String path = resolve_system_dependency_path(p_paths[i]); + + if (path.empty()) { + continue; + } + + paths.push_back(path); + } + + return paths; +} + +static inline bool is_plugin_config_valid(PluginConfig plugin_config) { + bool valid_name = !plugin_config.name.empty(); + bool valid_binary = !plugin_config.binary.empty() && FileAccess::exists(plugin_config.binary); + bool valid_initialize = !plugin_config.initialization_method.empty(); + bool valid_deinitialize = !plugin_config.deinitialization_method.empty(); + + return valid_name && valid_binary && valid_initialize && valid_deinitialize; +} + +static inline uint64_t get_plugin_modification_time(const PluginConfig &plugin_config, const String &config_path) { + uint64_t last_updated = FileAccess::get_modified_time(config_path); + last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary)); + + return last_updated; +} + +static inline PluginConfig load_plugin_config(Ref config_file, const String &path) { + PluginConfig plugin_config = {}; + + if (!config_file.is_valid()) { + return plugin_config; + } + + Error err = config_file->load(path); + + if (err != OK) { + return plugin_config; + } + + String config_base_dir = path.get_base_dir(); + + plugin_config.name = config_file->get_value(CONFIG_SECTION, CONFIG_NAME_KEY, String()); + plugin_config.initialization_method = config_file->get_value(CONFIG_SECTION, CONFIG_INITIALIZE_KEY, String()); + plugin_config.deinitialization_method = config_file->get_value(CONFIG_SECTION, CONFIG_DEINITIALIZE_KEY, String()); + + String binary_path = config_file->get_value(CONFIG_SECTION, CONFIG_BINARY_KEY, String()); + plugin_config.binary = resolve_local_dependency_path(config_base_dir, binary_path); + + if (config_file->has_section(DEPENDENCIES_SECTION)) { + Vector linked_dependencies = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_LINKED_KEY, Vector()); + Vector embedded_dependencies = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_EMBEDDED_KEY, Vector()); + Vector system_dependencies = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_SYSTEM_KEY, Vector()); + Vector files = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_FILES_KEY, Vector()); + + plugin_config.linked_dependencies = resolve_local_dependencies(config_base_dir, linked_dependencies); + plugin_config.embedded_dependencies = resolve_local_dependencies(config_base_dir, embedded_dependencies); + plugin_config.system_dependencies = resolve_system_dependencies(system_dependencies); + + plugin_config.files_to_copy = resolve_local_dependencies(config_base_dir, files); + + plugin_config.capabilities = config_file->get_value(DEPENDENCIES_SECTION, DEPENDENCIES_CAPABILITIES_KEY, Vector()); + } + + if (config_file->has_section(PLIST_SECTION)) { + List keys; + config_file->get_section_keys(PLIST_SECTION, &keys); + + for (int i = 0; i < keys.size(); i++) { + String value = config_file->get_value(PLIST_SECTION, keys[i], String()); + + if (value.empty()) { + continue; + } + + plugin_config.plist[keys[i]] = value; + } + } + + plugin_config.valid_config = is_plugin_config_valid(plugin_config); + + if (plugin_config.valid_config) { + plugin_config.last_updated = get_plugin_modification_time(plugin_config, path); + } + + return plugin_config; +} + +#endif // GODOT_PLUGIN_CONFIG_H From 1f2f477e1ee28f9fac8b7fc17bbd6d4707c4e5e8 Mon Sep 17 00:00:00 2001 From: Sergey Minakov Date: Mon, 17 Aug 2020 21:47:37 +0300 Subject: [PATCH 4/4] iOS Export: support multi-target plugin Plugins can use 'binary_name.a' or 'binary_name.release.a' and 'binary_name.debug.a' for plugin library. --- platform/iphone/export/export.cpp | 286 +++++++++++-------- platform/iphone/plugin/godot_plugin_config.h | 41 ++- 2 files changed, 200 insertions(+), 127 deletions(-) diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp index 7cca0f390d12..cbef13624779 100644 --- a/platform/iphone/export/export.cpp +++ b/platform/iphone/export/export.cpp @@ -111,8 +111,9 @@ class EditorExportPlatformIOS : public EditorExportPlatform { void _add_assets_to_project(const Ref &p_preset, Vector &p_project_data, const Vector &p_additional_assets); Error _export_additional_assets(const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &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 &r_exported_assets); Error _export_additional_assets(const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets); - Error _export_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets); + Error _export_ios_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug); bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const { String pname = p_package; @@ -1121,142 +1122,179 @@ void EditorExportPlatformIOS::_add_assets_to_project(const Ref &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets) { +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 &r_exported_assets) { DirAccess *filesystem_da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); + String binary_name = p_out_dir.get_file().get_basename(); - ERR_FAIL_COND_V_MSG(!filesystem_da, ERR_CANT_CREATE, "Cannot create DirAccess for path '" + p_out_dir + "'."); - for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { - String asset = p_assets[f_idx]; - if (!asset.begins_with("res://")) { - // either SDK-builtin or already a part of the export template - IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed }; - r_exported_assets.push_back(exported_asset); + DirAccess *da = DirAccess::create_for_path(p_asset); + if (!da) { + memdelete(filesystem_da); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + p_asset + "."); + } + bool file_exists = da->file_exists(p_asset); + bool dir_exists = da->dir_exists(p_asset); + if (!file_exists && !dir_exists) { + memdelete(da); + memdelete(filesystem_da); + return ERR_FILE_NOT_FOUND; + } + + String base_dir = p_asset.get_base_dir().replace("res://", ""); + String destination_dir; + String destination; + String asset_path; + + bool create_framework = false; + + if (p_is_framework && p_asset.ends_with(".dylib")) { + // For iOS we need to turn .dylib into .framework + // to be able to send application to AppStore + asset_path = String("dylibs").plus_file(base_dir); + + String file_name; + + if (!p_custom_file_name) { + file_name = p_asset.get_basename().get_file(); } else { - DirAccess *da = DirAccess::create_for_path(asset); - if (!da) { - memdelete(filesystem_da); - ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't create directory: " + asset + "."); - } - bool file_exists = da->file_exists(asset); - bool dir_exists = da->dir_exists(asset); - if (!file_exists && !dir_exists) { - memdelete(da); - memdelete(filesystem_da); - return ERR_FILE_NOT_FOUND; - } + file_name = *p_custom_file_name; + } - String base_dir = asset.get_base_dir().replace("res://", ""); - String destination_dir; - String destination; - String asset_path; + String framework_name = file_name + ".framework"; - bool create_framework = false; + asset_path = asset_path.plus_file(framework_name); + destination_dir = p_out_dir.plus_file(asset_path); + destination = destination_dir.plus_file(file_name); + create_framework = true; + } else if (p_is_framework && (p_asset.ends_with(".framework") || p_asset.ends_with(".xcframework"))) { + asset_path = String("dylibs").plus_file(base_dir); - if (p_is_framework && asset.ends_with(".dylib")) { - // For iOS we need to turn .dylib into .framework - // to be able to send application to AppStore - asset_path = String("dylibs").plus_file(base_dir); + String file_name; - String file_name = asset.get_basename().get_file(); - String framework_name = file_name + ".framework"; + if (!p_custom_file_name) { + file_name = p_asset.get_file(); + } else { + file_name = *p_custom_file_name; + } - asset_path = asset_path.plus_file(framework_name); - destination_dir = p_out_dir.plus_file(asset_path); - destination = destination_dir.plus_file(file_name); - create_framework = true; - } else if (p_is_framework && (asset.ends_with(".framework") || asset.ends_with(".xcframework"))) { - asset_path = String("dylibs").plus_file(base_dir); + asset_path = asset_path.plus_file(file_name); + destination_dir = p_out_dir.plus_file(asset_path); + destination = destination_dir; + } else { + asset_path = base_dir; - String file_name = asset.get_file(); - asset_path = asset_path.plus_file(file_name); - destination_dir = p_out_dir.plus_file(asset_path); - destination = destination_dir; - } else { - asset_path = base_dir; + String file_name; - String file_name = asset.get_file(); - destination_dir = p_out_dir.plus_file(asset_path); - asset_path = asset_path.plus_file(file_name); - destination = p_out_dir.plus_file(asset_path); - } + if (!p_custom_file_name) { + file_name = p_asset.get_file(); + } else { + file_name = *p_custom_file_name; + } - if (!filesystem_da->dir_exists(destination_dir)) { - Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); - if (make_dir_err) { - memdelete(da); - memdelete(filesystem_da); - return make_dir_err; - } - } + destination_dir = p_out_dir.plus_file(asset_path); + asset_path = asset_path.plus_file(file_name); + destination = p_out_dir.plus_file(asset_path); + } - Error err = dir_exists ? da->copy_dir(asset, destination) : da->copy(asset, destination); + if (!filesystem_da->dir_exists(destination_dir)) { + Error make_dir_err = filesystem_da->make_dir_recursive(destination_dir); + if (make_dir_err) { memdelete(da); - if (err) { - memdelete(filesystem_da); - return err; - } - IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed }; - r_exported_assets.push_back(exported_asset); + memdelete(filesystem_da); + return make_dir_err; + } + } - if (create_framework) { - String file_name = asset.get_basename().get_file(); - String framework_name = file_name + ".framework"; + Error err = dir_exists ? da->copy_dir(p_asset, destination) : da->copy(p_asset, destination); + memdelete(da); + if (err) { + memdelete(filesystem_da); + return err; + } + IOSExportAsset exported_asset = { binary_name.plus_file(asset_path), p_is_framework, p_should_embed }; + r_exported_assets.push_back(exported_asset); - // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib - { - List install_name_args; - install_name_args.push_back("-id"); - install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name)); - install_name_args.push_back(destination); + if (create_framework) { + String file_name; - OS::get_singleton()->execute("install_name_tool", install_name_args, true); - } + if (!p_custom_file_name) { + file_name = p_asset.get_basename().get_file(); + } else { + file_name = *p_custom_file_name; + } - // Creating Info.plist - { - String info_plist_format = "\n" - "\n" - "\n" - "\n" - "CFBundleShortVersionString\n" - "1.0\n" - "CFBundleIdentifier\n" - "com.gdnative.framework.$name\n" - "CFBundleName\n" - "$name\n" - "CFBundleExecutable\n" - "$name\n" - "DTPlatformName\n" - "iphoneos\n" - "CFBundleInfoDictionaryVersion\n" - "6.0\n" - "CFBundleVersion\n" - "1\n" - "CFBundlePackageType\n" - "FMWK\n" - "MinimumOSVersion\n" - "10.0\n" - "\n" - ""; - - String info_plist = info_plist_format.replace("$name", file_name); - - FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); - if (f) { - f->store_string(info_plist); - f->close(); - memdelete(f); - } - } + String framework_name = file_name + ".framework"; + + // Performing `install_name_tool -id @rpath/{name}.framework/{name} ./{name}` on dylib + { + List install_name_args; + install_name_args.push_back("-id"); + install_name_args.push_back(String("@rpath").plus_file(framework_name).plus_file(file_name)); + install_name_args.push_back(destination); + + OS::get_singleton()->execute("install_name_tool", install_name_args, true); + } + + // Creating Info.plist + { + String info_plist_format = "\n" + "\n" + "\n" + "\n" + "CFBundleShortVersionString\n" + "1.0\n" + "CFBundleIdentifier\n" + "com.gdnative.framework.$name\n" + "CFBundleName\n" + "$name\n" + "CFBundleExecutable\n" + "$name\n" + "DTPlatformName\n" + "iphoneos\n" + "CFBundleInfoDictionaryVersion\n" + "6.0\n" + "CFBundleVersion\n" + "1\n" + "CFBundlePackageType\n" + "FMWK\n" + "MinimumOSVersion\n" + "10.0\n" + "\n" + ""; + + String info_plist = info_plist_format.replace("$name", file_name); + + FileAccess *f = FileAccess::open(destination_dir.plus_file("Info.plist"), FileAccess::WRITE); + if (f) { + f->store_string(info_plist); + f->close(); + memdelete(f); } } } + memdelete(filesystem_da); return OK; } +Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector &p_assets, bool p_is_framework, bool p_should_embed, Vector &r_exported_assets) { + for (int f_idx = 0; f_idx < p_assets.size(); ++f_idx) { + String asset = p_assets[f_idx]; + if (!asset.begins_with("res://")) { + // either SDK-builtin or already a part of the export template + IOSExportAsset exported_asset = { asset, p_is_framework, p_should_embed }; + r_exported_assets.push_back(exported_asset); + } else { + Error err = _copy_asset(p_out_dir, asset, nullptr, p_is_framework, p_should_embed, r_exported_assets); + ERR_FAIL_COND_V(err, err); + } + } + + return OK; +} + Error EditorExportPlatformIOS::_export_additional_assets(const String &p_out_dir, const Vector &p_libraries, Vector &r_exported_assets) { Vector> export_plugins = EditorExport::get_singleton()->get_export_plugins(); for (int i = 0; i < export_plugins.size(); i++) { @@ -1302,12 +1340,11 @@ Vector EditorExportPlatformIOS::_get_preset_architectures(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets) { +Error EditorExportPlatformIOS::_export_ios_plugins(const Ref &p_preset, IOSConfigData &p_config_data, const String &dest_dir, Vector &r_exported_assets, bool p_debug) { String plugin_definition_cpp_code; String plugin_initialization_cpp_code; String plugin_deinitialization_cpp_code; - Vector plugin_libraries; Vector plugin_linked_dependencies; Vector plugin_embedded_dependencies; Vector plugin_files; @@ -1318,11 +1355,24 @@ Error EditorExportPlatformIOS::_export_plugins(const Ref &p_ Vector added_embedded_dependenciy_names; HashMap plist_values; + Error err; + for (int i = 0; i < enabled_plugins.size(); i++) { PluginConfig plugin = enabled_plugins[i]; - // Adding plugin binary. - plugin_libraries.push_back(plugin.binary); + // Export plugin binary. + if (!plugin.supports_targets) { + err = _copy_asset(dest_dir, plugin.binary, nullptr, true, true, r_exported_assets); + } else { + String plugin_binary_dir = plugin.binary.get_base_dir(); + String plugin_name_prefix = plugin.binary.get_basename().get_file(); + String plugin_file = plugin_name_prefix + "." + (p_debug ? "debug" : "release") + ".a"; + String result_file_name = plugin.binary.get_file(); + + err = _copy_asset(dest_dir, plugin_binary_dir.plus_file(plugin_file), &result_file_name, true, true, r_exported_assets); + } + + ERR_FAIL_COND_V(err, err); // Adding dependencies. // Use separate container for names to check for duplicates. @@ -1421,10 +1471,6 @@ Error EditorExportPlatformIOS::_export_plugins(const Ref &p_ // Export files { - // Export plugin libraries - Error err = _export_additional_assets(dest_dir, plugin_libraries, true, true, r_exported_assets); - ERR_FAIL_COND_V(err, err); - // Export linked plugin dependency err = _export_additional_assets(dest_dir, plugin_linked_dependencies, true, false, r_exported_assets); ERR_FAIL_COND_V(err, err); @@ -1587,7 +1633,7 @@ Error EditorExportPlatformIOS::export_project(const Ref &p_p return ERR_CANT_OPEN; } - err = _export_plugins(p_preset, config_data, dest_dir + binary_name, assets); + err = _export_ios_plugins(p_preset, config_data, dest_dir + binary_name, assets, p_debug); ERR_FAIL_COND_V(err, err); //export rest of the files diff --git a/platform/iphone/plugin/godot_plugin_config.h b/platform/iphone/plugin/godot_plugin_config.h index 4d7297d5b8b8..5323f9498932 100644 --- a/platform/iphone/plugin/godot_plugin_config.h +++ b/platform/iphone/plugin/godot_plugin_config.h @@ -71,6 +71,7 @@ The `plist` section are optional. struct PluginConfig { // Set to true when the config file is properly loaded. bool valid_config = false; + bool supports_targets = false; // Unix timestamp of last change to this plugin. uint64_t last_updated = 0; @@ -158,18 +159,46 @@ static inline Vector resolve_system_dependencies(Vector p_paths) return paths; } -static inline bool is_plugin_config_valid(PluginConfig plugin_config) { +static inline bool validate_plugin(PluginConfig &plugin_config) { bool valid_name = !plugin_config.name.empty(); - bool valid_binary = !plugin_config.binary.empty() && FileAccess::exists(plugin_config.binary); + bool valid_binary_name = !plugin_config.binary.empty(); bool valid_initialize = !plugin_config.initialization_method.empty(); bool valid_deinitialize = !plugin_config.deinitialization_method.empty(); - return valid_name && valid_binary && valid_initialize && valid_deinitialize; + bool fields_value = valid_name && valid_binary_name && valid_initialize && valid_deinitialize; + + if (fields_value && FileAccess::exists(plugin_config.binary)) { + plugin_config.valid_config = true; + plugin_config.supports_targets = false; + } else if (fields_value) { + String file_path = plugin_config.binary.get_base_dir(); + String file_name = plugin_config.binary.get_basename().get_file(); + String release_file_name = file_path.plus_file(file_name + ".release.a"); + String debug_file_name = file_path.plus_file(file_name + ".debug.a"); + + if (FileAccess::exists(release_file_name) && FileAccess::exists(debug_file_name)) { + plugin_config.valid_config = true; + plugin_config.supports_targets = true; + } + } + + return plugin_config.valid_config; } static inline uint64_t get_plugin_modification_time(const PluginConfig &plugin_config, const String &config_path) { uint64_t last_updated = FileAccess::get_modified_time(config_path); - last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary)); + + if (!plugin_config.supports_targets) { + last_updated = MAX(last_updated, FileAccess::get_modified_time(plugin_config.binary)); + } else { + String file_path = plugin_config.binary.get_base_dir(); + String file_name = plugin_config.binary.get_basename().get_file(); + String release_file_name = file_path.plus_file(file_name + ".release.a"); + String debug_file_name = file_path.plus_file(file_name + ".debug.a"); + + last_updated = MAX(last_updated, FileAccess::get_modified_time(release_file_name)); + last_updated = MAX(last_updated, FileAccess::get_modified_time(debug_file_name)); + } return last_updated; } @@ -226,9 +255,7 @@ static inline PluginConfig load_plugin_config(Ref config_file, const } } - plugin_config.valid_config = is_plugin_config_valid(plugin_config); - - if (plugin_config.valid_config) { + if (validate_plugin(plugin_config)) { plugin_config.last_updated = get_plugin_modification_time(plugin_config, path); }