Open tranb3r opened 1 year ago
Hi @tranb3r. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md
This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Simply add this code to your ios app. Then create and send a POST Request to APNs (sandbox) in order to trigger a background update.
[Register("AppDelegate")]
internal class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
[Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
public void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Console.WriteLine("DidReceiveRemoteNotification");
}
}
What happens if you create an iOS app without MAUI (dotnet new ios
) and do the same thing?
What happens if you create an iOS app without MAUI (
dotnet new ios
) and do the same thing?
I don't know. How is this relevent, since the issue is about the maui app starting (instead of simply being created)? Assuming I succeed in running an iOS app without maui (which I have never done), what should I look for?
A MAUI iOS App is a .NET iOS app with additional tooling.
This is where CreateMauiApp
is called. willFinishLaunchingWithOptions
is, I'm assuming, called whenever you run that POST to start the background process. If that's the case, you can repro that (willFinishLaunchingWithOptions invoking, followed by didReceiveRemoteNotification) with a straight iOS app without MAUI. If that's true, then willFinishLaunchingWithOptions always invoke.
Going by this comment (https://github.com/dotnet/maui/commit/53a1d32d9114893a4a92dec727e6a2e22b6305e2) we've always called on the app startup within that method (The method names and the underlying code are different, but the idea is the same, the application starts within that method). The method parameters, at first glance, don't seem to differentiate how the application starts, just that it did.
That said, you could override WillFinishLaunching and handle that yourself.
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
[Export("application:didReceiveRemoteNotification:fetchCompletionHandler:")]
public void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
Console.WriteLine("DidReceiveRemoteNotification");
}
public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions)
{
// Add your code here.
// This will call the underlying MauiUIApplicationDelegate code, calling CreateMauiApp.
return base.WillFinishLaunching(application, launchOptions);
}
}
@drasticactions
I can override WillFinishLaunching
, but what for?
You've explained that CreateMauiApp
is called in WillFinishLaunching
, and this is totally fine.
However, why is OnStart
being called as well? This is happening after WillFinishLaunching
is done.
You mean this? https://github.com/dotnet/maui/blob/d0490abd10a9197aa2293a74da539dc28aea0ab7/src/Controls/src/Core/Application.cs#L316-L318
That gets called from https://github.com/dotnet/maui/blob/main/src/Core/src/Platform/iOS/MauiUIApplicationDelegate.cs#L52, when the Window (and by extension, the Application) is being created.
Because the application is being created and started, hence why Application.OnStart
would be called. WillFinishLaunching
is first, followed by FinishedLaunching
.
If you override WillFinishLaunching
, you can shortcircuit this by handling it and not calling CreateMauiApp
and, by extension, not create the Platform Window and create the MAUI Application at all.
Well, I do need to create the application. That's where all the DI stuff is initialized. I can't process the background update if there is no app. But I don't want the app to start. It does not make sense to start it, since the UI is actually not visible in this scenario.
So, I can override WillFinishLaunching, but how do I know that I'm currently processing a background update and not starting the app? Also, why is this behavior different from what is done on Android, where the app is created, but not started?
I am not an iOS lifecycle expert, but I believe the order of operations is:
In this case, you can override didReceiveRemoteNotification
to set some sort of state on the application. However, the same data passed in at the userInfo
is also present in willFinishLaunchingWithOptions
in the launchOptions
argument, but under the UIApplication.LaunchOptionsRemoteNotificationKey
key.
If you want the services all set up, then you can override WillFinishLaunching
and call base. I am not sure how you tell iOS that you don't want to launch the app, maybe returning false? I am not sure.
public override bool WillFinishLaunching(UIApplication application, NSDictionary launchOptions)
{
// This will call the underlying MauiUIApplicationDelegate code, calling CreateMauiApp.
base.WillFinishLaunching(application, launchOptions);
// Add your code here.
return false; // ? maybe this?
}
@mattleibow That is not correct. The order of operations is:
application:willFinishLaunchingWithOptions:
)application:didFinishLaunchingWithOptions:
)application:didReceiveRemoteNotification:fetchCompletionHandler:
)Any idea for fixing this issue?
Does the launch options not contain the notification information?
I saw in the docs that the data is present in willFinishLaunchingWithOptions
in the launchOptions
argument, but under the UIApplication.LaunchOptionsRemoteNotificationKey
key.
Hi @tranb3r. We have added the "s/needs-info" label to this issue, which indicates that we have an open question for you before we can take further action. This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.
Yes, the launchOptions
does contain the notification information under the UIApplication.LaunchOptionsRemoteNotificationKey
key.
But the return value in WillFinishLaunching
or FinishedLaunching
is ignored when receiving a remote notification.
So, in WillFinishLaunching
, there is nothing I can do to prevent FinishedLaunching
from being called.
In FinishedLaunching
(which is where App OnStart
is being called), I can skip calling base.FinishedLaunching
, and it actually prevents the app from being launched, which is what I want. I can then process DidReceiveRemoteNotification
with services properly initialized.
However, when after that I launch the app manually, a black screen appears and the app is not displayed. What is strange is that the app log shows that the app is starting normally. But only a black screen is shown. Any idea what's happening?
Verified this issue with Visual Studio Enterprise 17.9.0 Preview 1.0. Can repro on iOS platform.
We've added this issue to our backlog, and we will work to address it as time and resources allow. If you have any additional information or questions about this issue, please leave a comment. For additional info about issue management, please read our Triage Process.
@Redth you are our notifications expert!
Description
When a MAUI iOS app receives a Background Update Notification,
DidReceiveRemoteNotification
is called, in order to process a background update. If the app was previously killed, then MAUI creates the app (which is fine) but it also starts the app (which is not fine). On Android, in a similar scenario, the app is created, but not started. Could you please fix it?More details about the succession of events:
In my app, the bad consequence is user being automatically logged out when the app receives a Background Update, because starting the app triggers a biometric check, and as it fails, the user is signed out.
Steps to Reproduce
Link to public reproduction project repository
no need
Version with bug
7.0 (current)
Last version that worked well
Unknown/Other
Affected platforms
iOS
Affected platform versions
iOS 16.2
Did you find any workaround?
no workaround
Relevant log output
No response