MAUI Windows 应用程序的 URI 启动会创建一个新实例。我只需要一个应用程序实例

问题描述 投票:0回答:3

我可以使用 URI 启动我的 Windows MAUI 应用程序,并且可以获取 URI 本身。 但是,似乎正在创建该应用程序的一个新实例。 这对我来说并不理想——如果我的应用程序已经在运行,我想使用该实例。

我已经为 Xamarin.Forms 应用程序做了类似的事情。 我在 Application 类中重写 OnActivated。

回复:我的 MAUI 应用程序,我什至不清楚问题是我如何在 package.appxmanifest 中完成“协议”,还是我如何响应生命周期事件。

windows maui winui-3 winui
3个回答
4
投票

这个解决方案基本上,如果您有任何打开的实例,则无法打开新实例。因为 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();

   }
}

3
投票

默认行为是运行应用程序的多个实例。您可以通过使用

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 上有一个开放的建议来简化此流程。


0
投票

此解决方案不需要

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.用户打开
my-app://url
2.用户打开
my-app://url
3. Instance1 接收
OnActivated
Protocol
3.使用 Protocol
 启动应用程序 (
Instance2

如您所见,在 Windows App SDK 中,没有向您之前的

Instance1
实例发出激活信号。

为了解决这个问题,我们使用 RedirectActivationToAsync:

  1. OnLaunch
    中,检查
    Kind
    是否为
    Protocol
    。这种情况只会发生在
    Instance2
    (通过 URI 启动的实例)。
  2. 如果是,请将这些参数重定向到所有其他实例(如果您有多实例应用程序),或您可能需要的任何自定义逻辑。
    • 对于 MAUI,我们也不会在此方法中调用
      base.OnLaunched
      ,因此不会创建新窗口。
  3. 相反,如果不是由
    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);
    }

}

© www.soinside.com 2019 - 2024. All rights reserved.