Restoring NSUserActivity

194 Views Asked by At

I am working with MacCatalyst and I would like to restore the previous content of windows after reopening the app. I found an example project (https://developer.apple.com/documentation/uikit/uiscenedelegate/restoring_your_app_s_state). I adopted the stateRestorationActivity(for scene: UIScene) method, however, according to the example project, when I want to configure a scene in the scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) method based on the session.stateRestorationActivity, the variable is always nil. Here's my code:

In SceneDelegate:

func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? {
    return scene.userActivity
}



func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    
    guard let windowScene = (scene as? UIWindowScene) else { return }
            
    #if targetEnvironment(macCatalyst)
    if let titlebar = windowScene.titlebar {
        titlebar.titleVisibility = .hidden
        titlebar.toolbarStyle = .unified
    }
    #endif
    
    window = UIWindow(frame: windowScene.coordinateSpace.bounds)
    window?.windowScene = windowScene

    let contentViewController = ContentViewController()
            
    window?.rootViewController = UINavigationController(rootViewController: contentViewController)
    window?.makeKeyAndVisible()
    
    if let userActivity = connectionOptions.userActivities.first ?? session.stateRestorationActivity {
        if !configure(window: window, with: userActivity) {
            print("Failed to restore from \(userActivity)")
        }
    } else {
        if !configure(window: window, with: ContentType.Inbox.openDetailUserActivity) {
            
        }
    }
            
}

In AppDelegate:

func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool {
    return true
}

func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
    return true
}


// MARK: - UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
    
    var configurationName: String!
    
    switch options.userActivities.first?.activityType {
    case .UserActivity.SystemActivityType, .UserActivity.TagActivityType, .UserActivity.ProjectActivityType:
        configurationName = "Detail Configuration"
    default:
        configurationName = "Default Configuration"
    }
    
    return UISceneConfiguration(name: configurationName, sessionRole: connectingSceneSession.role)

}

I registred different configurations of UISceneSessions in the info plist.

1

There are 1 best solutions below

0
C. Bess On

Looks like you need to assign a NSUserActivity to the correct UIWindowScene property with your view controller's viewWillAppear method, then in the viewWillDisappear assign nil to that property.

Make sure to assign it to the UIViewController that is the rootViewController for the UIWindow being shown. Meaning, if you have a UINavigationController as the parent, use navigationController?.view.window?.windowScene?.userActivity.

A code example is available, not mine, but a helpful one.

It seems like the state restoration subsystem takes the user activity from any view controllers of active scenes and stores the state from it, which makes sense.

Also, make sure to store your information in NSUserActivity.userInfo.

More details available on my blog as well.