diff --git a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets
index e111d6aebaf1..4645d6f2d739 100644
--- a/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets
+++ b/.nuspec/Microsoft.Maui.Controls.MultiTargeting.targets
@@ -32,10 +32,10 @@
-
-
-
-
+
+
+
+
diff --git a/src/Controls/samples/Controls.Sample/Controls.Sample.csproj b/src/Controls/samples/Controls.Sample/Controls.Sample.csproj
index 583d58757b58..a64a797d9017 100644
--- a/src/Controls/samples/Controls.Sample/Controls.Sample.csproj
+++ b/src/Controls/samples/Controls.Sample/Controls.Sample.csproj
@@ -30,4 +30,6 @@
+
+
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Services/Android/CustomAndroidLifecycleHandler.cs b/src/Controls/samples/Controls.Sample/Services/Android/CustomAndroidLifecycleHandler.cs
new file mode 100644
index 000000000000..e0b1621489ab
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Services/Android/CustomAndroidLifecycleHandler.cs
@@ -0,0 +1,41 @@
+using System.Runtime.CompilerServices;
+using Android.App;
+using Android.Content;
+using Android.Content.Res;
+using Android.OS;
+using Microsoft.Maui;
+
+namespace Maui.Controls.Sample.Services
+{
+ public class CustomAndroidLifecycleHandler : AndroidApplicationLifetime
+ {
+ public override void OnCreate(Activity activity, Bundle savedInstanceState) => LogMember();
+
+ public override void OnPostCreate(Activity activity, Bundle savedInstanceState) => LogMember();
+
+ public override void OnDestroy(Activity activity) => LogMember();
+
+ public override void OnPause(Activity activity) => LogMember();
+
+ public override void OnResume(Activity activity) => LogMember();
+
+ public override void OnPostResume(Activity activity) => LogMember();
+
+ public override void OnStart(Activity activity) => LogMember();
+
+ public override void OnStop(Activity activity) => LogMember();
+
+ public override void OnRestart(Activity activity) => LogMember();
+
+ public override void OnSaveInstanceState(Activity activity, Bundle outState) => LogMember();
+
+ public override void OnRestoreInstanceState(Activity activity, Bundle savedInstanceState) => LogMember();
+
+ public override void OnConfigurationChanged(Activity activity, Configuration newConfig) => LogMember();
+
+ public override void OnActivityResult(Activity activity, int requestCode, Result resultCode, Intent data) => LogMember();
+
+ static void LogMember([CallerMemberName] string name = "") =>
+ System.Diagnostics.Debug.WriteLine("LIFECYCLE: " + name);
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Services/iOS/CustomIosLifecycleHandler.cs b/src/Controls/samples/Controls.Sample/Services/iOS/CustomIosLifecycleHandler.cs
new file mode 100644
index 000000000000..ce7bd09d65d8
--- /dev/null
+++ b/src/Controls/samples/Controls.Sample/Services/iOS/CustomIosLifecycleHandler.cs
@@ -0,0 +1,31 @@
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+using Foundation;
+using Microsoft.Maui;
+using UIKit;
+
+namespace Maui.Controls.Sample
+{
+ public class CustomIosLifecycleHandler : IosApplicationLifetime
+ {
+ public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
+ {
+ LogMember();
+
+ return true;
+ }
+
+ public override void OnActivated(UIApplication application) => LogMember();
+
+ public override void OnResignActivation(UIApplication application) => LogMember();
+
+ public override void WillTerminate(UIApplication application) => LogMember();
+
+ public override void DidEnterBackground(UIApplication application) => LogMember();
+
+ public override void WillEnterForeground(UIApplication application) => LogMember();
+
+ static void LogMember([CallerMemberName] string name = "") =>
+ Debug.WriteLine("LIFECYCLE: " + name);
+ }
+}
\ No newline at end of file
diff --git a/src/Controls/samples/Controls.Sample/Startup.cs b/src/Controls/samples/Controls.Sample/Startup.cs
index 86789ef23bac..104df7e7da7e 100644
--- a/src/Controls/samples/Controls.Sample/Startup.cs
+++ b/src/Controls/samples/Controls.Sample/Startup.cs
@@ -43,8 +43,8 @@ public void Configure(IAppHostBuilder appBuilder)
{"Logging:LogLevel:Default", "Warning"}
});
})
- .UseMauiServiceProviderFactory(true)
- //.UseServiceProviderFactory(new DIExtensionsServiceProviderFactory())
+ //.UseMauiServiceProviderFactory(true)
+ .UseServiceProviderFactory(new DIExtensionsServiceProviderFactory())
.ConfigureServices((hostingContext, services) =>
{
services.AddSingleton();
@@ -56,6 +56,12 @@ public void Configure(IAppHostBuilder appBuilder)
services.AddTransient();
services.AddTransient();
+
+#if __ANDROID__
+ services.AddTransient();
+#elif __IOS__
+ services.AddTransient();
+#endif
})
.ConfigureFonts((hostingContext, fonts) =>
{
@@ -63,7 +69,7 @@ public void Configure(IAppHostBuilder appBuilder)
});
}
- // To use DI ServiceCollection and not the MAUI one
+ // To use the Microsoft.Extensions.DependencyInjection ServiceCollection and not the MAUI one
public class DIExtensionsServiceProviderFactory : IServiceProviderFactory
{
public ServiceCollection CreateBuilder(IServiceCollection services)
diff --git a/src/Core/src/Platform/Android/AndroidApplicationLifetime.cs b/src/Core/src/Platform/Android/AndroidApplicationLifetime.cs
new file mode 100644
index 000000000000..4061e64809db
--- /dev/null
+++ b/src/Core/src/Platform/Android/AndroidApplicationLifetime.cs
@@ -0,0 +1,81 @@
+using Android.App;
+using Android.Content;
+using Android.Content.Res;
+using Android.OS;
+using Android.Runtime;
+
+namespace Microsoft.Maui
+{
+ public class AndroidApplicationLifetime : IAndroidApplicationLifetime
+ {
+ public virtual void OnCreate(Activity activity, Bundle? savedInstanceState)
+ {
+
+ }
+
+ public virtual void OnPostCreate(Activity activity, Bundle? savedInstanceState)
+ {
+
+ }
+
+ public virtual void OnDestroy(Activity activity)
+ {
+
+ }
+
+ public virtual void OnPause(Activity activity)
+ {
+
+ }
+
+ public virtual void OnResume(Activity activity)
+ {
+
+ }
+
+ public virtual void OnPostResume(Activity activity)
+ {
+
+ }
+
+ public virtual void OnStart(Activity activity)
+ {
+
+ }
+
+ public virtual void OnStop(Activity activity)
+ {
+
+ }
+
+ public virtual void OnRestart(Activity activity)
+ {
+
+ }
+
+ public virtual void OnSaveInstanceState(Activity activity, Bundle outState)
+ {
+
+ }
+
+ public virtual void OnRestoreInstanceState(Activity activity, Bundle savedInstanceState)
+ {
+
+ }
+
+ public virtual void OnConfigurationChanged(Activity activity, Configuration newConfig)
+ {
+
+ }
+
+ public virtual void OnActivityResult(Activity activity, int requestCode, [GeneratedEnum] Result resultCode, Intent? data)
+ {
+
+ }
+
+ public virtual void OnBackPressed(Activity activity)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/Android/IAndroidApplicationLifetime.cs b/src/Core/src/Platform/Android/IAndroidApplicationLifetime.cs
new file mode 100644
index 000000000000..56f282c00ad0
--- /dev/null
+++ b/src/Core/src/Platform/Android/IAndroidApplicationLifetime.cs
@@ -0,0 +1,111 @@
+using Android.App;
+using Android.Content;
+using Android.Content.Res;
+using Android.OS;
+using Android.Runtime;
+
+namespace Microsoft.Maui
+{
+ ///
+ /// Allow to get Android Activity lifecycle callbacks.
+ ///
+ public interface IAndroidApplicationLifetime : IPlatformApplicationLifetime
+ {
+ ///
+ /// Called when the activity is starting.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// Previous state saved.
+ void OnCreate(Activity activity, Bundle? savedInstanceState);
+
+ ///
+ /// Called when activity start-up is complete (after OnStart() and OnRestoreInstanceState(Bundle) have been called).
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// Previous state saved.
+ void OnPostCreate(Activity activity, Bundle? savedInstanceState);
+
+ ///
+ /// Called when the activity had been stopped, but is now again being displayed to the user.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnStart(Activity activity);
+
+ ///
+ /// Called for your activity to start interacting with the user.
+ /// This is an indicator that the activity became active and ready to receive input.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnResume(Activity activity);
+
+ ///
+ /// Called when activity resume is complete (after OnResume() has been called).
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnPostResume(Activity activity);
+
+ ///
+ /// Called as part of the activity lifecycle when the user no longer actively interacts with the activity,
+ /// but it is still visible on screen.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnPause(Activity activity);
+
+ ///
+ /// Called when you are no longer visible to the user.
+ ///
+ /// The activity on which we receive lifecycle events callbacks
+ void OnStop(Activity activity);
+
+ ///
+ /// Called after OnStop when the current activity is being re-displayed to the user (the user has navigated back to it).
+ ///
+ /// The activity on which we receive lifecycle events callbacks
+ void OnRestart(Activity activity);
+
+ ///
+ /// This can happen either because the activity is finishing, or because the system is
+ /// temporarily destroying this instance of the activity to save space.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnDestroy(Activity activity);
+
+ ///
+ /// Called to retrieve per-instance state from an activity before being killed so that the state can be
+ /// restored in OnCreate or OnRestoreInstanceState.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// Bundle in which to place your saved state.
+ void OnSaveInstanceState(Activity activity, Bundle outState);
+
+ ///
+ /// Restore the state of the dialog from a previously saved bundle.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// The state of the dialog previously saved.
+ void OnRestoreInstanceState(Activity activity, Bundle savedInstanceState);
+
+ ///
+ /// Called when the current configuration of the resources being used by the application have changed.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// The new resource configuration.
+ void OnConfigurationChanged(Activity activity, Configuration newConfig);
+
+ ///
+ /// Called when an activity you launched exits, giving you the requestCode you started it with,
+ /// the resultCode it returned, and any additional data from it.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ /// The integer request code originally supplied to startActivityForResult(), allowing you to identify who this result came from.
+ /// The integer result code returned by the child activity.
+ /// An Intent, which can return result data to the caller.
+ void OnActivityResult(Activity activity, int requestCode, [GeneratedEnum] Result resultCode, Intent? data);
+
+ ///
+ /// Called when the activity has detected the user's press of the back key.
+ ///
+ /// The activity on which we receive lifecycle events callbacks.
+ void OnBackPressed(Activity activity);
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs
index 93fde4f05d5d..74859ccf1b0d 100644
--- a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs
+++ b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs
@@ -1,10 +1,16 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
+using Android.Content;
+using Android.Content.Res;
using Android.OS;
+using Android.Runtime;
using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.AppCompat.Widget;
using AndroidX.CoordinatorLayout.Widget;
using Google.Android.Material.AppBar;
+using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Maui
{
@@ -32,11 +38,102 @@ protected override void OnCreate(Bundle? savedInstanceState)
CoordinatorLayout parent = new CoordinatorLayout(this);
- SetContentView(parent, new ViewGroup.LayoutParams(CoordinatorLayout.LayoutParams.MatchParent, CoordinatorLayout.LayoutParams.MatchParent));
+ SetContentView(parent, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
//AddToolbar(parent);
- parent.AddView(content.ToNative(window.MauiContext), new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MatchParent, CoordinatorLayout.LayoutParams.MatchParent));
+ parent.AddView(content.ToNative(window.MauiContext), new CoordinatorLayout.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.MatchParent));
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnCreate(this, savedInstanceState);
+ }
+
+ protected override void OnPostCreate(Bundle? savedInstanceState)
+ {
+ base.OnPostCreate(savedInstanceState);
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnPostCreate(this, savedInstanceState);
+ }
+
+ protected override void OnStart()
+ {
+ base.OnStart();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnStart(this);
+ }
+
+ protected override void OnPause()
+ {
+ base.OnPause();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnPause(this);
+ }
+
+ protected override void OnResume()
+ {
+ base.OnResume();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnResume(this);
+ }
+
+ protected override void OnPostResume()
+ {
+ base.OnPostResume();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnPostResume(this);
+ }
+
+ protected override void OnRestart()
+ {
+ base.OnRestart();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnRestart(this);
+ }
+
+ protected override void OnDestroy()
+ {
+ base.OnDestroy();
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnDestroy(this);
+ }
+
+ protected override void OnSaveInstanceState(Bundle outState)
+ {
+ base.OnSaveInstanceState(outState);
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnSaveInstanceState(this, outState);
+ }
+
+ protected override void OnRestoreInstanceState(Bundle savedInstanceState)
+ {
+ base.OnRestoreInstanceState(savedInstanceState);
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnRestoreInstanceState(this, savedInstanceState);
+ }
+
+ public override void OnConfigurationChanged(Configuration newConfig)
+ {
+ base.OnConfigurationChanged(newConfig);
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnConfigurationChanged(this, newConfig);
+ }
+
+ protected override void OnActivityResult(int requestCode, [GeneratedEnum] Android.App.Result resultCode, Intent? data)
+ {
+ base.OnActivityResult(requestCode, resultCode, data);
+
+ foreach (var androidApplicationLifetime in GetAndroidApplicationLifetime())
+ androidApplicationLifetime.OnActivityResult(this, requestCode, resultCode, data);
}
void AddToolbar(ViewGroup parent)
@@ -44,9 +141,12 @@ void AddToolbar(ViewGroup parent)
Toolbar toolbar = new Toolbar(this);
var appbarLayout = new AppBarLayout(this);
- appbarLayout.AddView(toolbar, new ViewGroup.LayoutParams(AppBarLayout.LayoutParams.MatchParent, global::Android.Resource.Attribute.ActionBarSize));
+ appbarLayout.AddView(toolbar, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, Android.Resource.Attribute.ActionBarSize));
SetSupportActionBar(toolbar);
parent.AddView(appbarLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MatchParent, ViewGroup.LayoutParams.WrapContent));
}
+
+ IEnumerable GetAndroidApplicationLifetime() =>
+ MauiApplication.Current?.Services?.GetServices() ?? Enumerable.Empty();
}
}
diff --git a/src/Core/src/Platform/Android/MauiApplication.cs b/src/Core/src/Platform/Android/MauiApplication.cs
index 2283a529f5f4..7f2a0ea540f2 100644
--- a/src/Core/src/Platform/Android/MauiApplication.cs
+++ b/src/Core/src/Platform/Android/MauiApplication.cs
@@ -32,6 +32,7 @@ public override void OnCreate()
// Configure native services like HandlersContext, ImageSourceHandlers etc..
void ConfigureNativeServices(HostBuilderContext ctx, IServiceCollection services)
{
+ services.AddTransient();
}
}
diff --git a/src/Core/src/Platform/IPlatformApplicationLifetime.cs b/src/Core/src/Platform/IPlatformApplicationLifetime.cs
new file mode 100644
index 000000000000..e9b0ea58c748
--- /dev/null
+++ b/src/Core/src/Platform/IPlatformApplicationLifetime.cs
@@ -0,0 +1,10 @@
+namespace Microsoft.Maui
+{
+ ///
+ /// Allow to get specific lifecycle events for each platform.
+ ///
+ public interface IPlatformApplicationLifetime
+ {
+
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/iOS/IIosApplicationLifetime.cs b/src/Core/src/Platform/iOS/IIosApplicationLifetime.cs
new file mode 100644
index 000000000000..2e04da555a25
--- /dev/null
+++ b/src/Core/src/Platform/iOS/IIosApplicationLifetime.cs
@@ -0,0 +1,49 @@
+using Foundation;
+using UIKit;
+
+namespace Microsoft.Maui
+{
+ ///
+ /// Allow to get iOS UIApplication lifecycle callbacks.
+ ///
+ public interface IIosApplicationLifetime : IPlatformApplicationLifetime
+ {
+ ///
+ /// Method invoked after the application has launched to configure the main window and view controller.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ /// An NSDictionary with the launch options, can be null.
+ /// Boolean
+ bool FinishedLaunching(UIApplication application, NSDictionary launchOptions);
+
+ ///
+ /// Called when the application is launched and every time the app returns to the foreground.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ void OnActivated(UIApplication application);
+
+ ///
+ /// The app is about to move from the active state to the inactive state.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ void OnResignActivation(UIApplication application);
+
+ ///
+ /// Called if the application is being terminated due to memory constraints or directly by the user.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ void WillTerminate(UIApplication application);
+
+ ///
+ /// Indicates that the application has entered the background.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ void DidEnterBackground(UIApplication application);
+
+ ///
+ /// Called prior to the application returning from a backgrounded state.
+ ///
+ /// Reference to the UIApplication that invoked this delegate method.
+ void WillEnterForeground(UIApplication application);
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/iOS/IosApplicationLifetime.cs b/src/Core/src/Platform/iOS/IosApplicationLifetime.cs
new file mode 100644
index 000000000000..5c3d3f669d61
--- /dev/null
+++ b/src/Core/src/Platform/iOS/IosApplicationLifetime.cs
@@ -0,0 +1,38 @@
+using Foundation;
+using UIKit;
+
+namespace Microsoft.Maui
+{
+ public class IosApplicationLifetime : IIosApplicationLifetime
+ {
+ public virtual bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
+ {
+ return true;
+ }
+
+ public virtual void OnActivated(UIApplication application)
+ {
+
+ }
+
+ public virtual void OnResignActivation(UIApplication application)
+ {
+
+ }
+
+ public virtual void WillTerminate(UIApplication application)
+ {
+
+ }
+
+ public virtual void DidEnterBackground(UIApplication application)
+ {
+
+ }
+
+ public virtual void WillEnterForeground(UIApplication application)
+ {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs
index 1ed2e8308227..defedae7be15 100644
--- a/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs
+++ b/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs
@@ -1,4 +1,6 @@
using System;
+using System.Collections.Generic;
+using System.Linq;
using Foundation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -41,12 +43,49 @@ public override bool FinishedLaunching(UIApplication application, NSDictionary l
Window.MakeKeyAndVisible();
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.FinishedLaunching(application, launchOptions);
+
return true;
}
+ public override void OnActivated(UIApplication application)
+ {
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.OnActivated(application);
+ }
+
+ public override void OnResignActivation(UIApplication application)
+ {
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.OnResignActivation(application);
+ }
+
+ public override void WillTerminate(UIApplication application)
+ {
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.WillTerminate(application);
+ }
+
+ public override void DidEnterBackground(UIApplication application)
+ {
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.DidEnterBackground(application);
+ }
+
+ public override void WillEnterForeground(UIApplication application)
+ {
+ foreach (var iOSApplicationDelegateHandler in GetIosApplicationLifetime())
+ iOSApplicationDelegateHandler.WillEnterForeground(application);
+ }
+
void ConfigureNativeServices(HostBuilderContext ctx, IServiceCollection services)
{
+ services.AddTransient();
}
+
+ IEnumerable GetIosApplicationLifetime() =>
+ Services?.GetServices() ?? Enumerable.Empty();
}
public abstract class MauiUIApplicationDelegate : UIApplicationDelegate, IUIApplicationDelegate