我可以使用 URI 启动我的 Windows MAUI 应用程序,并且可以获取 URI 本身。 但是,似乎正在创建该应用程序的一个新实例。 这对我来说并不理想——如果我的应用程序已经在运行,我想使用该实例。
我已经为 Xamarin.Forms 应用程序做了类似的事情。 我在 Application 类中重写 OnActivated。
回复:我的 MAUI 应用程序,我什至不清楚问题是我如何在 package.appxmanifest 中完成“协议”,还是我如何响应生命周期事件。
这个解决方案基本上,如果您有任何打开的实例,则无法打开新实例。因为 WaitOne 功能是在创建新程序之前检测另一个实例并关闭新程序。(App.xaml.cs) (.NET MAUI)
public partial class App : Application{
private static Mutex mutex = new Mutex(true, Assembly.GetEntryAssembly().GetName().Name);
public App()
{
if (!mutex.WaitOne(TimeSpan.Zero, true))
{
Current.Quit();
Environment.Exit(0);
}
InitializeComponent();
MainPage = new AppShell();
}
}
默认行为是运行应用程序的多个实例。您可以通过使用
Main
方法定义自定义类来使应用程序成为单实例,如 此博客 帖子中所建议:
[STAThread]
static async Task Main(string[] args)
{
WinRT.ComWrappersSupport.InitializeComWrappers();
bool isRedirect = await DecideRedirection();
if (!isRedirect)
{
Microsoft.UI.Xaml.Application.Start((p) =>
{
var context = new DispatcherQueueSynchronizationContext(
DispatcherQueue.GetForCurrentThread());
SynchronizationContext.SetSynchronizationContext(context);
new App();
});
}
return 0;
}
private static async Task DecideRedirection()
{
bool isRedirect = false;
AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
ExtendedActivationKind kind = args.Kind;
AppInstance keyInstance = AppInstance.FindOrRegisterForKey("randomKey");
if (keyInstance.IsCurrent)
{
keyInstance.Activated += OnActivated;
}
else
{
isRedirect = true;
await keyInstance.RedirectActivationToAsync(args);
}
return isRedirect;
}
GitHub 上有一个开放的建议来简化此流程。
此解决方案不需要
Program.cs
(我无法在 MAUI 项目中添加该文件),并且您通常会留在 MAUI 代码中。它还适用于 WinUI3 和 Windows App SDK。请注意,此解决方案还仅保证协议激活时的单个实例(即启动 URI 时不会打开新窗口)。如果您想要真正的单实例,您需要额外的或不同的逻辑。
我遇到了这些问题:
我无法通过协议获得任何Activated 或OnActivated 事件调用。
会打开一个新窗口。
旧实例(例如,登录窗口正在等待)不会收到任何已调用
my-app://login/result=xyz
之类的 URI 的信号。
我发现了应用程序生命周期功能迁移,我建议阅读它,至少是我链接的部分,它将帮助您理解这个问题以及为什么我以这种方式解决它。请注意,尽管链接到单实例应用程序,但我仅使用它来解决问题,并且该解决方案不会强制您的应用程序成为单实例。
总结本文,Windows App SDK(WinUI3 基于的,而 MAUI 基于的)流程发生了变化:
UWP | Windows 应用程序 SDK |
---|---|
1.应用程序启动(实例1) | 1.应用程序启动(实例1) |
2.用户打开
|
2.用户打开
|
3. Instance1 接收 和
|
3.使用 Protocol 启动应用程序 (Instance2 |
如您所见,在 Windows App SDK 中,没有向您之前的
Instance1
实例发出激活信号。
为了解决这个问题,我们使用 RedirectActivationToAsync:
OnLaunch
中,检查Kind
是否为Protocol
。这种情况只会发生在 Instance2
(通过 URI 启动的实例)。base.OnLaunched
,因此不会创建新窗口。Protocol
启动,则注册Activated
事件来监听由Instance2
转发的协议事件。 毛伊岛注意事项: 您也必须为毛伊岛执行此操作。由于某种原因,此处未调用 OnActivated
生命周期。这是解决方案,它适用于 MAUI,但我相信它也适用于 WinUI3 和 Windows App SDK:
// In your App.xaml.cs
public partial class App : MauiWinUIApplication
{
// ...
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
var appInstance = AppInstance.GetCurrent();
var e = appInstance.GetActivatedEventArgs();
// If it's not a Protocol activation, just launch the app normally
if (e.Kind != ExtendedActivationKind.Protocol ||
e.Data is not ProtocolActivatedEventArgs protocol)
{
appInstance.Activated += AppInstance_Activated;
base.OnLaunched(args);
return;
}
// If it's a Protocol activation, redirect it to other instances
var instances = AppInstance.GetInstances();
await Task.WhenAll(instances
.Select(async q => await q.RedirectActivationToAsync(e)));
return;
}
private void AppInstance_Activated(object? sender, AppActivationArguments e)
{
if (e.Kind != ExtendedActivationKind.Protocol ||
e.Data is not ProtocolActivatedEventArgs protocol)
{
return;
}
// Process your activation here
Debug.WriteLine("URI activated: " + protocol.Uri);
}
}