diff --git a/CHANGELOG.md b/CHANGELOG.md index 72e3223..628297e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. +## 2021-02-05 + +## Added + +- `badge_number` property, `set_badge_number`, `get_badge_number` methods to `PushNotifications` plugin. +- `GodotUserNotificationDelegate` and `UserNotificationService` can be used by as a single interface to process incoming notifications (both remote and local). + +## 2021-02-03 + +## Added + +- `PushNotifications` plugin that enables Apple Remote Notifications support for Godot projects. + ## 2021-01-31 ## Fixes diff --git a/README.md b/README.md index fcb6046..667249e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Godot iOS plugins +`master` branch is current development branch and can introduce breaking changes to plugin's public interface. +`3.2` branch aim is to provide same public interface as it was before switch to new iOS plugin system. ## Instructions @@ -31,7 +33,7 @@ * Running ``` - scons target= arch= simulator= plugin= version=<3.2|4.0> + scons target= arch= simulator= plugin= version=<3.3|4.0> ``` will generate `.a` static library for chosen target. Do note, that Godot's default `debug` export template is compiled with `release_debug` target. @@ -46,4 +48,4 @@ * Run `./scripts/generate_xcframework.sh ` to generate `xcframework` with specific configuration. `xcframework` allows plugin to support both `arm64` device and `arm64` simulator. -* The result `.xcframework` will be stored in `bin` folder as well as intermidiate `.a` binaries. \ No newline at end of file +* The result `.xcframework` will be stored in `bin` folder as well as intermidiate `.a` binaries. diff --git a/SConstruct b/SConstruct index 22d2b7f..5982d76 100644 --- a/SConstruct +++ b/SConstruct @@ -24,8 +24,8 @@ opts.Add(EnumVariable('arch', "Compilation Architecture", '', ['', 'arm64', 'arm opts.Add(BoolVariable('simulator', "Compilation platform", 'no')) opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'bin/')) -opts.Add(EnumVariable('plugin', 'Plugin to build', '', ['', 'arkit', 'camera', 'icloud', 'gamecenter', 'inappstore'])) -opts.Add(EnumVariable('version', 'Godot version to target', '', ['', '3.2', '4.0'])) +opts.Add(EnumVariable('plugin', 'Plugin to build', '', ['', 'apn', 'arkit', 'camera', 'icloud', 'gamecenter', 'inappstore'])) +opts.Add(EnumVariable('version', 'Godot version to target', '', ['', '3.3', '4.0'])) # Updates the environment with the option variables. opts.Update(env) @@ -93,7 +93,7 @@ env.Append(LINKFLAGS=["-arch", env['arch'], '-isysroot', sdk_path, '-F' + sdk_pa if env['arch'] == 'armv7': env.Prepend(CXXFLAGS=['-fno-aligned-allocation']) -if env['version'] == '3.2': +if env['version'] == '3.3': env.Prepend(CFLAGS=['-std=gnu11']) env.Prepend(CXXFLAGS=['-DGLES_ENABLED', '-std=gnu++14']) diff --git a/plugins/apn/README.md b/plugins/apn/README.md new file mode 100644 index 0000000..ff7d644 --- /dev/null +++ b/plugins/apn/README.md @@ -0,0 +1,40 @@ +# Godot iOS Apple Push Notifications plugin + +Requires `-ObjC` value added to the `Other Linker Flags` in Xcode project. + +Example: + +``` +var _apn = null + +func _apn_device(value): + print("device string: " + value); + +... + +func _ready(): + if Engine.has_singleton("APN"): + var _apn = Engine.get_singleton("APN"); + _apn.connect("device_address_changed", self, "_apn_device"); + + _apn.register_push_notifications(_apn.PUSH_SOUND | _apn.PUSH_BADGE | _apn.PUSH_ALERT); +``` + +## Enum + +Type: `PushOptions` +Values: `PUSH_ALERT`, `PUSH_BADGE`, `PUSH_SOUND`, `PUSH_SETTINGS` + +## Methods + +`register_push_notifications(PushOptions options)` - Registers device to receive remote notifications through Apple Push Notification service. +`set_badge_number(int value)` - Sets the badge value of the app icon on the Home screen. +`get_badge_number()` - Returns the badge value of the app icon on the Home screen. + +## Properties + +`badge_number: int` - The number represents the badge of the app icon on the Home screen. + +## Signals + +`device_address_changed(String token)` - Called whenever iOS device updates remote notification token value. diff --git a/plugins/apn/apn.gdip b/plugins/apn/apn.gdip new file mode 100644 index 0000000..a02da8a --- /dev/null +++ b/plugins/apn/apn.gdip @@ -0,0 +1,19 @@ +[config] +name="PushNotifications" +binary="apn.xcframework" + +initialization="godot_apn_init" +deinitialization="godot_apn_deinit" + +[dependencies] +linked=[] +embedded=[] +system=[] + +capabilities=[] + +files=[] + +linker_flags=["-ObjC"] + +[plist] diff --git a/plugins/apn/apn.h b/plugins/apn/apn.h new file mode 100644 index 0000000..1ad8662 --- /dev/null +++ b/plugins/apn/apn.h @@ -0,0 +1,63 @@ +/*************************************************************************/ +/* apn.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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_apn_implementation_h +#define godot_apn_implementation_h + +#include "core/object.h" + +class APNPlugin : public Object { + GDCLASS(APNPlugin, Object); + + static void _bind_methods(); + +public: + enum PushOptions { + PUSH_ALERT = 1 << 0, + PUSH_BADGE = 1 << 1, + PUSH_SOUND = 1 << 2, + PUSH_SETTINGS = 1 << 3, + }; + + static APNPlugin *get_singleton(); + + void register_push_notifications(PushOptions options); + void update_device_token(String token); + + void set_badge_number(int value); + int get_badge_number(); + + APNPlugin(); + ~APNPlugin(); +}; + +VARIANT_ENUM_CAST(APNPlugin::PushOptions) + +#endif /* godot_apn_implementation_h */ diff --git a/plugins/apn/apn.mm b/plugins/apn/apn.mm new file mode 100644 index 0000000..1efebf0 --- /dev/null +++ b/plugins/apn/apn.mm @@ -0,0 +1,97 @@ +/*************************************************************************/ +/* apn.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "apn.h" + +#import + +#include "core/class_db.h" +#include "core/project_settings.h" + +#import "godot_apn_delegate.h" + +static APNPlugin *singleton; + +APNPlugin *APNPlugin::get_singleton() { + return singleton; +} + +void APNPlugin::_bind_methods() { + ClassDB::bind_method(D_METHOD("register_push_notifications", "options"), &APNPlugin::register_push_notifications); + + ClassDB::bind_method(D_METHOD("set_badge_number", "value"), &APNPlugin::set_badge_number); + ClassDB::bind_method(D_METHOD("get_badge_number"), &APNPlugin::get_badge_number); + ADD_PROPERTY(PropertyInfo(Variant::INT, "badge_number"), "set_badge_number", "get_badge_number"); + + ADD_SIGNAL(MethodInfo("device_address_changed", PropertyInfo(Variant::STRING, "id"))); + + BIND_ENUM_CONSTANT(PUSH_ALERT); + BIND_ENUM_CONSTANT(PUSH_BADGE); + BIND_ENUM_CONSTANT(PUSH_SOUND); + BIND_ENUM_CONSTANT(PUSH_SETTINGS); +} + +void APNPlugin::register_push_notifications(PushOptions options) { + UNAuthorizationOptions notificationsOptions = UNAuthorizationOptionNone; + + if (options & PUSH_ALERT) { + notificationsOptions |= UNAuthorizationOptionAlert; + } + + if (options & PUSH_BADGE) { + notificationsOptions |= UNAuthorizationOptionBadge; + } + + if (options & PUSH_SOUND) { + notificationsOptions |= UNAuthorizationOptionSound; + } + + [[GodotAPNAppDelegate shared] registerPushNotificationsWithOptions:options]; +} + +void APNPlugin::update_device_token(String token) { + emit_signal("device_address_changed", token); +} + +void APNPlugin::set_badge_number(int value) { + UIApplication.sharedApplication.applicationIconBadgeNumber = (long)value; +} + +int APNPlugin::get_badge_number() { + return (int)UIApplication.sharedApplication.applicationIconBadgeNumber; +} + +APNPlugin::APNPlugin() { + singleton = this; +} + +APNPlugin::~APNPlugin() { + singleton = NULL; +} diff --git a/plugins/apn/apn_plugin.cpp b/plugins/apn/apn_plugin.cpp new file mode 100644 index 0000000..5ab1914 --- /dev/null +++ b/plugins/apn/apn_plugin.cpp @@ -0,0 +1,47 @@ +/*************************************************************************/ +/* apn_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "apn_plugin.h" +#import "apn.h" + +#import "core/engine.h" + +APNPlugin *plugin; + +void godot_apn_init() { + plugin = memnew(APNPlugin); + Engine::get_singleton()->add_singleton(Engine::Singleton("APN", plugin)); +} + +void godot_apn_deinit() { + if (plugin) { + memdelete(plugin); + } +} diff --git a/plugins/apn/apn_plugin.h b/plugins/apn/apn_plugin.h new file mode 100644 index 0000000..4e4bb3e --- /dev/null +++ b/plugins/apn/apn_plugin.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* apn_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 godot_apn_init(); +void godot_apn_deinit(); diff --git a/plugins/apn/godot_apn_delegate.h b/plugins/apn/godot_apn_delegate.h new file mode 100644 index 0000000..7edd151 --- /dev/null +++ b/plugins/apn/godot_apn_delegate.h @@ -0,0 +1,39 @@ +/*************************************************************************/ +/* godot_apn_delegate.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 +#import + +@interface GodotAPNAppDelegate : NSObject + ++ (instancetype)shared; +- (void)registerPushNotificationsWithOptions:(UNAuthorizationOptions)options; + +@end diff --git a/plugins/apn/godot_apn_delegate.mm b/plugins/apn/godot_apn_delegate.mm new file mode 100644 index 0000000..0c09916 --- /dev/null +++ b/plugins/apn/godot_apn_delegate.mm @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* godot_apn_delegate.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "godot_apn_delegate.h" + +#include "apn.h" + +#import "godot_user_notification_delegate.h" +#import "platform/iphone/godot_app_delegate.h" + +struct APNSInitializer { + + APNSInitializer() { + [GodotApplicalitionDelegate addService:[GodotAPNAppDelegate shared]]; + } +}; +static APNSInitializer initializer; + +@interface GodotAPNAppDelegate () + +@end + +@implementation GodotAPNAppDelegate + +- (instancetype)init { + self = [super init]; + + if (self) { + UNUserNotificationCenter.currentNotificationCenter.delegate = [GodotUserNotificationDelegate shared]; + } + + return self; +} + ++ (instancetype)shared { + static GodotAPNAppDelegate *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GodotAPNAppDelegate alloc] init]; + }); + return sharedInstance; +} + +- (void)registerPushNotificationsWithOptions:(UNAuthorizationOptions)options { + [UNUserNotificationCenter.currentNotificationCenter requestAuthorizationWithOptions:options + completionHandler:^(BOOL granted, NSError *_Nullable error) { + NSLog(@"Push notifications access: %@, error: %@", @(granted), error); + }]; + [UIApplication.sharedApplication registerForRemoteNotifications]; +} + +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + const char *data = (const char *)[deviceToken bytes]; + NSMutableString *token = [NSMutableString string]; + + for (NSUInteger i = 0; i < [deviceToken length]; i++) { + [token appendFormat:@"%02.2hhX", data[i]]; + } + + String device_token; + device_token.parse_utf8([[token copy] UTF8String]); + + APNPlugin::get_singleton()->update_device_token(device_token); +} + +@end diff --git a/plugins/apn/godot_app_delegate_extension.h b/plugins/apn/godot_app_delegate_extension.h new file mode 100644 index 0000000..d18f8b8 --- /dev/null +++ b/plugins/apn/godot_app_delegate_extension.h @@ -0,0 +1,35 @@ +/*************************************************************************/ +/* godot_app_delegate_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "platform/iphone/godot_app_delegate.h" + +@interface GodotApplicalitionDelegate (PushNotifications) + +@end diff --git a/plugins/apn/godot_app_delegate_extension.m b/plugins/apn/godot_app_delegate_extension.m new file mode 100644 index 0000000..f189e34 --- /dev/null +++ b/plugins/apn/godot_app_delegate_extension.m @@ -0,0 +1,67 @@ +/*************************************************************************/ +/* godot_app_delegate_extension.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "godot_app_delegate_extension.h" + +@implementation GodotApplicalitionDelegate (PushNotifications) + +- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + for (ApplicationDelegateService *service in GodotApplicalitionDelegate.services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; + } +} + +- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + for (ApplicationDelegateService *service in GodotApplicalitionDelegate.services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service application:application didFailToRegisterForRemoteNotificationsWithError:error]; + } +} + +- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler { + for (ApplicationDelegateService *service in GodotApplicalitionDelegate.services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; + } + + completionHandler(UIBackgroundFetchResultNoData); +} + +@end diff --git a/plugins/apn/godot_user_notification_delegate.h b/plugins/apn/godot_user_notification_delegate.h new file mode 100644 index 0000000..5663b81 --- /dev/null +++ b/plugins/apn/godot_user_notification_delegate.h @@ -0,0 +1,43 @@ +/*************************************************************************/ +/* godot_user_notification_delegate.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 + +typedef NSObject UserNotificationService; + +@interface GodotUserNotificationDelegate : NSObject + +@property(class, readonly, strong) NSArray *services; + ++ (instancetype)shared; + ++ (void)addService:(UserNotificationService *)service; + +@end diff --git a/plugins/apn/godot_user_notification_delegate.m b/plugins/apn/godot_user_notification_delegate.m new file mode 100644 index 0000000..5c26e6a --- /dev/null +++ b/plugins/apn/godot_user_notification_delegate.m @@ -0,0 +1,102 @@ +/*************************************************************************/ +/* godot_user_notification_delegate.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "godot_user_notification_delegate.h" + +@interface GodotUserNotificationDelegate () + +@end + +@implementation GodotUserNotificationDelegate + +static NSMutableArray *services = nil; + ++ (NSArray *)services { + return services; +} + ++ (void)load { + services = [NSMutableArray new]; +} + ++ (instancetype)shared { + static GodotUserNotificationDelegate *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GodotUserNotificationDelegate alloc] init]; + }); + return sharedInstance; +} + ++ (void)addService:(UserNotificationService *)service { + if (!services || !service) { + return; + } + [services addObject:service]; +} + +// MARK: Delegate + +// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user. +- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { + for (UserNotificationService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service userNotificationCenter:center willPresentNotification:notification withCompletionHandler:completionHandler]; + } +} + +// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from application:didFinishLaunchingWithOptions:. +- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { + for (UserNotificationService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service userNotificationCenter:center didReceiveNotificationResponse:response withCompletionHandler:completionHandler]; + } +} + +// The method will be called on the delegate when the application is launched in response to the user's request to view in-app notification settings. +// Add UNAuthorizationOptionProvidesAppNotificationSettings as an option in requestAuthorizationWithOptions:completionHandler: to add a button to inline notification settings view and the notification settings view in Settings. +// The notification will be nil when opened from Settings. +- (void)userNotificationCenter:(UNUserNotificationCenter *)center openSettingsForNotification:(nullable UNNotification *)notification __API_AVAILABLE(macos(10.14), ios(12.0))__API_UNAVAILABLE(watchos, tvos) { + for (UserNotificationService *service in services) { + if (![service respondsToSelector:_cmd]) { + continue; + } + + [service userNotificationCenter:center openSettingsForNotification:notification]; + } +} + +@end diff --git a/plugins/arkit/README.md b/plugins/arkit/README.md new file mode 100644 index 0000000..31fc815 --- /dev/null +++ b/plugins/arkit/README.md @@ -0,0 +1,17 @@ +# Godot iOS ARKit plugin + +Uses Godot's `XRInterface`/`ARVRInterface` to handle iOS AR functionality. + +## Methods + +`set_light_estimation_is_enabled(bool flag)` - Sets a value responsible for usage of estimation of lighting conditions based on the camera image. +`get_light_estimation_is_enabled()` - Returns a value responsible for usage of estimation of lighting conditions based on the camera image. +`get_ambient_intensity()` - Returns a value used for intensity, in lumens, of ambient light throughout the scene. +`get_ambient_color_temperature()` - Return a value used for color temperature of ambient light throughout the scene. +`raycast(Vector2 screen_coords)` - Performs a raycast to search for real-world objects or AR anchors in the captured camera image. + +## Properties + +`light_estimation: bool` - Returns or sets a value responsible for usage of estimation of lighting conditions based on the camera image. + +## Events reporting diff --git a/plugins/camera/README.md b/plugins/camera/README.md new file mode 100644 index 0000000..0f4c86b --- /dev/null +++ b/plugins/camera/README.md @@ -0,0 +1,9 @@ +# Godot iOS Camera plugin + +Uses Godot's `CameraServer` to handle iOS device camera feed. + +## Methods + +## Properties + +## Events reporting diff --git a/plugins/gamecenter/README.md b/plugins/gamecenter/README.md new file mode 100644 index 0000000..12648a9 --- /dev/null +++ b/plugins/gamecenter/README.md @@ -0,0 +1,25 @@ +# Godot iOS GameCenter plugin + +## Methods + +### Authorization + +`authenticate()` - Performs user authentication. +`is_authenticated()` - Returns authentication state. + +### GameCenter methods + +`post_score(Dictionary score_dictionary)` - Reports a score data to iOS `GameCenter`. Generates new event with `post_score` type. +`award_achievement(Dictionary achievent_dictionary)` - Reports progress of achievement data to iOS `GameCenter`. Generates new event with `award_achievement` type. +`reset_achievements()` - Resets all achievement progress for the local player. Generates new event with `reset_achievements` type. +`request_achievements()` - Loads previously submitted achievement progress for the local player from iOS `GameCenter`. Generates new event with `achievements` type. +`request_achievement_descriptions()` - Downloads the achievement descriptions from iOS `GameCenter`. Generates new event with `achievement_descriptions` type. +`show_game_center(Dictionary screen_dictionary)` - Displays Game Center information of your game. Generates new event with `show_game_center` type when information screen closes. +`request_identity_verification_signature()` - Creates a signature for a third-party server to authenticate the local player. Generates new event with `identity_verification_signature` type. + +## Properties + +## Events reporting + +`get_pending_event_count()` - Returns number of events pending from plugin to be processed. +`pop_pending_event()` - Returns first unprocessed plugin event. diff --git a/plugins/gamecenter/game_center.mm b/plugins/gamecenter/game_center.mm index 851a526..64bda48 100644 --- a/plugins/gamecenter/game_center.mm +++ b/plugins/gamecenter/game_center.mm @@ -327,7 +327,7 @@ ERR_FAIL_COND_V(!is_authenticated(), ERR_UNAUTHORIZED); GKLocalPlayer *player = [GKLocalPlayer localPlayer]; - [player generateIdentityVerificationSignatureWithCompletionHandler:^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) { + void (^verificationSignatureHandler)(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) = ^(NSURL *publicKeyUrl, NSData *signature, NSData *salt, uint64_t timestamp, NSError *error) { Dictionary ret; ret["type"] = "identity_verification_signature"; if (error == nil) { @@ -336,7 +336,7 @@ ret["signature"] = [[signature base64EncodedStringWithOptions:0] UTF8String]; ret["salt"] = [[salt base64EncodedStringWithOptions:0] UTF8String]; ret["timestamp"] = timestamp; - if (@available(iOS 13, *)) { + if (@available(iOS 13.5, *)) { ret["player_id"] = [player.teamPlayerID UTF8String]; } else { ret["player_id"] = [player.playerID UTF8String]; @@ -348,7 +348,13 @@ }; pending_events.push_back(ret); - }]; + }; + + if (@available(iOS 13.5, *)) { + [player fetchItemsForIdentityVerificationSignature:verificationSignatureHandler]; + } else { + [player generateIdentityVerificationSignatureWithCompletionHandler:verificationSignatureHandler]; + } return OK; }; diff --git a/plugins/icloud/README.md b/plugins/icloud/README.md new file mode 100644 index 0000000..03397d0 --- /dev/null +++ b/plugins/icloud/README.md @@ -0,0 +1,18 @@ +# Godot iOS iCloud plugin + +Plugin generates new event with `key_value_changed` type when values stored in the iCloud key-value store changes. + +## Methods + +`remove_key(String key)` - Removes the value associated with the specified key from the iCloud key-value store. +`set_key_values(Dictionary values)` - Sets multiple objects for the specified keys in the iCloud key-value store. +`get_key_value(String key)` - Returns the object associated with the specified key stored in iCloud key-value store. +`synchronize_key_values()` - Synchronizes in-memory keys and values for iCloud storage with those stored on disk. +`get_all_key_values()` - Returns a dictionary containing all of the key-value pairs in the iCloud key-value store. + +## Properties + +## Events reporting + +`get_pending_event_count()` - Returns number of events pending from plugin to be processed. +`pop_pending_event()` - Returns first unprocessed plugin event. \ No newline at end of file diff --git a/plugins/inappstore/README.md b/plugins/inappstore/README.md new file mode 100644 index 0000000..d6cbc2f --- /dev/null +++ b/plugins/inappstore/README.md @@ -0,0 +1,16 @@ +# Godot iOS InAppStore plugin + +## Methods + +`request_product_info(Dictionary products_dictionary)` - Loads the unique identifiers for your in-app products in order to retrieve products information. Generates new event with `product_info` type. +`restore_purchases()` - Asks App Store payment queue to restore previously completed purchases. Generates new event with `restore` type. +`purchase(Dictionary product_dictionary)` - Adds a product payment request to the App Store payment queue. Generates new event with `purchase` type. +`set_auto_finish_transaction(bool flag)` - Sets a value responsible for enabling automatic transaction finishing. +`finish_transaction(String product_id)` - Notifies the App Store that the app finished processing the transaction. + +## Properties + +## Events reporting + +`get_pending_event_count()` - Returns number of events pending from plugin to be processed. +`pop_pending_event()` - Returns first unprocessed plugin event. \ No newline at end of file diff --git a/scripts/release_static_library.sh b/scripts/release_static_library.sh index 52b5209..8324142 100755 --- a/scripts/release_static_library.sh +++ b/scripts/release_static_library.sh @@ -1,56 +1,21 @@ #!/bin/bash -# Compile GameCenter +GODOT_PLUGINS="gamecenter inappstore icloud camera arkit apn" -./scripts/generate_static_library.sh gamecenter release $1 -./scripts/generate_static_library.sh gamecenter release_debug $1 -mv ./bin/gamecenter.release_debug.a ./bin/gamecenter.debug.a - -# Compile InAppStore - -./scripts/generate_static_library.sh inappstore release $1 -./scripts/generate_static_library.sh inappstore release_debug $1 -mv ./bin/inappstore.release_debug.a ./bin/inappstore.debug.a - -# Compile iCloud - -./scripts/generate_static_library.sh icloud release $1 -./scripts/generate_static_library.sh icloud release_debug $1 -mv ./bin/icloud.release_debug.a ./bin/icloud.debug.a - -# Compile Camera - -./scripts/generate_static_library.sh camera release $1 -./scripts/generate_static_library.sh camera release_debug $1 -mv ./bin/camera.release_debug.a ./bin/camera.debug.a - -# Compile ARKit - -./scripts/generate_static_library.sh arkit release $1 -./scripts/generate_static_library.sh arkit release_debug $1 -mv ./bin/arkit.release_debug.a ./bin/arkit.debug.a +# Compile Plugin +for lib in $GODOT_PLUGINS; do + ./scripts/generate_static_library.sh $lib release $1 + ./scripts/generate_static_library.sh $lib release_debug $1 + mv ./bin/${lib}.release_debug.a ./bin/${lib}.debug.a +done # Move to release folder rm -rf ./bin/release mkdir ./bin/release -# Move GameCenter -mkdir ./bin/release/gamecenter -mv ./bin/gamecenter.{release,debug}.a ./bin/release/gamecenter - -# Move InAppStore -mkdir ./bin/release/inappstore -mv ./bin/inappstore.{release,debug}.a ./bin/release/inappstore - -# Move InAppStore -mkdir ./bin/release/icloud -mv ./bin/icloud.{release,debug}.a ./bin/release/icloud - -# Move Camera -mkdir ./bin/release/camera -mv ./bin/camera.{release,debug}.a ./bin/release/camera - -# Move ARKit -mkdir ./bin/release/arkit -mv ./bin/arkit.{release,debug}.a ./bin/release/arkit \ No newline at end of file +# Move Plugin +for lib in $GODOT_PLUGINS; do + mkdir ./bin/release/${lib} + mv ./bin/${lib}.{release,debug}.a ./bin/release/${lib} +done \ No newline at end of file diff --git a/scripts/release_xcframework.sh b/scripts/release_xcframework.sh index 95757f9..086a560 100755 --- a/scripts/release_xcframework.sh +++ b/scripts/release_xcframework.sh @@ -1,61 +1,22 @@ #!/bin/bash -# Compile GameCenter +GODOT_PLUGINS="gamecenter inappstore icloud camera arkit apn" -./scripts/generate_xcframework.sh gamecenter release $1 -./scripts/generate_xcframework.sh gamecenter release_debug $1 -mv ./bin/gamecenter.release_debug.xcframework ./bin/gamecenter.debug.xcframework - -# Compile InAppStore - -./scripts/generate_xcframework.sh inappstore release $1 -./scripts/generate_xcframework.sh inappstore release_debug $1 -mv ./bin/inappstore.release_debug.xcframework ./bin/inappstore.debug.xcframework - -# Compile iCloud - -./scripts/generate_xcframework.sh icloud release $1 -./scripts/generate_xcframework.sh icloud release_debug $1 -mv ./bin/icloud.release_debug.xcframework ./bin/icloud.debug.xcframework - -# Compile Camera - -./scripts/generate_xcframework.sh camera release $1 -./scripts/generate_xcframework.sh camera release_debug $1 -mv ./bin/camera.release_debug.xcframework ./bin/camera.debug.xcframework - -# Compile ARKit - -./scripts/generate_xcframework.sh arkit release $1 -./scripts/generate_xcframework.sh arkit release_debug $1 -mv ./bin/arkit.release_debug.xcframework ./bin/arkit.debug.xcframework +# Compile Plugin +for lib in $GODOT_PLUGINS; do + ./scripts/generate_xcframework.sh $lib release $1 + ./scripts/generate_xcframework.sh $lib release_debug $1 + mv ./bin/${lib}.release_debug.xcframework ./bin/${lib}.debug.xcframework +done # Move to release folder rm -rf ./bin/release mkdir ./bin/release -# Move GameCenter -mkdir ./bin/release/gamecenter -mv ./bin/gamecenter.{release,debug}.xcframework ./bin/release/gamecenter -cp ./plugins/gamecenter/gamecenter.gdip ./bin/release/gamecenter - -# Move InAppStore -mkdir ./bin/release/icloud -mv ./bin/icloud.{release,debug}.xcframework ./bin/release/icloud -cp ./plugins/icloud/icloud.gdip ./bin/release/icloud - -# Move InAppStore -mkdir ./bin/release/inappstore -mv ./bin/inappstore.{release,debug}.xcframework ./bin/release/inappstore -cp ./plugins/inappstore/inappstore.gdip ./bin/release/inappstore - -# Move Camera -mkdir ./bin/release/camera -mv ./bin/camera.{release,debug}.xcframework ./bin/release/camera -cp ./plugins/camera/camera.gdip ./bin/release/camera - -# Move ARKit -mkdir ./bin/release/arkit -mv ./bin/arkit.{release,debug}.xcframework ./bin/release/arkit -cp ./plugins/arkit/arkit.gdip ./bin/release/arkit \ No newline at end of file +# Move Plugin +for lib in $GODOT_PLUGINS; do + mkdir ./bin/release/${lib} + mv ./bin/${lib}.{release,debug}.xcframework ./bin/release/${lib} + cp ./plugins/${lib}/${lib}.gdip ./bin/release/${lib} +done