Avalonia icon indicating copy to clipboard operation
Avalonia copied to clipboard

Add IActivityApplicationLifetime for android

Open emmauss opened this issue 7 months ago • 8 comments

What does the pull request do?

Adds a lifetime interface specifically for android. It exposes a function to create the app's main view.

[NotClientImplementable]
public interface IActivityApplicationLifetime : IApplicationLifetime
{
   Func<Control>? MainViewFactory { get; set; }
}

What is the current behavior?

Android launches an app with only one Application instance but multiple instances of any activity can be created by the app's lifecycle, explicitly by the dev, or by external apps and debuggers. This means the main activity can be launched multiple times in the lifetime, but with only 1 instance of the main view, any new instances of main activity will crash the app. This can be worked around by setting the launch mode to SingleInstance, but that may not be suitable for most modern apps.

What is the updated/expected behavior with this PR?

Anytime a new instance of the main activity is created, a new instance of the main view is created and set as the avalonia view's content. There's no longer a single main toplevel saved in the lifetime object for the whole app duration.

How was the solution implemented (if it's not obvious)?

Checklist

  • [ ] Added unit tests (if possible)?
  • [ ] Added XML documentation to any related classes?
  • [ ] Consider submitting a PR to https://github.com/AvaloniaUI/avalonia-docs with user documentation

Breaking changes

Xplat projects would need to be updated to set the main view generation function in App.xaml.cs

Obsoletions / Deprecations

Fixed issues

Fixes https://github.com/AvaloniaUI/Avalonia/issues/17943

emmauss avatar May 20 '25 12:05 emmauss

You can test this PR using the following package version. 12.0.999-cibuild0056615-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

avaloniaui-bot avatar May 20 '25 12:05 avaloniaui-bot

You can test this PR using the following package version. 12.0.999-cibuild0056636-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

avaloniaui-bot avatar May 21 '25 13:05 avaloniaui-bot

Could this be made compatible with #18879, which is for iOS?

TomEdwardsEnscape avatar May 21 '25 20:05 TomEdwardsEnscape

Could this be made compatible with #18879, which is for iOS?

I don't quite understand what issue that iOS pr is supposed to fix, nor do I think this pr can be adapted to it. This PR specifically targets Android's unique ability to launch any activity at any time, from any where, just by using the class id of the activity, and fixes the issue of no main view or crash when the launch activity is created anew with an existing instance.

emmauss avatar May 21 '25 22:05 emmauss

I did a terrible job of explaining myself, sorry.

My PR adds IPlatformSingleViewApplicationLifetime and IPlatformSingleViewApplicationLifetime<T>, which could be implemented by your ApplicationLifetime class. This would avoid the need to define an Android-only interface in the Controls project.

However, does it even make sense to use a "single view" application lifetime when the platform determines that there can in fact be any number of views active at the same time? Can we even guarantee that only one is visible at once? I've no experience with Android development, but judging from the floating windows apps can generate on my Android phone I presume that we can't make that guarantee.

The app I am working on has various Avalonia views and also a native view, and it needs to switch between them natively. The app is currently iOS only, but an Android version with equivalent requirements is likely at some point, and an application lifetime with a single MainViewFactory doesn't describe its structure very well. The main view is just one of multiple that will seemingly all need factories.

Would moving this factory method out of the lifetime and over to AvaloniaActivity make sense? Then the lifetime could implement IPlatformSingleViewApplicationLifetime<Activity>. If my understanding is correct, that would provide a means to switch to a native activity via Avalonia's API. A name tweak to something like "PlatformMainView" is also called for.

TomEdwardsEnscape avatar May 25 '25 20:05 TomEdwardsEnscape

AvaloniaActivity already supports setting custom view using the Content property. So you can install an intent filter for any non-launcher activity, set the Content in OnCreate and when that activity is launched, no matter how it is launched, the content will be loaded.

This PR only targets MainAvaloniaActivity. That is because this activity's content is set in App.xaml.cs, and not explicitly in the Activity code.

emmauss avatar May 25 '25 21:05 emmauss

The activity system on android, as annoying as it is to work with, ensures that your issue will not occur on android. To the OS, an activity is the toplevel for any UI. There's nothing above it or owning it. Each activity is launched with its own window, and can only be launched by using Intents, and not by constructing it manually. The OS handles creating and navigating the Activity. Its due to this reason that we've not yet made any toplevel navigation or dialog system for android, because there's no concept of Parent or Owner window. Every activity is pushed to its process's task stack, or another app's process task stack. MainActivity isn't the entry point of an android app. It's the activity launched by the Home Launcher or App Launcher, thus the launcher activity. The user can start multiple MainActivities and they will all be unique and independent of each other, though among these instances, only 1 is launched by the App Launcher.

emmauss avatar May 25 '25 21:05 emmauss

You can test this PR using the following package version. 12.0.999-cibuild0056815-alpha. (feed url: https://nuget-feed-all.avaloniaui.net/v3/index.json) [PRBUILDID]

avaloniaui-bot avatar Jun 02 '25 10:06 avaloniaui-bot

Notes from the API review meeting: the API is approved as is.

MrJul avatar Jun 25 '25 08:06 MrJul