File: Platform\iOS\MauiUISceneDelegate.cs
Web Access
Project: src\src\Core\src\Core.csproj (Microsoft.Maui)
using System;
using Foundation;
using Microsoft.Maui.LifecycleEvents;
using Microsoft.Maui.Platform;
using ObjCRuntime;
using UIKit;
 
namespace Microsoft.Maui
{
	[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
	[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
	public class MauiUISceneDelegate : UIResponder, IUIWindowSceneDelegate
	{
		[Export("window")]
		public virtual UIWindow? Window { get; set; }
 
		[Export("scene:willConnectToSession:options:")]
		public virtual void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
		{
			IPlatformApplication.Current?.Services?.InvokeLifecycleEvents<iOSLifecycle.SceneWillConnect>(del => del(scene, session, connectionOptions));
 
			if (session.Configuration.Name == MauiUIApplicationDelegate.MauiSceneConfigurationKey && IPlatformApplication.Current?.Application != null)
			{
				this.CreatePlatformWindow(IPlatformApplication.Current.Application, scene, session, connectionOptions);
 
				if (Window != null)
					GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.OnPlatformWindowCreated>(del => del(Window));
			}
		}
 
		[Export("sceneDidDisconnect:")]
		public virtual void DidDisconnect(UIScene scene)
		{
			IPlatformApplication.Current?.Services?.InvokeLifecycleEvents<iOSLifecycle.SceneDidDisconnect>(del => del(scene));
 
			// for iOS 13 only where active apperance is not supported yet
			// for iOS 14+, see DidUpdateCoordinateSpace
			if (!OperatingSystem.IsMacCatalystVersionAtLeast(14))
			{
				if (Window is not null && Window.IsKeyWindow)
				{
					// manually resign the key window and rebuild the menu
					Window.ResignKeyWindow();
					UIMenuSystem
						.MainSystem
						.SetNeedsRebuild();
				}
			}
		}
 
		[Export("stateRestorationActivityForScene:")]
		public virtual NSUserActivity? GetStateRestorationActivity(UIScene scene)
		{
			var window = Window.GetWindow();
			if (window is null)
				return null;
 
			var persistedState = new PersistedState();
 
			window.Backgrounding(persistedState);
 
			// the user saved nothing, so there is nothing to restore
			if (persistedState.Count == 0)
				return null;
 
			return persistedState.ToUserActivity(window.GetType().FullName!);
		}
 
		IServiceProvider? GetServiceProvider() =>
			Window?.GetWindow()?.Handler?.GetServiceProvider();
 
		[Export("sceneWillEnterForeground:")]
		public virtual void WillEnterForeground(UIScene scene) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneWillEnterForeground>(del => del(scene));
 
		[Export("sceneDidBecomeActive:")]
		public virtual void OnActivated(UIScene scene) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneOnActivated>(del => del(scene));
 
		[Export("sceneWillResignActive:")]
		public virtual void OnResignActivation(UIScene scene) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneOnResignActivation>(del => del(scene));
 
		[Export("sceneDidEnterBackground:")]
		public virtual void DidEnterBackground(UIScene scene) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneDidEnterBackground>(del => del(scene));
 
		[Export("scene:openURLContexts:")]
		public virtual bool OpenUrl(UIScene scene, NSSet<UIOpenUrlContext> urlContexts)
		{
			var wasHandled = false;
 
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneOpenUrl>(del =>
			{
				wasHandled = del(scene, urlContexts) || wasHandled;
			});
 
			return wasHandled;
		}
 
		[Export("scene:continueUserActivity:")]
		public virtual bool ContinueUserActivity(UIScene scene, NSUserActivity userActivity)
		{
			var wasHandled = false;
 
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneContinueUserActivity>(del =>
			{
				wasHandled = del(scene, userActivity) || wasHandled;
			});
 
			return wasHandled;
		}
 
		[Export("scene:willContinueUserActivityWithType:")]
		public virtual void WillContinueUserActivity(UIScene scene, string userActivityType) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneWillContinueUserActivity>(del => del(scene, userActivityType));
 
		[Export("scene:didFailToContinueUserActivityWithType:error:")]
		public virtual void DidFailToContinueUserActivity(UIScene scene, string userActivityType, NSError error) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneDidFailToContinueUserActivity>(del => del(scene, userActivityType, error));
 
		[Export("scene:didUpdateUserActivity:")]
		public virtual void DidUpdateUserActivity(UIScene scene, NSUserActivity userActivity) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneDidUpdateUserActivity>(del => del(scene, userActivity));
 
		[Export("scene:restoreInteractionStateWithUserActivity:")]
		[System.Runtime.Versioning.SupportedOSPlatform("ios15.0")]
		[System.Runtime.Versioning.SupportedOSPlatform("tvos15.0")]
		[System.Runtime.Versioning.SupportedOSPlatform("maccatalyst15.0")]
		public virtual void RestoreInteractionState(UIScene scene, NSUserActivity stateRestorationActivity) =>
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.SceneRestoreInteractionState>(del => del(scene, stateRestorationActivity));
 
		[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
		[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
		[System.Runtime.Versioning.SupportedOSPlatform("maccatalyst13.0")]
		[Export("windowScene:didUpdateCoordinateSpace:interfaceOrientation:traitCollection:")]
		public virtual void DidUpdateCoordinateSpace(UIWindowScene windowScene, IUICoordinateSpace previousCoordinateSpace, UIInterfaceOrientation previousInterfaceOrientation, UITraitCollection previousTraitCollection)
		{
			GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.WindowSceneDidUpdateCoordinateSpace>(del => del(windowScene, previousCoordinateSpace, previousInterfaceOrientation, previousTraitCollection));
 
			if (OperatingSystem.IsIOSVersionAtLeast(14))
			{
				// for iOS 14+ where active apperance is supported
				var newActiveAppearance = windowScene.TraitCollection.ActiveAppearance;
				if (newActiveAppearance != previousTraitCollection.ActiveAppearance &&
					newActiveAppearance == UIUserInterfaceActiveAppearance.Active)
				{
					// if window went from inactive to active (become focused), rebuild the menu
					UIMenuSystem
						.MainSystem
						.SetNeedsRebuild();
				}
			}
		}
	}
}