Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wire up scene life cycle events #9525

Merged
merged 2 commits into from
Aug 19, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,40 +12,71 @@ internal static MauiAppBuilder ConfigureCrossPlatformLifecycleEvents(this MauiAp

static void OnConfigureLifeCycle(IiOSLifecycleBuilder iOS)
{
iOS
.FinishedLaunching((app, launchOptions) =>
{
app.GetWindow()?.Created();
return true;
})
.WillEnterForeground(app =>
{
app.GetWindow()?.Resumed();
})
.OnActivated(app =>
{
app.GetWindow()?.Activated();
})
.OnResignActivation(app =>
{
app.GetWindow()?.Deactivated();
})
.DidEnterBackground(app =>
{
app.GetWindow()?.Stopped();
})
.WillTerminate(app =>
{
// By this point if we were a multi window app, the GetWindow would be null anyway
app.GetWindow()?.Destroying();
})
.SceneDidDisconnect(scene =>
{
if (scene is UIWindowScene windowScene)
{
windowScene.GetWindow()?.Destroying();
}
});
iOS = iOS
.OnPlatformWindowCreated((window) =>
{
window.GetWindow()?.Created();
})
.WillTerminate(app =>
{
// By this point if we were a multi window app, the GetWindow would be null anyway
app.GetWindow()?.Destroying();
})
.WillEnterForeground(app =>
{
if (!app.Delegate.HasSceneManifest())
app.GetWindow()?.Resumed();
})
.OnActivated(app =>
{
if (!app.Delegate.HasSceneManifest())
app.GetWindow()?.Activated();
})
.OnResignActivation(app =>
{
if (!app.Delegate.HasSceneManifest())
app.GetWindow()?.Deactivated();
})
.DidEnterBackground(app =>
{
if (!app.Delegate.HasSceneManifest())
app.GetWindow()?.Stopped();
});

// Scenes
if (!OperatingSystem.IsIOSVersionAtLeast(13))
{
// Pre iOS 13 doesn't support scenes
}
else
{
iOS
.SceneWillEnterForeground(scene =>
{
if (scene is UIWindowScene windowScene)
windowScene.GetWindow()?.Resumed();
})
.SceneOnActivated(scene =>
{
if (scene is UIWindowScene windowScene)
windowScene.GetWindow()?.Activated();
})
.SceneOnResignActivation(scene =>
{
if (scene is UIWindowScene windowScene)
windowScene.GetWindow()?.Deactivated();
})
.SceneDidEnterBackground(scene =>
{
if (scene is UIWindowScene windowScene)
windowScene.GetWindow()?.Stopped();
})
.SceneDidDisconnect(scene =>
{
if (scene is UIWindowScene windowScene)
windowScene.GetWindow()?.Destroying();
});
}
}
}
}
12 changes: 12 additions & 0 deletions src/Core/src/LifecycleEvents/iOS/iOSLifecycle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,20 @@ public static class iOSLifecycle
// Scene
public delegate void SceneWillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions);
public delegate void SceneDidDisconnect(UIScene scene);
public delegate void SceneWillEnterForeground(UIScene scene);
public delegate void SceneOnActivated(UIScene scene);
public delegate void SceneOnResignActivation(UIScene scene);
public delegate void SceneDidEnterBackground(UIScene scene);
public delegate bool SceneOpenUrl(UIScene scene, NSSet<UIOpenUrlContext> urlContexts);
public delegate bool SceneContinueUserActivity(UIScene scene, NSUserActivity userActivity);
public delegate void SceneWillContinueUserActivity(UIScene scene, string userActivityType);
public delegate void SceneDidFailToContinueUserActivity(UIScene scene, string userActivityType, NSError error);
public delegate void SceneDidUpdateUserActivity(UIScene scene, NSUserActivity userActivity);
public delegate void SceneRestoreInteractionState(UIScene scene, NSUserActivity stateRestorationActivity);


// Internal events
internal delegate void OnMauiContextCreated(IMauiContext mauiContext);
internal delegate void OnPlatformWindowCreated(UIWindow window);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
namespace Microsoft.Maui.LifecycleEvents
using Foundation;
using UIKit;

namespace Microsoft.Maui.LifecycleEvents
{
public static class iOSLifecycleBuilderExtensions
{
Expand All @@ -14,9 +17,60 @@ public static class iOSLifecycleBuilderExtensions
public static IiOSLifecycleBuilder WillTerminate(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.WillTerminate del) => lifecycle.OnEvent(del);
public static IiOSLifecycleBuilder ApplicationSignificantTimeChange(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.ApplicationSignificantTimeChange del) => lifecycle.OnEvent(del);


[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneWillConnect(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneWillConnect del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneDidDisconnect(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneDidDisconnect del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneOnActivated(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneOnActivated del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneOnResignActivation(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneOnResignActivation del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneWillEnterForeground(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneWillEnterForeground del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneDidEnterBackground(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneDidEnterBackground del) => lifecycle.OnEvent(del);


[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneOpenUrl(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneOpenUrl del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneContinueUserActivity(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneContinueUserActivity del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneWillContinueUserActivity(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneWillContinueUserActivity del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneDidFailToContinueUserActivity(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneDidFailToContinueUserActivity del) => lifecycle.OnEvent(del);

[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public static IiOSLifecycleBuilder SceneDidUpdateUserActivity(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneDidUpdateUserActivity del) => lifecycle.OnEvent(del);


[System.Runtime.Versioning.SupportedOSPlatform("ios15.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos15.0")]
[System.Runtime.Versioning.SupportedOSPlatform("maccatalyst15.0")]
public static IiOSLifecycleBuilder SceneRestoreInteractionState(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.SceneWillConnect del) => lifecycle.OnEvent(del);


internal static IiOSLifecycleBuilder OnMauiContextCreated(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.OnMauiContextCreated del) => lifecycle.OnEvent(del);
internal static IiOSLifecycleBuilder OnPlatformWindowCreated(this IiOSLifecycleBuilder lifecycle, iOSLifecycle.OnPlatformWindowCreated del) => lifecycle.OnEvent(del);
}
}
5 changes: 5 additions & 0 deletions src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@ public virtual bool FinishedLaunching(UIApplication application, NSDictionary la

// if there is no scene delegate or support for scene delegates, then we set up the window here
if (!this.HasSceneManifest())
{
this.CreatePlatformWindow(Application, application, launchOptions);

if (Window != null)
Services?.InvokeLifecycleEvents<iOSLifecycle.OnPlatformWindowCreated>(del => del(Window));
}

Services?.InvokeLifecycleEvents<iOSLifecycle.FinishedLaunching>(del => del(application!, launchOptions!));

Expand Down
75 changes: 72 additions & 3 deletions src/Core/src/Platform/iOS/MauiUISceneDelegate.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
using Foundation;
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:")]
[System.Runtime.Versioning.SupportedOSPlatform("ios13.0")]
[System.Runtime.Versioning.SupportedOSPlatform("tvos13.0")]
public virtual void WillConnect(UIScene scene, UISceneSession session, UISceneConnectionOptions connectionOptions)
{
MauiUIApplicationDelegate.Current?.Services?.InvokeLifecycleEvents<iOSLifecycle.SceneWillConnect>(del => del(scene, session, connectionOptions));

if (session.Configuration.Name == MauiUIApplicationDelegate.MauiSceneConfigurationKey && MauiUIApplicationDelegate.Current?.Application != null)
{
this.CreatePlatformWindow(MauiUIApplicationDelegate.Current.Application, scene, session, connectionOptions);

if (Window != null)
GetServiceProvider()?.InvokeLifecycleEvents<iOSLifecycle.OnPlatformWindowCreated>(del => del(Window));
}
}

Expand All @@ -47,5 +51,70 @@ public virtual void DidDisconnect(UIScene scene)

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.SceneDidEnterBackground>(del => del(scene));

[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));
}
}
5 changes: 5 additions & 0 deletions src/Core/src/Platform/iOS/UIApplicationExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@ internal static UIEdgeInsets GetSafeAreaInsetsForWindow(this UIApplication appli
}
#pragma warning restore CA1416

if (!OperatingSystem.IsIOSVersionAtLeast(13))
return null;
else if (windowScene.Delegate is MauiUISceneDelegate sd)
PureWeen marked this conversation as resolved.
Show resolved Hide resolved
return sd.Window?.GetWindow();

return null;
}
}
Expand Down
Loading