Windows 共享界面允许你的应用接收来自其他应用共享的内容。 本指南介绍如何将应用注册为共享目标,并跨打包的应用(MSIX)、渐进式Web 应用(PWA)和未打包的 Win32 应用处理共享内容。
在本文中
| Section | 你将找到的内容 |
|---|---|
| 声明功能之前 | 仅声明应用可处理的文件类型和格式 |
| 实现打包应用的共享目标(UWP 和打包桌面) | UWP 和打包桌面应用的清单声明和激活处理 |
| 实现 PWA 的共享目标 |
share_target 清单和 POST 处理 |
| 在未打包的 Win32 应用中接收共享内容 | 授予包标识并注册为共享目标 |
| 最佳实践 | 关于可靠接收流程的建议 |
| 报告接收进度 | 针对大型或长时间运行的共享任务的状态报告 |
| 故障排除 | 常见 Share Target 问题修复 |
在声明能力之前
大多数共享目标集成中的问题都源于 声明了超出你的应用实际处理能力的内容。 如果你的应用声明 <uap:SupportsAnyFileType />,它将出现在 每种 文件类型的共享工作表中,包括它无法处理的文件(例如,当用户共享电子表格时显示的照片编辑器)。
始终仅声明应用可以处理的特定文件类型和数据格式。 例如:
<!-- ✓ Correct: declare only what you support -->
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.png</uap:FileType>
</uap:SupportedFileTypes>
<!-- ✗ Incorrect: declares everything -->
<!-- <uap:SupportsAnyFileType /> -->
仅将 <uap:SupportsAnyFileType /> 用于通用文件传输工具(如云存储、文件传输应用)。 请参阅 DataFormat 和 FileType 参考 ,了解按应用类别的声明。
实现打包应用的共享目标(UWP 和打包桌面)
本部分适用于 UWP 应用和打包的桌面应用(WinUI 3、WPF、WinForms)。 这两个包都作为具有程序包标识的 MSIX 包提供,因此它们以相同的方式声明共享目标,并且仅在处理激活的方式(步骤 2 中所示)有所不同。
1. 在清单文件中声明
编辑你的 package.appxmanifest,以将其注册为共享目标。
仅声明应用可处理的文件类型和数据格式:
<Extensions>
<uap:Extension Category="windows.shareTarget">
<uap:ShareTarget>
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.jpeg</uap:FileType>
<uap:FileType>.png</uap:FileType>
<uap:FileType>.gif</uap:FileType>
<uap:FileType>.bmp</uap:FileType>
</uap:SupportedFileTypes>
<uap:DataFormat>Bitmap</uap:DataFormat>
</uap:ShareTarget>
</uap:Extension>
</Extensions>
2. 处理共享激活
当你的应用被激活为共享目标时,请处理 OnShareTargetActivated 事件:
注释
OnShareTargetActivated 是 UWP 应用的激活重写(Windows.UI.Xaml.Application)。 打包的桌面应用(WinUI 3、WPF、WinForms)通过 AppInstance.GetActivatedEventArgs 接收共享激活,并检查 ExtendedActivationKind.ShareTarget。 请参阅 获取打包应用的激活信息。
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
try
{
if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
// Validate: check count, types, and sizes
if (items.Count == 0)
{
shareOperation.ReportError("No items received.");
return;
}
var file = (IStorageFile)items[0];
// Process the file
await ProcessImageAsync(file);
}
shareOperation.ReportCompleted();
}
catch (Exception ex)
{
shareOperation.ReportError($"Error: {ex.Message}");
}
}
private async Task ProcessImageAsync(IStorageFile file)
{
// Your processing logic here
}
对于使用Windows 应用 SDK生成的打包桌面应用(WinUI 3、WPF、WinForms),没有OnShareTargetActivated替代。 请改为检查 Main 方法中的激活情况,并查看是否存在 ExtendedActivationKind.ShareTarget:
using Microsoft.Windows.AppLifecycle;
using Windows.ApplicationModel.Activation;
using Windows.ApplicationModel.DataTransfer;
[STAThread]
static void Main(string[] args)
{
AppActivationArguments activatedArgs = AppInstance.GetCurrent().GetActivatedEventArgs();
if (activatedArgs.Kind == ExtendedActivationKind.ShareTarget)
{
HandleShareAsync(activatedArgs.Data as ShareTargetActivatedEventArgs);
}
else
{
// Normal launch path
}
}
static async void HandleShareAsync(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
if (shareOperation.Data.Contains(StandardDataFormats.StorageItems))
{
IReadOnlyList<IStorageItem> items = await shareOperation.Data.GetStorageItemsAsync();
// Process the shared items.
}
shareOperation.ReportCompleted();
}
3.选择要声明的数据格式
使用此引用可决定声明的内容:
| 格式 | 何时使用 | 示例应用 |
|---|---|---|
StorageItems |
你的应用接收文件 | 照片编辑器、文档阅读器 |
Bitmap |
你的应用接收图像 | 图像查看器,设计应用 |
Text |
你的应用接收纯文本 | 备注应用、文本编辑器 |
Html |
你的应用接收 RTF 内容 | 电子邮件客户端,富文本编辑器 |
Uri / WebLink |
您的应用可处理链接 | 浏览器,链接管理器 |
Rtf |
你的应用接收带格式的文本 | Word处理器 |
有关详细信息,请参阅 DataFormat 和 FileType 参考。
为渐进式 Web 应用(PWA)实现共享目标
Windows 上的 PWA 通过 Web 应用清单注册为共享目标。 添加条目 share_target :
{
"name": "My PWA",
"short_name": "MyPWA",
"share_target": {
"action": "/share",
"method": "POST",
"enctype": "multipart/form-data",
"params": {
"title": "title",
"text": "text",
"url": "url",
"files": [
{
"name": "media",
"accept": ["image/*", "video/*"]
}
]
}
}
}
在 /share 路由中,处理 POST 请求:
app.post('/share', async (req, res) => {
const { title, text, url, files } = req.body;
// Validate and process
if (files && files.length > 0) {
const file = files[0];
// Process the file
console.log('Received file:', file.originalname);
}
if (text) {
console.log('Received text:', text);
}
res.redirect('/');
});
仅声明 PWA 可以处理的文件类型。 例如,除非应用真正处理所有文件,否则不要声明 * 为接受类型。
在未打包的 Win32 应用中接收共享内容
若要注册为共享目标,应用需要 包标识。 如果 Win32 应用已解压缩,请通过以下两种方式之一授予它包标识:
- 使用 MSIX 重新打包(首选):使用Visual Studio中的Windows应用程序打包Project模板进行干净、受信任的安装。 请参阅 为桌面应用程序设置 MSIX 打包。
- 具有外部位置的包 (稀疏包):添加一个包含标识、共享目标注册和视觉资产的空 MSIX 包,而现有安装程序则继续管理应用二进制文件。 仅当你有一个无法迁移到 MSIX 的安装程序时,才使用此项。
本节其余内容将逐步介绍外部位置方法。
1. 编写包清单文件
创建一个 AppxManifest.xml,用于设置 <uap10:AllowExternalContent>、声明标识和功能,并注册共享目标。 使Publisher、PackageName和ApplicationId与.exe.manifest及签名证书保持同步。
<Identity Name="PhotoStoreDemo" ProcessorArchitecture="neutral" Publisher="CN=YourPubNameHere" Version="1.0.0.0" />
<Properties>
<uap10:AllowExternalContent>true</uap10:AllowExternalContent>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
</Capabilities>
<Applications>
<Application Id="PhotoStoreDemo" Executable="PhotoStoreDemo.exe" uap10:TrustLevel="mediumIL" uap10:RuntimeBehavior="win32App">
<Extensions>
<uap:Extension Category="windows.shareTarget">
<uap:ShareTarget Description="Send to PhotoStoreDemo">
<uap:SupportedFileTypes>
<uap:FileType>.jpg</uap:FileType>
<uap:FileType>.png</uap:FileType>
</uap:SupportedFileTypes>
<uap:DataFormat>StorageItems</uap:DataFormat>
<uap:DataFormat>Bitmap</uap:DataFormat>
</uap:ShareTarget>
</uap:Extension>
</Extensions>
</Application>
</Applications>
添加将可执行文件链接到包标识的应用程序清单(YourApp.exe.manifest):
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="PhotoStoreDemo.app" />
<msix xmlns="urn:schemas-microsoft-com:msix.v1"
publisher="CN=YourPubNameHere"
packageName="PhotoStoreDemo"
applicationId="PhotoStoreDemo" />
</assembly>
2.创建包并签名
使用 MakeAppx.exe 和 /nv 开关生成仅包含清单的包,然后使用 SignTool.exe 和受信任的证书对其进行签名:
MakeAppx.exe pack /d <folder with AppxManifest.xml> /p <output>\mypackage.msix /nv
SignTool.exe sign /fd SHA256 /a /f <path to cert> /p <cert key> <path to package>
将签名证书安装到计算机上的受信任位置。
3.首次运行时注册包
首次运行时,请注册 external-location 程序包,以便应用能够以身份标识重新启动。 提供外部位置和已签名 .msix的绝对路径。
[STAThread]
public static void Main(string[] cmdArgs)
{
if (!ExecutionMode.IsRunningWithIdentity())
{
string externalLocation = Environment.CurrentDirectory;
string externalPkgPath = externalLocation + @"\PhotoStoreDemo.package.msix";
if (registerPackageWithExternalLocation(externalLocation, externalPkgPath))
{
// Registration succeeded - restart so the app runs with identity.
// Join the arguments into a single string; cmdArgs.ToString() would
// return the array type name ("System.String[]"), not the arguments.
string forwardedArgs = cmdArgs is null ? string.Empty : string.Join(" ", cmdArgs);
Process.Start(Application.ResourceAssembly.Location, arguments: forwardedArgs);
}
else
{
// Registration failed - run without identity.
new SingleInstanceManager().Run(cmdArgs);
}
}
}
4. 处理共享激活
应用使用标识重启后,处理 ExtendedActivationKind.ShareTarget 方式如 “处理共享激活”中所示。
有关完整示例,请参阅 PhotoStoreDemo 示例(采用外部位置打包)和WinUI 共享目标示例。
对于源端桌面共享,请按照从您的应用共享内容中的说明使用 IDataTransferManagerInterop。
最佳做法
构建接收流程时,请使用此清单。
| 推荐 | 避免 | 它为何重要 |
|---|---|---|
| 仅声明特定的文件扩展名和数据格式 | 为非文件移动类应用声明 <uap:SupportsAnyFileType /> |
防止无关的共享目标显示在共享菜单中 |
| 在处理之前验证格式、计数、文件类型和文件大小 | 假设传入数据始终符合预期 | 防止运行时故障和共享体验中断 |
为链接处理程序声明 Uri,为图像处理程序声明 Bitmap + StorageItems |
通用共享负载的部分声明 | 确保您的应用仅针对其实际支持的内容显示 |
在长时间运行的接收流中使用 ReportStarted、ReportDataRetrieved 和 ReportCompleted |
在不报告进度的情况下执行长时间运行的接收工作 | 保持共享操作的可靠性,并使系统处于正确状态 |
上报接收进度(可选,但建议启用)
对于较大的负载或处理时间较长的情况,请由共享目标报告状态:
protected override async void OnShareTargetActivated(ShareTargetActivatedEventArgs args)
{
ShareOperation shareOperation = args.ShareOperation;
shareOperation.ReportStarted();
try
{
// Acquire the data your app needs.
var items = await shareOperation.Data.GetStorageItemsAsync();
shareOperation.ReportDataRetrieved();
// Process data.
await ProcessAsync(items);
shareOperation.ReportCompleted();
}
catch (Exception ex)
{
shareOperation.ReportError($"Share failed: {ex.Message}");
}
}
如果您希望返回一个供后续分享使用的 QuickLink,请使用 ReportCompleted(QuickLink)。
故障排除
我的应用未显示在“共享工作表”中:
- 验证清单声明是否与共享的内容匹配(检查文件类型和数据格式)。
- 对于打包的应用,请确保使用包标识运行应用。
- 查看适用于您的应用类别的 DataFormat 和 FileType 参考文档。
我的应用会针对它无法处理的内容显示出来:
- 将你的
SupportedFileTypes和DataFormat列表缩小到你支持的内容。
共享面板因报错而关闭:
- 请确保在进行任何异步工作之前调用
ReportStarted(),并在完成时调用ReportCompleted()。 - 使用描述性消息处理异常和调用
ReportError()。
我未收到我预期的文件:
- 检查文件格式是否与已声明的
FileType或DataFormat相匹配。 - 在激活处理程序中添加验证逻辑,以检查实际到达的内容。