Windows 分享面板可讓你的應用程式接收從其他應用程式分享的內容。 本指南說明如何將您的應用程式註冊為 Share Target,並處理跨封裝應用程式(MSIX)、Progressive Web Apps(PWA)及未封裝 Win32 應用程式間的共享內容。
本文內容
| 章節 | 你會發現什麼 |
|---|---|
| 在你宣告能力之前 | 只宣告你應用程式能處理的檔案類型和格式 |
| 為打包式應用程式(UWP 和打包桌面)實作 Share Target。 | UWP 及打包桌面應用程式的清單宣告與啟用處理 |
| 為 PWA 實施共享目標 |
share_target 清單與郵件處理 |
| 在未封裝的 Win32 應用程式中接收分享 | 授予套件身份並註冊為共享目標 |
| 最佳作法 | 可靠接收流的建議 |
| 回報接收進度 | 大型或長期經營股份的狀態報告 |
| Troubleshooting | 常見 Share Target 問題的修正 |
在你宣告能力之前
大多數 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 和打包桌面)實作 Share Target。
本節適用於 UWP 應用程式及打包桌面應用程式(WinUI 3、WPF、WinForms)。 兩者都是以 MSIX 套件形式出貨,並帶有套件身份,因此它們宣告 Share Target 的方式相同,僅在啟用處理方式上有所不同(如步驟 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 事件:
Note
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. 選擇宣告的資料格式
請參考此資料決定要申報哪些內容:
| Format | 何時使用 | 範例應用程式 |
|---|---|---|
StorageItems |
你的應用程式會接收檔案 | 照片編輯、文件閱讀器 |
Bitmap |
你的應用程式會接收圖片 | 影像檢視器、設計應用程式 |
Text |
你的應用程式接收的是純文字 | 筆記應用程式、文字編輯器 |
Html |
你的應用程式會接收豐富的文字內容 | 電子郵件用戶端、富文字編輯器 |
Uri / WebLink |
你的應用程式會處理連結 | 瀏覽器、連結管理器 |
Rtf |
你的應用程式會收到格式化的文字 | 文字處理器 |
更多細節請參閱 DataFormat 與 FileType 參考。
為漸進式 Web Apps(PWA)實施共享目標
Windows 上的 PWA 會透過網頁應用程式清單註冊為共享目標。 新增一個 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 應用程式中接收分享
要註冊為 Share Target,你的應用程式需要套件 身份。 如果你的 Win32 應用程式是未封裝的,請以兩種方式之一賦予它套件身份:
- 建議使用 MSIX 重新打包(建議):使用 Visual Studio 中的 Windows Application Packaging 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. 首次執行時註冊套件
第一次執行時,註冊外部定位套件,讓應用程式以身份重新啟動。 提供通往外部位置的絕對路徑,並標示 .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 Share Target 範例。
若要在桌面端分享原始碼,請依照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) 。
Troubleshooting
我的應用程式不會出現在分享工作表中:
- 確認你的清單聲明與分享的內容相符(檢查檔案類型和資料格式)。
- 對於打包式應用程式,請確保你執行的是帶有套件身份的應用程式。
- 請檢查您的應用程式類別中的 DataFormat 與 FileType 參考 。
我的應用程式會出現它無法處理的內容:
- 將你的
SupportedFileTypes和DataFormat清單縮減為只包含你支援的項目。
分享表單關閉時發生錯誤:
- 請務必在進行任何非同步作業之前呼叫
ReportStarted(),並在完成後呼叫ReportCompleted()。 - 處理例外,並用描述性訊息呼叫
ReportError()。
我沒有收到我預期的檔案:
- 檢查檔案格式是否符合宣告的
FileType或DataFormat。 - 在你的啟用處理常式中加入驗證邏輯,以檢查實際傳入的是什麼。