Skip to content

[UIScene] Migrate state restoration for scenes #174402

Closed

Description

@vashworth

Problem

After migrating to UIScene, state restoration no longer works the same as before.

Previously state restoration was ViewController-based. FlutterViewController methods encodeRestorableStateWithCoder and decodeRestorableStateWithCoder were used to save and restore state. application:shouldRestoreSecureApplicationState: in the FlutterAppDelegate also determined whether or not restoration should be allowed.

After migrating to UIScene, these methods are no longer called by UIKit. This does not appear to be documented anywhere.

Instead, state must be restored through the SceneDelegate.

Prerequisites

Proposal

In the FlutterSceneDelegate, there are two functions we can utilize for scene restoration:

Flutter uses a plugin called the restorationPlugin to send the restoration data to and from the framework. restorationPlugin is a property of the FlutterEngine. To access this plugin, the UIScene needs access to the FlutterEngine.

In addition, you need a way to associate a UIScene with a particular FlutterViewController/FlutterEngine when restoring. To do that, we can use the FlutterViewController’s restorationId, which persists across launches.

Lastly, we’ll need to store the last modified date of the app bundle to determine when and when not to restore the state (replacing application:shouldRestoreSecureApplicationState:).

- (NSUserActivity*)stateRestorationActivityForScene:(UIScene*)scene {
 // Saves activity to the state
 NSUserActivity* activity = scene.userActivity;
 if (!activity) {
   activity = [[NSUserActivity alloc] initWithActivityType:scene.session.configuration.name];
 }

 for (FlutterEngine* engine in [_engines allObjects]) {
   if (!engine) {
     continue;
   }
   UIViewController* vc = (UIViewController*)engine.viewController;
   NSString* restorationId = vc.restorationIdentifier;
   if (restorationId && restorationId.length > 0) {
     NSData* restorationData = [engine.restorationPlugin restorationData];
     if (restorationData) {
       int64_t stateDate = [self lastAppModificationTime];
       [activity addUserInfoEntriesFromDictionary:@{restorationId : restorationData}];
       [activity addUserInfoEntriesFromDictionary:@{
         kRestorationStateAppModificationKey : [NSNumber numberWithLongLong:stateDate]
       }];
     }
   }
 }

 return activity;
}

- (void)scene:(UIScene*)scene
   restoreInteractionStateWithUserActivity:(NSUserActivity*)stateRestorationActivity {
 // Restores state from the activity
 NSDictionary<NSString*, id>* userInfo = stateRestorationActivity.userInfo;
 for (FlutterEngine* engine in [_engines allObjects]) {
   if (!engine) {
     continue;
   }
   UIViewController* vc = (UIViewController*)engine.viewController;
   NSString* restorationId = vc.restorationIdentifier;
   if (restorationId && restorationId.length > 0) {
     NSNumber* stateDateNumber = userInfo[kRestorationStateAppModificationKey];
     int64_t stateDate = 0;
     if (stateDateNumber && [stateDateNumber isKindOfClass:[NSNumber class]]) {
       stateDate = [stateDateNumber longLongValue];
     }
     if (self.lastAppModificationTime != stateDate) {
       // Don't restore state if the app has been re-installed since the state was last saved
       return;
     }
     NSData* restorationData = userInfo[restorationId];
     if ([restorationData isKindOfClass:[NSData class]]) {
       [engine.restorationPlugin setRestorationData:restorationData];
     }
   }
 }
}

See prototype.

Activity

  1. added
    platform-iosiOS applications specifically
    P2Important issues not at the top of the work list
    team-iosOwned by iOS platform team
    triaged-iosTriaged by iOS platform team
    on Aug 25, 2025
  2. added a commit that references this issue on Aug 30, 2025
  3. github-actions commented on Oct 17, 2025

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  4. locked as resolved and limited conversation to collaborators on Oct 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work listplatform-iosiOS applications specificallyteam-iosOwned by iOS platform teamtriaged-iosTriaged by iOS platform team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions