Atlas - SDL_uikitappdelegate.m
Home / ext / SDL / src / video / uikit Lines: 1 | Size: 22457 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_VIDEO_DRIVER_UIKIT 24 25#include "../SDL_sysvideo.h" 26 27#import "SDL_uikitappdelegate.h" 28#import "SDL_uikitmodes.h" 29#import "SDL_uikitwindow.h" 30 31#include "../../events/SDL_events_c.h" 32#include "../../main/SDL_main_callbacks.h" 33 34#ifdef main 35#undef main 36#endif 37 38static SDL_main_func forward_main; 39static int forward_argc; 40static char **forward_argv; 41static int exit_status; 42 43int SDL_RunApp(int argc, char *argv[], SDL_main_func mainFunction, void *reserved) 44{ 45 // store arguments 46 forward_main = mainFunction; 47 forward_argc = argc; 48 forward_argv = argv; 49 50 // Give over control to run loop, SDLUIKitDelegate will handle most things from here 51 @autoreleasepool { 52 NSString *name = nil; 53 54 if (@available(iOS 13.0, tvOS 13.0, *)) { 55 name = [SDLUIKitSceneDelegate getSceneDelegateClassName]; 56 } 57 if (!name) { 58 name = [SDLUIKitDelegate getAppDelegateClassName]; 59 } 60 UIApplicationMain(argc, argv, nil, name); 61 } 62 63 return exit_status; 64} 65 66#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 67// Load a launch image using the old UILaunchImageFile-era naming rules. 68static UIImage *SDL_LoadLaunchImageNamed(NSString *name, int screenh) 69{ 70 UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; 71 UIUserInterfaceIdiom idiom = [UIDevice currentDevice].userInterfaceIdiom; 72 UIImage *image = nil; 73 74 if (idiom == UIUserInterfaceIdiomPhone && screenh == 568) { 75 // The image name for the iPhone 5 uses its height as a suffix. 76 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-568h", name]]; 77 } else if (idiom == UIUserInterfaceIdiomPad) { 78 // iPad apps can launch in any orientation. 79 if (UIInterfaceOrientationIsLandscape(curorient)) { 80 if (curorient == UIInterfaceOrientationLandscapeLeft) { 81 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeLeft", name]]; 82 } else { 83 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-LandscapeRight", name]]; 84 } 85 if (!image) { 86 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Landscape", name]]; 87 } 88 } else { 89 if (curorient == UIInterfaceOrientationPortraitUpsideDown) { 90 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-PortraitUpsideDown", name]]; 91 } 92 if (!image) { 93 image = [UIImage imageNamed:[NSString stringWithFormat:@"%@-Portrait", name]]; 94 } 95 } 96 } 97 98 if (!image) { 99 image = [UIImage imageNamed:name]; 100 } 101 102 return image; 103} 104 105@interface SDLLaunchStoryboardViewController : UIViewController 106@property(nonatomic, strong) UIViewController *storyboardViewController; 107- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController; 108@end 109 110@implementation SDLLaunchStoryboardViewController 111 112- (instancetype)initWithStoryboardViewController:(UIViewController *)storyboardViewController 113{ 114 self = [super init]; 115 self.storyboardViewController = storyboardViewController; 116 return self; 117} 118 119- (void)viewDidLoad 120{ 121 [super viewDidLoad]; 122 123 [self addChildViewController:self.storyboardViewController]; 124 [self.view addSubview:self.storyboardViewController.view]; 125 self.storyboardViewController.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 126 self.storyboardViewController.view.frame = self.view.bounds; 127 [self.storyboardViewController didMoveToParentViewController:self]; 128 129#ifndef SDL_PLATFORM_VISIONOS 130 UIApplication.sharedApplication.statusBarHidden = self.prefersStatusBarHidden; 131 UIApplication.sharedApplication.statusBarStyle = self.preferredStatusBarStyle; 132#endif 133} 134 135- (BOOL)prefersStatusBarHidden 136{ 137 return [[NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarHidden"] boolValue]; 138} 139 140- (UIStatusBarStyle)preferredStatusBarStyle 141{ 142 NSString *statusBarStyle = [NSBundle.mainBundle objectForInfoDictionaryKey:@"UIStatusBarStyle"]; 143 if ([statusBarStyle isEqualToString:@"UIStatusBarStyleLightContent"]) { 144 return UIStatusBarStyleLightContent; 145 } 146 if (@available(iOS 13.0, *)) { 147 if ([statusBarStyle isEqualToString:@"UIStatusBarStyleDarkContent"]) { 148 return UIStatusBarStyleDarkContent; 149 } 150 } 151 return UIStatusBarStyleDefault; 152} 153 154@end 155#endif // !SDL_PLATFORM_TVOS 156 157 158@interface SDLLaunchScreenController () 159 160#ifndef SDL_PLATFORM_TVOS 161- (NSUInteger)supportedInterfaceOrientations; 162#endif 163 164@end 165 166@implementation SDLLaunchScreenController 167 168- (instancetype)init 169{ 170 return [self initWithNibName:nil bundle:[NSBundle mainBundle]]; 171} 172 173- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 174{ 175 if (!(self = [super initWithNibName:nil bundle:nil])) { 176 return nil; 177 } 178 179 NSString *screenname = nibNameOrNil; 180 NSBundle *bundle = nibBundleOrNil; 181 182 // A launch screen may not exist. Fall back to launch images in that case. 183 if (screenname) { 184 @try { 185 self.view = [bundle loadNibNamed:screenname owner:self options:nil][0]; 186 } 187 @catch (NSException *exception) { 188 /* If a launch screen name is specified but it fails to load, iOS 189 * displays a blank screen rather than falling back to an image. */ 190 return nil; 191 } 192 } 193 194 if (!self.view) { 195 NSArray *launchimages = [bundle objectForInfoDictionaryKey:@"UILaunchImages"]; 196 NSString *imagename = nil; 197 UIImage *image = nil; 198 199#ifdef SDL_PLATFORM_VISIONOS 200 int screenw = SDL_XR_SCREENWIDTH; 201 int screenh = SDL_XR_SCREENHEIGHT; 202#else 203 int screenw = (int)([UIScreen mainScreen].bounds.size.width + 0.5); 204 int screenh = (int)([UIScreen mainScreen].bounds.size.height + 0.5); 205#endif 206 207 208 209#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 210 UIInterfaceOrientation curorient = [UIApplication sharedApplication].statusBarOrientation; 211 212 // We always want portrait-oriented size, to match UILaunchImageSize. 213 if (screenw > screenh) { 214 int width = screenw; 215 screenw = screenh; 216 screenh = width; 217 } 218#endif 219 220 // Xcode 5 introduced a dictionary of launch images in Info.plist. 221 if (launchimages) { 222 for (NSDictionary *dict in launchimages) { 223 NSString *minversion = dict[@"UILaunchImageMinimumOSVersion"]; 224 NSString *sizestring = dict[@"UILaunchImageSize"]; 225 226 // Ignore this image if the current version is too low. 227 if (minversion && !UIKit_IsSystemVersionAtLeast(minversion.doubleValue)) { 228 continue; 229 } 230 231 // Ignore this image if the size doesn't match. 232 if (sizestring) { 233 CGSize size = CGSizeFromString(sizestring); 234 if ((int)(size.width + 0.5) != screenw || (int)(size.height + 0.5) != screenh) { 235 continue; 236 } 237 } 238 239#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 240 UIInterfaceOrientationMask orientmask = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; 241 NSString *orientstring = dict[@"UILaunchImageOrientation"]; 242 243 if (orientstring) { 244 if ([orientstring isEqualToString:@"PortraitUpsideDown"]) { 245 orientmask = UIInterfaceOrientationMaskPortraitUpsideDown; 246 } else if ([orientstring isEqualToString:@"Landscape"]) { 247 orientmask = UIInterfaceOrientationMaskLandscape; 248 } else if ([orientstring isEqualToString:@"LandscapeLeft"]) { 249 orientmask = UIInterfaceOrientationMaskLandscapeLeft; 250 } else if ([orientstring isEqualToString:@"LandscapeRight"]) { 251 orientmask = UIInterfaceOrientationMaskLandscapeRight; 252 } 253 } 254 255 // Ignore this image if the orientation doesn't match. 256 if ((orientmask & (1 << curorient)) == 0) { 257 continue; 258 } 259#endif 260 261 imagename = dict[@"UILaunchImageName"]; 262 } 263 264 if (imagename) { 265 image = [UIImage imageNamed:imagename]; 266 } 267 } 268#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 269 else { 270 imagename = [bundle objectForInfoDictionaryKey:@"UILaunchImageFile"]; 271 272 if (imagename) { 273 image = SDL_LoadLaunchImageNamed(imagename, screenh); 274 } 275 276 if (!image) { 277 image = SDL_LoadLaunchImageNamed(@"Default", screenh); 278 } 279 } 280#endif 281 282 if (image) { 283#ifdef SDL_PLATFORM_VISIONOS 284 CGRect viewFrame = CGRectMake(0, 0, screenw, screenh); 285#else 286 CGRect viewFrame = [UIScreen mainScreen].bounds; 287#endif 288 UIImageView *view = [[UIImageView alloc] initWithFrame:viewFrame]; 289 UIImageOrientation imageorient = UIImageOrientationUp; 290 291#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 292 // Bugs observed / workaround tested in iOS 8.3. 293 if (UIInterfaceOrientationIsLandscape(curorient)) { 294 if (image.size.width < image.size.height) { 295 /* On iOS 8, portrait launch images displayed in forced- 296 * landscape mode (e.g. a standard Default.png on an iPhone 297 * when Info.plist only supports landscape orientations) need 298 * to be rotated to display in the expected orientation. */ 299 if (curorient == UIInterfaceOrientationLandscapeLeft) { 300 imageorient = UIImageOrientationRight; 301 } else if (curorient == UIInterfaceOrientationLandscapeRight) { 302 imageorient = UIImageOrientationLeft; 303 } 304 } 305 } 306#endif 307 308 // Create the properly oriented image. 309 view.image = [[UIImage alloc] initWithCGImage:image.CGImage scale:image.scale orientation:imageorient]; 310 311 self.view = view; 312 } 313 } 314 315 return self; 316} 317 318- (void)loadView 319{ 320 // Do nothing. 321} 322 323#ifndef SDL_PLATFORM_TVOS 324- (BOOL)shouldAutorotate 325{ 326 // If YES, the launch image will be incorrectly rotated in some cases. 327 return NO; 328} 329 330- (NSUInteger)supportedInterfaceOrientations 331{ 332 /* We keep the supported orientations unrestricted to avoid the case where 333 * there are no common orientations between the ones set in Info.plist and 334 * the ones set here (it will cause an exception in that case.) */ 335 return UIInterfaceOrientationMaskAll; 336} 337#endif // !SDL_PLATFORM_TVOS 338 339@end // SDLLaunchScreenController 340 341 342API_AVAILABLE(ios(13.0)) 343@implementation SDLUIKitSceneDelegate 344{ 345 UIWindow *launchWindow; 346} 347 348+ (NSString *)getSceneDelegateClassName 349{ 350 return @"SDLUIKitSceneDelegate"; 351} 352 353- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions 354{ 355 if (![scene isKindOfClass:[UIWindowScene class]]) { 356 return; 357 } 358 359 UIWindowScene *windowScene = (UIWindowScene *)scene; 360 windowScene.delegate = self; 361 362 NSBundle *bundle = [NSBundle mainBundle]; 363 364#ifdef SDL_IPHONE_LAUNCHSCREEN 365 UIViewController *vc = nil; 366 NSString *screenname = nil; 367 368#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 369 screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; 370 371 if (screenname) { 372 @try { 373 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle]; 374 __auto_type storyboardVc = [storyboard instantiateInitialViewController]; 375 vc = [[SDLLaunchStoryboardViewController alloc] initWithStoryboardViewController:storyboardVc]; 376 } 377 @catch (NSException *exception) { 378 // Do nothing (there's more code to execute below). 379 } 380 } 381#endif 382 383 if (vc == nil) { 384 vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle]; 385 } 386 387 if (vc.view) { 388#ifdef SDL_PLATFORM_VISIONOS 389 CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT); 390#else 391 CGRect viewFrame = windowScene.coordinateSpace.bounds; 392#endif 393 launchWindow = [[UIWindow alloc] initWithWindowScene:windowScene]; 394 launchWindow.frame = viewFrame; 395 396 launchWindow.windowLevel = UIWindowLevelNormal + 1.0; 397 launchWindow.hidden = NO; 398 launchWindow.rootViewController = vc; 399 } 400#endif 401 402 // Set working directory to resource path 403 [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]]; 404 405 // Handle any connection options (like opening URLs) 406 for (NSUserActivity *activity in connectionOptions.userActivities) { 407 if (activity.webpageURL) { 408 [self handleURL:activity.webpageURL]; 409 } 410 } 411 412 for (UIOpenURLContext *urlContext in connectionOptions.URLContexts) { 413 [self handleURL:urlContext.URL]; 414 } 415 416 SDL_SetMainReady(); 417 [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0]; 418} 419 420- (void)scene:(UIScene *)scene openURLContexts:(NSSet<UIOpenURLContext *> *)URLContexts 421{ 422 for (UIOpenURLContext *context in URLContexts) { 423 [self handleURL:context.URL]; 424 } 425} 426 427- (void)sceneDidBecomeActive:(UIScene *)scene 428{ 429 SDL_OnApplicationDidEnterForeground(); 430} 431 432- (void)sceneWillResignActive:(UIScene *)scene 433{ 434 SDL_OnApplicationWillEnterBackground(); 435} 436 437- (void)sceneWillEnterForeground:(UIScene *)scene 438{ 439 SDL_OnApplicationWillEnterForeground(); 440} 441 442- (void)sceneDidEnterBackground:(UIScene *)scene 443{ 444 SDL_OnApplicationDidEnterBackground(); 445} 446 447- (void)handleURL:(NSURL *)url 448{ 449 const char *sourceApplicationCString = NULL; 450 NSURL *fileURL = url.filePathURL; 451 if (fileURL != nil) { 452 SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String); 453 } else { 454 SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String); 455 } 456 SDL_SendDropComplete(NULL); 457} 458 459- (void)hideLaunchScreen 460{ 461 UIWindow *window = launchWindow; 462 463 if (!window || window.hidden) { 464 return; 465 } 466 467 launchWindow = nil; 468 469 [UIView animateWithDuration:0.2 470 animations:^{ 471 window.alpha = 0.0; 472 } 473 completion:^(BOOL finished) { 474 window.hidden = YES; 475 UIKit_ForceUpdateHomeIndicator(); 476 }]; 477} 478 479- (void)postFinishLaunch 480{ 481 [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; 482 483 SDL_SetiOSEventPump(true); 484 exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); 485 SDL_SetiOSEventPump(false); 486 487 if (launchWindow) { 488 launchWindow.hidden = YES; 489 launchWindow = nil; 490 } 491} 492 493- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options API_AVAILABLE(ios(13.0)) 494{ 495 // This doesn't appear to be called, but it needs to be implemented to signal that we support the UIScene life cycle 496 UISceneConfiguration *config = [[UISceneConfiguration alloc] initWithName:@"SDLSceneConfiguration" sessionRole:connectingSceneSession.role]; 497 config.delegateClass = [SDLUIKitSceneDelegate class]; 498 return config; 499} 500 501@end // SDLUIKitSceneDelegate 502 503 504@implementation SDLUIKitDelegate 505{ 506 UIWindow *launchWindow; 507} 508 509// convenience method 510+ (id)sharedAppDelegate 511{ 512 /* the delegate is set in UIApplicationMain(), which is guaranteed to be 513 * called before this method */ 514 return [UIApplication sharedApplication].delegate; 515} 516 517+ (NSString *)getAppDelegateClassName 518{ 519 /* subclassing notice: when you subclass this appdelegate, make sure to add 520 * a category to override this method and return the actual name of the 521 * delegate */ 522 return @"SDLUIKitDelegate"; 523} 524 525- (void)hideLaunchScreen 526{ 527 UIWindow *window = launchWindow; 528 529 if (!window || window.hidden) { 530 return; 531 } 532 533 launchWindow = nil; 534 535 // Do a nice animated fade-out (roughly matches the real launch behavior.) 536 [UIView animateWithDuration:0.2 537 animations:^{ 538 window.alpha = 0.0; 539 } 540 completion:^(BOOL finished) { 541 window.hidden = YES; 542 UIKit_ForceUpdateHomeIndicator(); // Wait for launch screen to hide so settings are applied to the actual view controller. 543 }]; 544} 545 546- (void)postFinishLaunch 547{ 548 /* Hide the launch screen the next time the run loop is run. SDL apps will 549 * have a chance to load resources while the launch screen is still up. */ 550 [self performSelector:@selector(hideLaunchScreen) withObject:nil afterDelay:0.0]; 551 552 // run the user's application, passing argc and argv 553 SDL_SetiOSEventPump(true); 554 exit_status = SDL_CallMainFunction(forward_argc, forward_argv, forward_main); 555 SDL_SetiOSEventPump(false); 556 557 if (launchWindow) { 558 launchWindow.hidden = YES; 559 launchWindow = nil; 560 } 561 562 // exit, passing the return status from the user's application 563 /* We don't actually exit to support applications that do setup in their 564 * main function and then allow the Cocoa event loop to run. */ 565 // exit(exit_status); 566} 567 568- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 569{ 570 NSBundle *bundle = [NSBundle mainBundle]; 571 572#ifdef SDL_IPHONE_LAUNCHSCREEN 573 /* The normal launch screen is displayed until didFinishLaunching returns, 574 * but SDL_main is called after that happens and there may be a noticeable 575 * delay between the start of SDL_main and when the first real frame is 576 * displayed (e.g. if resources are loaded before SDL_GL_SwapWindow is 577 * called), so we show the launch screen programmatically until the first 578 * time events are pumped. */ 579 UIViewController *vc = nil; 580 NSString *screenname = nil; 581 582 // tvOS only uses a plain launch image. 583#if !defined(SDL_PLATFORM_TVOS) && !defined(SDL_PLATFORM_VISIONOS) 584 screenname = [bundle objectForInfoDictionaryKey:@"UILaunchStoryboardName"]; 585 586 if (screenname) { 587 @try { 588 /* The launch storyboard is actually a nib in some older versions of 589 * Xcode. We'll try to load it as a storyboard first, as it's more 590 * modern. */ 591 UIStoryboard *storyboard = [UIStoryboard storyboardWithName:screenname bundle:bundle]; 592 __auto_type storyboardVc = [storyboard instantiateInitialViewController]; 593 vc = [[SDLLaunchStoryboardViewController alloc] initWithStoryboardViewController:storyboardVc]; 594 } 595 @catch (NSException *exception) { 596 // Do nothing (there's more code to execute below). 597 } 598 } 599#endif 600 601 if (vc == nil) { 602 vc = [[SDLLaunchScreenController alloc] initWithNibName:screenname bundle:bundle]; 603 } 604 605 if (vc.view) { 606#ifdef SDL_PLATFORM_VISIONOS 607 CGRect viewFrame = CGRectMake(0, 0, SDL_XR_SCREENWIDTH, SDL_XR_SCREENHEIGHT); 608#else 609 CGRect viewFrame = [UIScreen mainScreen].bounds; 610#endif 611 launchWindow = [[UIWindow alloc] initWithFrame:viewFrame]; 612 613 /* We don't want the launch window immediately hidden when a real SDL 614 * window is shown - we fade it out ourselves when we're ready. */ 615 launchWindow.windowLevel = UIWindowLevelNormal + 1.0; 616 617 /* Show the window but don't make it key. Events should always go to 618 * other windows when possible. */ 619 launchWindow.hidden = NO; 620 621 launchWindow.rootViewController = vc; 622 } 623#endif 624 625 // Set working directory to resource path 626 [[NSFileManager defaultManager] changeCurrentDirectoryPath:[bundle resourcePath]]; 627 628 SDL_SetMainReady(); 629 [self performSelector:@selector(postFinishLaunch) withObject:nil afterDelay:0.0]; 630 631 return YES; 632} 633 634- (UIWindow *)window 635{ 636 SDL_VideoDevice *_this = SDL_GetVideoDevice(); 637 if (_this) { 638 SDL_Window *window = NULL; 639 for (window = _this->windows; window != NULL; window = window->next) { 640 SDL_UIKitWindowData *data = (__bridge SDL_UIKitWindowData *)window->internal; 641 if (data != nil) { 642 return data.uiwindow; 643 } 644 } 645 } 646 return nil; 647} 648 649- (void)setWindow:(UIWindow *)window 650{ 651 // Do nothing. 652} 653 654- (void)sendDropFileForURL:(NSURL *)url fromSourceApplication:(NSString *)sourceApplication 655{ 656 NSURL *fileURL = url.filePathURL; 657 const char *sourceApplicationCString = sourceApplication ? [sourceApplication UTF8String] : NULL; 658 if (fileURL != nil) { 659 SDL_SendDropFile(NULL, sourceApplicationCString, fileURL.path.UTF8String); 660 } else { 661 SDL_SendDropFile(NULL, sourceApplicationCString, url.absoluteString.UTF8String); 662 } 663 SDL_SendDropComplete(NULL); 664} 665 666- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options 667{ 668 // TODO: Handle options 669 [self sendDropFileForURL:url fromSourceApplication:NULL]; 670 return YES; 671} 672 673@end // SDLUIKitDelegate 674 675#endif // SDL_VIDEO_DRIVER_UIKIT 676[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.