diff --git a/Assets/Editor/PostProcessBuild.cs b/Assets/Editor/PostProcessBuild.cs index fb712c7..4a77bb1 100644 --- a/Assets/Editor/PostProcessBuild.cs +++ b/Assets/Editor/PostProcessBuild.cs @@ -11,23 +11,23 @@ public class PostProcessBuild : IPostprocessBuildWithReport public void OnPostprocessBuild(UnityEditor.Build.Reporting.BuildReport report) { - // 检查是否为 iOS 平台构建 - // if (report.summary.platform == BuildTarget.iOS) - // { - // string projectPath = report.summary.outputPath; - // string customControllerPath = "Assets/Editor/UnityAppController.mm"; // 自定义文件的路径 - // string destinationPath = Path.Combine(projectPath, "Classes/UnityAppController.mm"); + //检查是否为 iOS 平台构建 + if (report.summary.platform == BuildTarget.iOS) + { + string projectPath = report.summary.outputPath; + string customControllerPath = "Assets/Editor/UnityAppController.mm"; // 自定义文件的路径 + string destinationPath = Path.Combine(projectPath, "Classes/UnityAppController.mm"); - // if (File.Exists(customControllerPath)) - // { - // // 复制文件到 Xcode 项目中 - // File.Copy(customControllerPath, destinationPath, overwrite: true); - // Debug.Log("Custom UnityAppController.mm has been copied to Xcode project."); - // } - // else - // { - // Debug.LogError("Custom UnityAppController.mm file not found at " + customControllerPath); - // } - // } + if (File.Exists(customControllerPath)) + { + // 复制文件到 Xcode 项目中 + File.Copy(customControllerPath, destinationPath, overwrite: true); + Debug.Log("Custom UnityAppController.mm has been copied to Xcode project."); + } + else + { + Debug.LogError("Custom UnityAppController.mm file not found at " + customControllerPath); + } + } } } \ No newline at end of file diff --git a/Assets/Editor/UnityAppController.mm b/Assets/Editor/UnityAppController.mm index a8950a7..15d28fe 100644 --- a/Assets/Editor/UnityAppController.mm +++ b/Assets/Editor/UnityAppController.mm @@ -53,8 +53,10 @@ bool _ios100orNewer = false, _ios101orNewer = false, _ios102orNewer = false, _io bool _ios110orNewer = false, _ios111orNewer = false, _ios112orNewer = false; bool _ios130orNewer = false, _ios140orNewer = false, _ios150orNewer = false, _ios160orNewer = false; +// minimal Unity initialization done, enough to do calls to provide data like URL launch +bool _unityEngineLoaded = false; // was core of Unity loaded (non-graphics part prior to loading first scene) -bool _unityEngineInitialized = false; +bool _unityEngineInitialized = false; // was unity rendering already inited: we should not touch rendering while this is false bool _renderingInited = false; // was unity inited: we should not touch unity api while this is false @@ -155,7 +157,6 @@ NSInteger _forceInterfaceOrientationMask = 0; InitUnityReplayKit(); #endif - //自己加的部分 [UIApplication sharedApplication].statusBarHidden = YES; @@ -167,7 +168,7 @@ NSInteger _forceInterfaceOrientationMask = 0; //[vc.view setFrame:self.window.bounds]; //[vc.view setBackgroundColor:[UIColor orangeColor]]; [self.window setRootViewController:vc]; - + vc.modalPresentationStyle = UIModalPresentationFullScreen; [vc.view addSubview:unityView]; H5View *hview; hview = [H5View shared]; @@ -214,6 +215,12 @@ extern "C" void UnityDestroyDisplayLink() [GetAppController() destroyDisplayLink]; } +extern "C" void UnityRequestUnload() +{ + _unityAppReady = false; + [[NSNotificationCenter defaultCenter] postNotificationName: kUnityDidUnload object: nil]; +} + extern "C" void UnityRequestQuit() { _didResignActive = true; @@ -226,15 +233,15 @@ extern "C" void UnityRequestQuit() extern void SensorsCleanup(); extern "C" void UnityCleanupTrampoline() { - // Unity view and viewController will not necessary be destroyed right after this function execution. - // We need to ensure that these objects will not receive any callbacks from system during that time. - [_UnityAppController window].rootViewController = nil; - [[_UnityAppController unityView] removeFromSuperview]; - // Prevent multiple cleanups if (_UnityAppController == nil) return; + // Unity view and viewController will not necessary be destroyed right after this function execution. + // We need to ensure that these objects will not receive any callbacks from system during that time. + _UnityAppController.window.rootViewController = nil; + [_UnityAppController.unityView removeFromSuperview]; + [KeyboardDelegate Destroy]; SensorsCleanup(); @@ -252,7 +259,6 @@ extern "C" void UnityCleanupTrampoline() - (NSUInteger)application:(UIApplication*)application supportedInterfaceOrientationsForWindow:(UIWindow*)window { - return UIInterfaceOrientationMaskPortrait; // No rootViewController is set because we are switching from one view controller to another, all orientations should be enabled if ([window rootViewController] == nil) return UIInterfaceOrientationMaskAll; @@ -337,9 +343,39 @@ extern "C" void UnityCleanupTrampoline() - (BOOL)application:(UIApplication*)application willFinishLaunchingWithOptions:(NSDictionary*)launchOptions { AppController_SendNotificationWithArg(kUnityWillFinishLaunchingWithOptions, launchOptions); + NSURL* url = [self extractURLFromLaunchOptions: launchOptions]; + if (url != nil) + { + [self initUnityApplicationNoGraphics]; + UnitySetAbsoluteURL(url.absoluteString.UTF8String); + } return YES; } +// Helper method to extract URL from launch options +- (NSURL*)extractURLFromLaunchOptions:(NSDictionary*)launchOptions +{ + // Check for the direct launch URL + NSURL* url = launchOptions[UIApplicationLaunchOptionsURLKey]; + if (url != nil) + { + return url; + } + + // Check for the user activity dictionary and URL from user activity + NSUserActivity* userActivity = launchOptions[UIApplicationLaunchOptionsUserActivityDictionaryKey][@"UIApplicationLaunchOptionsUserActivityKey"]; + if (userActivity != nil && [userActivity.activityType isEqualToString: NSUserActivityTypeBrowsingWeb]) + { + url = userActivity.webpageURL; + if (url != nil) + { + return url; + } + } + + return nil; +} + - (UIWindowScene*)pickStartupWindowScene:(NSSet*)scenes API_AVAILABLE(ios(13.0), tvos(13.0)) { // if we have scene with UISceneActivationStateForegroundActive - pick it @@ -374,30 +410,23 @@ extern "C" void UnityCleanupTrampoline() if ([UIDevice currentDevice].generatesDeviceOrientationNotifications == NO) [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; #endif - - - EventMark *eventMark; - eventMark = [EventMark sharedEventMark]; - [eventMark initDataEyeSDK]; - - if ([self isBackgroundLaunchOptions: launchOptions]) + // if application is in background, don't initialize Unity + // this happens if app uses location fence, notifications with content/actions, ... + // initUnityWithApplication: initializes rendering, possibly loads scene and calls Start(), none meant for background + if (UIApplication.sharedApplication.applicationState == UIApplicationStateBackground) return YES; [self initUnityWithApplication: application]; return YES; } -- (BOOL)isBackgroundLaunchOptions:(NSDictionary*)launchOptions +- (void)initUnityApplicationNoGraphics { - if (launchOptions.count == 0) - return NO; - - // launch due to location event, the app likely will stay in background - BOOL locationLaunch = [[launchOptions valueForKey: UIApplicationLaunchOptionsLocationKey] boolValue]; - if (locationLaunch) - return YES; - return NO; + if (_unityEngineLoaded) + return; + _unityEngineLoaded = true; + UnityInitApplicationNoGraphics(UnityDataBundleDir()); } - (void)initUnityWithApplication:(UIApplication*)application @@ -407,7 +436,7 @@ extern "C" void UnityCleanupTrampoline() _unityEngineInitialized = true; // basic unity init - UnityInitApplicationNoGraphics(UnityDataBundleDir()); + [self initUnityApplicationNoGraphics]; [self selectRenderingAPI]; [UnityRenderingView InitializeForAPI: self.renderingAPI]; @@ -594,6 +623,12 @@ extern "C" void UnityCleanupTrampoline() // this happens if the app is force closed immediately after opening it. if (_unityAppReady) { + // make sure that we are in a "unity cannot be touched" state + // if there was some complex UI shown when terminating, we can get extra UI calls from iOS after applicationWillTerminate: + // and we want to make sure we never do anything touching unity runtime at this point + _unityAppReady = _renderingInited = _unityEngineInitialized = false; + _didResignActive = true; + UnityCleanup(); UnityCleanupTrampoline(); } @@ -623,20 +658,11 @@ void AppController_SendUnityViewControllerNotification(NSString* name) [[NSNotificationCenter defaultCenter] postNotificationName: name object: UnityGetGLViewController()]; } -extern "C" UIWindow* UnityGetMainWindow() -{ - return GetAppController().mainDisplay.window; -} +extern "C" UIWindow* UnityGetMainWindow() { return GetAppController().mainDisplay.window; } +extern "C" UIViewController* UnityGetGLViewController() { return GetAppController().rootViewController; } +extern "C" UnityView* UnityGetUnityView() { return GetAppController().unityView; } +extern "C" UIView* UnityGetGLView() { return UnityGetUnityView(); } -extern "C" UIViewController* UnityGetGLViewController() -{ - return GetAppController().rootViewController; -} - -extern "C" UIView* UnityGetGLView() -{ - return GetAppController().unityView; -} extern "C" ScreenOrientation UnityCurrentOrientation() { return GetAppController().unityView.contentOrientation; } @@ -679,8 +705,10 @@ static bool isDebuggerAttachedToConsole(void) assert(junk == 0); // We're being debugged if the P_TRACED flag is set. - - return ((info.kp_proc.p_flag & P_TRACED) != 0); + // But if we are starting app on device (and make debugger wait and attach after start) + // it will NOT connect stout (only stderr, used by nslog) + // Hence we also check that stoud is rerouted + return ((info.kp_proc.p_flag & P_TRACED) != 0) && isatty(STDOUT_FILENO); } void UnityInitTrampoline()