在您的應用程式中接收內容 - 整合 Windows 分享

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>、宣告身分與功能,並註冊分享目標。 使 PublisherPackageNameApplicationId 與你的 .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 普通股有效載荷的部分申報 確保你的應用程式會顯示出它實際支援的內容
在長時間執行的接收流程中使用 ReportStartedReportDataRetrievedReportCompleted 執行長時間的接收作業而未回報進度 保持共享操作的可靠性,並賦予系統正確的狀態

對於較大的酬載或處理時間較長的作業,請從分享目標回報狀態:

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 參考

我的應用程式會出現它無法處理的內容:

  • 將你的 SupportedFileTypesDataFormat 清單縮減為只包含你支援的項目。

分享表單關閉時發生錯誤:

  • 請務必在進行任何非同步作業之前呼叫 ReportStarted(),並在完成後呼叫 ReportCompleted()
  • 處理例外,並用描述性訊息呼叫 ReportError()

我沒有收到我預期的檔案:

  • 檢查檔案格式是否符合宣告的 FileTypeDataFormat
  • 在你的啟用處理常式中加入驗證邏輯,以檢查實際傳入的是什麼。