Merge pull request #43557 from naithar/feature/pluggable_app_delegates_3.2

[3.2] [iOS] Pluggable application delegate
This commit is contained in:
Rémi Verschelde 2021-01-15 16:14:21 +01:00 committed by GitHub
commit c47ad12e80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 542 additions and 2 deletions

View file

@ -13,6 +13,7 @@ iphone_lib = [
"joypad_iphone.mm", "joypad_iphone.mm",
"godot_view.mm", "godot_view.mm",
"display_layer.mm", "display_layer.mm",
"godot_app_delegate.m",
"godot_view_renderer.mm", "godot_view_renderer.mm",
"godot_view_gesture_recognizer.mm", "godot_view_gesture_recognizer.mm",
"device_metrics.m", "device_metrics.m",

View file

@ -0,0 +1,41 @@
/*************************************************************************/
/* godot_app_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 <UIKit/UIKit.h>
typedef NSObject<UIApplicationDelegate> ApplicationDelegateService;
@interface GodotApplicalitionDelegate : NSObject <UIApplicationDelegate>
@property(class, readonly, strong) NSArray<ApplicationDelegateService *> *services;
+ (void)addService:(ApplicationDelegateService *)service;
@end

View file

@ -0,0 +1,497 @@
/*************************************************************************/
/* godot_app_delegate.m */
/*************************************************************************/
/* 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 "godot_app_delegate.h"
#import "app_delegate.h"
@interface GodotApplicalitionDelegate ()
@end
@implementation GodotApplicalitionDelegate
static NSMutableArray<ApplicationDelegateService *> *services = nil;
+ (NSArray<ApplicationDelegateService *> *)services {
return services;
}
+ (void)load {
services = [NSMutableArray new];
[services addObject:[AppDelegate new]];
}
+ (void)addService:(ApplicationDelegateService *)service {
if (!services || !service) {
return;
}
[services addObject:service];
}
// UIApplicationDelegate documantation can be found here: https://developer.apple.com/documentation/uikit/uiapplicationdelegate
// MARK: Window
- (UIWindow *)window {
UIWindow *result = nil;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
UIWindow *value = [service window];
if (value) {
result = value;
}
}
return result;
}
// MARK: Initializing
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application willFinishLaunchingWithOptions:launchOptions]) {
result = YES;
}
}
return result;
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary<UIApplicationLaunchOptionsKey, id> *)launchOptions {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application didFinishLaunchingWithOptions:launchOptions]) {
result = YES;
}
}
return result;
}
/* Can be handled by Info.plist. Not yet supported by Godot.
// MARK: Scene
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {}
*/
// MARK: Life-Cycle
- (void)applicationDidBecomeActive:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationDidBecomeActive:application];
}
}
- (void)applicationWillResignActive:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationWillResignActive:application];
}
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationDidEnterBackground:application];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationWillEnterForeground:application];
}
}
- (void)applicationWillTerminate:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationWillTerminate:application];
}
}
// MARK: Environment Changes
- (void)applicationProtectedDataDidBecomeAvailable:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationProtectedDataDidBecomeAvailable:application];
}
}
- (void)applicationProtectedDataWillBecomeUnavailable:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationProtectedDataWillBecomeUnavailable:application];
}
}
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationDidReceiveMemoryWarning:application];
}
}
- (void)applicationSignificantTimeChange:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationSignificantTimeChange:application];
}
}
// MARK: App State Restoration
- (BOOL)application:(UIApplication *)application shouldSaveSecureApplicationState:(NSCoder *)coder API_AVAILABLE(ios(13.2)) {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application shouldSaveSecureApplicationState:coder]) {
result = YES;
}
}
return result;
}
- (BOOL)application:(UIApplication *)application shouldRestoreSecureApplicationState:(NSCoder *)coder API_AVAILABLE(ios(13.2)) {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application shouldRestoreSecureApplicationState:coder]) {
result = YES;
}
}
return result;
}
- (UIViewController *)application:(UIApplication *)application viewControllerWithRestorationIdentifierPath:(NSArray<NSString *> *)identifierComponents coder:(NSCoder *)coder {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
UIViewController *controller = [service application:application viewControllerWithRestorationIdentifierPath:identifierComponents coder:coder];
if (controller) {
return controller;
}
}
return nil;
}
- (void)application:(UIApplication *)application willEncodeRestorableStateWithCoder:(NSCoder *)coder {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application willEncodeRestorableStateWithCoder:coder];
}
}
- (void)application:(UIApplication *)application didDecodeRestorableStateWithCoder:(NSCoder *)coder {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application didDecodeRestorableStateWithCoder:coder];
}
}
// MARK: Download Data in Background
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application handleEventsForBackgroundURLSession:identifier completionHandler:completionHandler];
}
completionHandler();
}
// MARK: Remote Notification
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
}
}
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
for (ApplicationDelegateService *service in 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 services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}
completionHandler(UIBackgroundFetchResultNoData);
}
// MARK: User Activity and Handling Quick Actions
- (BOOL)application:(UIApplication *)application willContinueUserActivityWithType:(NSString *)userActivityType {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application willContinueUserActivityWithType:userActivityType]) {
result = YES;
}
}
return result;
}
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray<id<UIUserActivityRestoring> > *restorableObjects))restorationHandler {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application continueUserActivity:userActivity restorationHandler:restorationHandler]) {
result = YES;
}
}
return result;
}
- (void)application:(UIApplication *)application didUpdateUserActivity:(NSUserActivity *)userActivity {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application didUpdateUserActivity:userActivity];
}
}
- (void)application:(UIApplication *)application didFailToContinueUserActivityWithType:(NSString *)userActivityType error:(NSError *)error {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application didFailToContinueUserActivityWithType:userActivityType error:error];
}
}
- (void)application:(UIApplication *)application performActionForShortcutItem:(UIApplicationShortcutItem *)shortcutItem completionHandler:(void (^)(BOOL succeeded))completionHandler {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application performActionForShortcutItem:shortcutItem completionHandler:completionHandler];
}
}
// MARK: WatchKit
- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *replyInfo))reply {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application handleWatchKitExtensionRequest:userInfo reply:reply];
}
}
// MARK: HealthKit
- (void)applicationShouldRequestHealthAuthorization:(UIApplication *)application {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service applicationShouldRequestHealthAuthorization:application];
}
}
// MARK: Opening an URL
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:app openURL:url options:options]) {
return YES;
}
}
return NO;
}
// MARK: Disallowing Specified App Extension Types
- (BOOL)application:(UIApplication *)application shouldAllowExtensionPointIdentifier:(UIApplicationExtensionPointIdentifier)extensionPointIdentifier {
BOOL result = NO;
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
if ([service application:application shouldAllowExtensionPointIdentifier:extensionPointIdentifier]) {
result = YES;
}
}
return result;
}
// MARK: SiriKit
- (id)application:(UIApplication *)application handlerForIntent:(INIntent *)intent API_AVAILABLE(ios(14.0)) {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
id result = [service application:application handlerForIntent:intent];
if (result) {
return result;
}
}
return nil;
}
// MARK: CloudKit
- (void)application:(UIApplication *)application userDidAcceptCloudKitShareWithMetadata:(CKShareMetadata *)cloudKitShareMetadata {
for (ApplicationDelegateService *service in services) {
if (![service respondsToSelector:_cmd]) {
continue;
}
[service application:application userDidAcceptCloudKitShareWithMetadata:cloudKitShareMetadata];
}
}
/* Handled By Info.plist file for now
// MARK: Interface Geometry
- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {}
*/
@end

View file

@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/ /*************************************************************************/
#import "app_delegate.h" #import "godot_app_delegate.h"
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#include <stdio.h> #include <stdio.h>
@ -43,7 +43,8 @@ int main(int argc, char *argv[]) {
printf("running app main\n"); printf("running app main\n");
@autoreleasepool { @autoreleasepool {
UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); NSString *className = NSStringFromClass([GodotApplicalitionDelegate class]);
UIApplicationMain(argc, argv, nil, className);
} }
printf("main done\n"); printf("main done\n");
return 0; return 0;