协议激活(也称为 深层链接 或 URI 激活)允许另一个应用、浏览器或命令行通过导航到 URI(例如 myapp://action?param=value)启动应用。
本文专门介绍WPF应用的代码。 有关完整指南,请参阅主 句柄 URI 激活 文章。 有关使用 Windows 应用 SDK 进行丰富激活的完整详细信息,请参阅使用应用生命周期 API 进行Rich 激活。
注册用于协议激活
必须注册应用才能处理协议激活。 对于未打包的应用,可以在代码中注册。 对于打包的应用,可以在应用清单中注册。
未打包的应用
对于未打包的.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 元素的 Package 中声明 XML 命名空间:xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"。
进行激活处理
使用 AppInstance.GetCurrent()检索激活参数。GetActivatedEventArgs。 以下示例包含未打包的WPF应用的代码,该应用在启动时调用 RegisterForProtocolActivation。 打包应用程序通过“Manifest”注册进行激活,因此可以跳过 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.
}
注释
WPF和Windows 窗体应用必须调用 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();
});
}
有关应用程序实例的详细信息,请参阅 使用应用生命周期 API 的应用实例化。