在 .NET 應用程式中處理 URI 協定的啟用

協定啟用(也稱為 深度連結URI 啟用)允許另一個應用程式、瀏覽器或命令列透過移至 URI(例如 myapp://action?param=value)來做為應用程式啟動方式。

本文展示了專門針對 WPF 應用程式的程式碼。 完整指引請參閱主文《 處理 URI 啟動 》條目。 關於 Windows 應用程式 SDK 的豐富啟用完整細節,請參見 應用程式生命週期 API 的豐富啟用

為協議啟動註冊

您必須註冊應用程式才能處理協定啟動。 對於未封裝的應用程式,你需要用程式碼註冊。 對於打包的應用程式,你需要在應用程式清單中註冊。

未封裝的應用程式

對於未封裝的 .NET 應用程式(預設的 WPF/WinForms 設定),啟動時使用 ActivationRegistrationManager 註冊你的協定。 註冊是按用戶計算且持續存在,所以每次啟動時都可以這麼做。

App.xaml.cs 中覆寫 OnStartup

using Microsoft.Windows.AppLifecycle;

protected override void OnStartup(StartupEventArgs e)
{
    // Register the URI scheme "myapp://" for this app.
    // For the logo, pass the exe path + resource index (or "" to use the default icon).
    string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName ?? "";
    string logo = string.IsNullOrEmpty(exePath) ? "" : exePath + ",0";
    ActivationRegistrationManager.RegisterForProtocolActivation(
        "myapp",                // URI scheme (no "://")
        logo,                   // logo: exe path + resource index, or "" for default icon
        "My App",               // display name for the protocol
        exePath);               // path of this EXE; pass "" to default to the current process

    base.OnStartup(e);
}

要清理註冊(例如在卸載步驟中),請呼叫 ActivationRegistrationManager.UnregisterForProtocolActivation("myapp", "")

已封裝應用程式

對於已封裝的 .NET 應用程式,請在 Package.appxmanifest 元素下以 <Applications><Application> 宣告協定:

<Applications>
  <Application ...>
    <Extensions>
      <uap:Extension Category="windows.protocol">
        <uap:Protocol Name="myapp">
          <uap:DisplayName>My App</uap:DisplayName>
        </uap:Protocol>
      </uap:Extension>
    </Extensions>
  </Application>
</Applications>

確保 uap XML 命名空間在 Package 元素 xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"上宣告: 。

處理啟動程序

請使用 AppInstance.GetCurrent() 取得啟用參數。GetActivatedEventArgs。 以下範例包含一個未封裝的 WPF 應用程式程式碼,啟動時呼叫 RegisterForProtocolActivation。 包裝好的應用程式會透過清單註冊獲得啟動,因此可以跳過通話 RegisterForProtocolActivation

using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;

protected override void OnStartup(StartupEventArgs e)
{
    // Unpackaged apps only: register the protocol at startup.
    // Packaged apps (MSIX): skip these lines — the manifest handles registration.
    string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName ?? "";
    string logo = string.IsNullOrEmpty(exePath) ? "" : exePath + ",0";
    ActivationRegistrationManager.RegisterForProtocolActivation(
        "myapp", logo, "My App", exePath);

    // Get the activation args for this specific launch.
    AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs();
    if (args?.Kind == ExtendedActivationKind.Protocol)
    {
        var protocolArgs = (ProtocolActivatedEventArgs)args.Data;
        HandleProtocolActivation(protocolArgs.Uri);
    }

    base.OnStartup(e);
}

private void HandleProtocolActivation(Uri uri)
{
    // Navigate to or open content based on uri.AbsolutePath or uri.Query.
}

Note

WPF 和 Windows Forms 應用程式 must呼叫 AppInstance.GetCurrent().GetActivatedEventArgs() 以取得 URI 啟用資料。 與 C++ Win32 應用程式不同,.NET 應用程式不會透過啟動進入點參數接收啟用參數。

處理單一實例重定向

如果你的應用程式應該一次只執行一個實例,請使用 AppInstance.FindOrRegisterForKey 將後續的 URI 啟動重新導向至正在執行的實例:

protected override void OnStartup(StartupEventArgs e)
{
    string exePath = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName ?? "";
    string logo = string.IsNullOrEmpty(exePath) ? "" : exePath + ",0";
    ActivationRegistrationManager.RegisterForProtocolActivation(
        "myapp", logo, "My App", exePath);

    // Try to claim the "main" key. If another instance already has it, redirect and exit.
    AppInstance currentInstance = AppInstance.FindOrRegisterForKey("main");
    if (!currentInstance.IsCurrent)
    {
        var activationArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
        // Run the async redirect on a thread-pool thread to avoid a potential deadlock
        // with the WPF SynchronizationContext. Signal completion via an event so that
        // this code path exits cleanly without re-entering the STA message pump.
        var redirectCompleted = new System.Threading.ManualResetEventSlim(false);
        System.Threading.Tasks.Task.Run(async () =>
        {
            await currentInstance.RedirectActivationToAsync(activationArgs);
            redirectCompleted.Set();
        });
        redirectCompleted.Wait();
        Shutdown();
        return;
    }

    // This is the first instance. Subscribe to future activations.
    currentInstance.Activated += OnActivated;
    base.OnStartup(e);
}

private void OnActivated(object sender, AppActivationArguments args)
{
    Dispatcher.Invoke(() =>
    {
        if (args.Kind == ExtendedActivationKind.Protocol)
        {
            var protocolArgs = (ProtocolActivatedEventArgs)args.Data;
            HandleProtocolActivation(protocolArgs.Uri);
        }
        MainWindow?.Activate();
    });
}

欲了解更多關於應用程式實例化的資訊,請參閱 使用 App 生命週期 API 進行應用程式實例化。