From 37b32b5670fedae13ae24e3124cb0f202b7b6045 Mon Sep 17 00:00:00 2001 From: Ethan Arbuckle Date: Sat, 30 Mar 2024 23:47:29 -0700 Subject: [PATCH] Fix crashes. App scenes are rendering on the Carplay scene --- src/CRCarplayWindow.mm | 21 ++++++++++++++++++--- src/hooks/CarPlay.xm | 2 +- src/hooks/SpringBoard.xm | 11 ++++++++++- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/CRCarplayWindow.mm b/src/CRCarplayWindow.mm index 6296116..a09c87a 100644 --- a/src/CRCarplayWindow.mm +++ b/src/CRCarplayWindow.mm @@ -274,7 +274,14 @@ - (void)setupLiveAppView id mainScreenIdentity = objcInvoke(displaySceneManager, @"displayIdentity"); assertGotExpectedObject(mainScreenIdentity, @"FBSDisplayIdentity"); - id sceneIdentity = objcInvoke_2(displaySceneManager, @"_sceneIdentityForApplication:createPrimaryIfRequired:", self.application, 1); + id sceneIdentity = nil; + if ([displaySceneManager respondsToSelector:NSSelectorFromString(@"_sceneIdentityForApplication:createPrimaryIfRequired:")]) { + sceneIdentity = objcInvoke_2(displaySceneManager, @"_sceneIdentityForApplication:createPrimaryIfRequired:", self.application, 1); + } + else if ([displaySceneManager respondsToSelector:NSSelectorFromString(@"_sceneIdentityForApplication:createPrimaryIfRequired:sceneSessionRole:")]) { + sceneIdentity = objcInvoke_3(displaySceneManager, @"_sceneIdentityForApplication:createPrimaryIfRequired:sceneSessionRole:", self.application, 1, @"UIWindowSceneSessionRoleApplication"); + } + assertGotExpectedObject(sceneIdentity, @"FBSSceneIdentity"); id sceneHandleRequest = objcInvoke_3(objc_getClass("SBApplicationSceneHandleRequest"), @"defaultRequestForApplication:sceneIdentity:displayIdentity:", self.application, sceneIdentity, mainScreenIdentity); @@ -349,7 +356,14 @@ - (void)setupLiveAppView // Create a scene monitor to watch for the app process dying. The carplay window will dismiss itself. // todo: this returns nil if the app process isn't running.. - NSString *sceneID = objcInvoke_1(sceneLayoutManager, @"primarySceneIdentifierForBundleIdentifier:", appIdentifier); + NSString *sceneID = nil; + if ([sceneLayoutManager respondsToSelector:NSSelectorFromString(@"primarySceneIdentifierForBundleIdentifier:")]) { + sceneID = objcInvoke_1(sceneLayoutManager, @"primarySceneIdentifierForBundleIdentifier:", appIdentifier); + } + else if ([sceneLayoutManager respondsToSelector:NSSelectorFromString(@"primarySceneIdentifierForBundleIdentifier:sceneSessionRole:")]) { + sceneID = objcInvoke_2(sceneLayoutManager, @"primarySceneIdentifierForBundleIdentifier:sceneSessionRole:", appIdentifier, @"UIWindowSceneSessionRoleApplication"); + } + self.sceneMonitor = objcInvoke_1([objc_getClass("FBSceneMonitor") alloc], @"initWithSceneID:", sceneID); objcInvoke_1(self.sceneMonitor, @"setDelegate:", self); } @@ -463,7 +477,7 @@ - (void)dismiss id sceneSettings = objcInvoke(appScene, @"mutableSettings"); objcInvoke_1(sceneSettings, @"setBackgrounded:", 1); objcInvoke_1(sceneSettings, @"setForeground:", 0); - ((void (*)(id, SEL, id, id, void *))objc_msgSend)(appScene, NSSelectorFromString(@"updateSettings:withTransitionContext:completion:"), sceneSettings, nil, 0); + // ((void (*)(id, SEL, id, id))objc_msgSend)(appScene, NSSelectorFromString(@"updateSettings:withTransitionContext:"), sceneSettings, nil); } } @@ -568,6 +582,7 @@ - (void)resizeAppViewForOrientation:(int)desiredOrientation fullscreen:(BOOL)ful xOrigin = (carplayDisplaySize.width / 2) - (scaledDisplayWidth / 2); } + NSLog(@"Scaling app view to %.2fx%.2f (target size: %.2fx%.2f)", widthScale, heightScale, carplayDisplaySize.width, carplayDisplaySize.height); [hostingContentView setTransform:CGAffineTransformMakeScale(widthScale, heightScale)]; [[self.appViewController view] setFrame:CGRectMake(xOrigin, [[self.appViewController view] frame].origin.y, carplayDisplaySize.width, carplayDisplaySize.height)]; diff --git a/src/hooks/CarPlay.xm b/src/hooks/CarPlay.xm index 5d1dd98..c30d13f 100644 --- a/src/hooks/CarPlay.xm +++ b/src/hooks/CarPlay.xm @@ -98,7 +98,7 @@ Include all User applications on the CarPlay dashboard id appState = objcInvoke(appProxy, @"appState"); if (objcInvokeT(appState, @"isValid", int) == 1) { - objcInvoke_2(allAppsLibrary, @"addApplicationProxy:withOverrideURL:", appProxy, 0); + // objcInvoke_2(allAppsLibrary, @"addApplicationProxy:withOverrideURL:", appProxy, 0); } } diff --git a/src/hooks/SpringBoard.xm b/src/hooks/SpringBoard.xm index b6d1970..47631cb 100644 --- a/src/hooks/SpringBoard.xm +++ b/src/hooks/SpringBoard.xm @@ -183,8 +183,9 @@ happen while the device is in a faceup/facedown orientation. Called when something is trying to change a scene's settings (including sending it to background/foreground). Use this to prevent the App from going to sleep when other applications are launched on the main screen. */ -- (void)updateSettings:(id)arg1 withTransitionContext:(id)arg2 completion:(void *)arg3 +- (void)_updateSettings:(id)arg1 withTransitionContext:(id)arg2 completion:(void *)arg3 { + LOG_LIFECYCLE_EVENT; id sceneClient = objcInvoke(self, @"client"); if ([sceneClient respondsToSelector:NSSelectorFromString(@"process")]) { @@ -202,6 +203,14 @@ Use this to prevent the App from going to sleep when other applications are laun %orig; } +/* + The scene's client getter method was removed in iOS 15 but the ivar is still accessible +*/ +%new +- (id)client { + return getIvar(self, @"_client"); +} + %end %hook SBMainSwitcherViewController