iosipadipadosuiscenedelegate

How can I choose which scene gets restored on iPadOS when all have been dismissed?


I have an iPad app in which I'm starting to support multiple windows / scenes. I have one main window type, let's say MainScene, and at least one secondary window type for opening specific types of content, say DetailScene.

I have not declared my scene types in Info.plist. I have implemented application:configurationForConnectingSceneSession:options: like this:

-(UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options
{
  NSUserActivity *activity = options.userActivities.anyObject;
  NSString *activityType = activity.activityType;
  if ([activityType isEqualToString:@"detailType"])
    return [DetailSceneDelegate makeSceneConfiguration];

  return [MainSceneDelegate makeSceneConfiguration];
}

Say I perform these steps:

  1. Launch app for the first time. I get a call to configurationForConnectingSceneSession, and the activity type is nil so it returns a MainScene.
  2. Open a new window for some piece of content. That uses the detail scene activity type, so configurationForConnectingSceneSession returns a DetailScene. Creating the new scene looks like this:
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"detailType"];
activity.userInfo = @{@"content_id": @(contentRowId)};
[[UIApplication sharedApplication] requestSceneSessionActivation:nil userActivity:activity options:nil errorHandler:nil];
  1. Suspend the app and open the app switcher. Discard (by flicking up) first the main window and then the detail window. The app is now killed.
  2. Relaunch the app.

At this point I do not get a call to configurationForConnectingSceneSession. I get the detail scene back, restored from its user activity, with calls straight to DetailSceneDelegate.

My question: how do I control what scene gets restored in this situation? I want my main scene to come back.

Messages and Mail and Notes all do this. If you open Messages and drag a conversation out into a new window, you get a window for that conversation with a Done button in the corner that will dismiss the window. If you perform my steps above with Messages, you will relaunch to the full Messages view. Are they converting the detail view to a main view on the fly? Or is there a way to tell the system that the detail scene is secondary and should not be restored first, or that I should get asked what I want to restore via configurationForConnectingSceneSession? Or something else?


Solution

  • I cross-posted this to the Apple Developer forums and got an answer from a Framework Engineer. The answer is UISceneActivationConditions, set as a property on UIScene. Set the canActivateForTargetContentIdentifierPredicate to always return NO:

    scene.activationConditions.canActivateForTargetContentIdentifierPredicate = [NSPredicate predicateWithValue:NO];
    

    I do this in my implementation of scene:willConnectToSession:options: in my UIWindowSceneDelegate implementation.

    As of current writing, on Xcode 13.2 and iOS 15.2 simulator, it works if the second launch (step 4 above) is via tapping the app icon, but not when it's via building and running in Xcode. I may file a feedback on this.