注意
關於尚未正式發行的產品的一些資訊,在正式商業發行前可能會進行大幅修改。 Microsoft 對此處提供的資訊,不提供任何明示或暗示的保證。
本文將逐步引導您建立簡單的摘要提供者,其會註冊摘要內容 URI 並實作 IFeedProvider 介面。 Widgets Board 叫用這個介面的方法,用來要求自訂查詢字串參數,通常是為了支持驗證案例。 資訊流提供者可以支援單一資訊流或多個資訊流。
若要使用 C++/WinRT 實作摘要提供者,請參閱在 win32 應用程式 (C++/WinRT) 中實作摘要提供者。
必要條件
- 您的裝置必須啟用開發人員模式。 如需詳細資訊,請參閱 開發人員的設定。
- Visual Studio 2026 或更新版本,搭配 WinUI 應用程式開發 工作負載。
建立新的 C# 主控台應用程式
在 Visual Studio 中,建立新專案。 在 [建立新專案] 對話方塊中,將語言篩選條件設定為「C」,並將平台篩選條件設定為 Windows,然後選取 [建立新專案] 專案範本。 將新專案命名為「ExampleFeedProvider」。 請確定未勾選將方案和專案放置於同一目錄。 出現提示時,將目標 .NET 版本設定為 6.0。
載入專案時,在 [方案總管] 中,以滑鼠右鍵按一下專案名稱,然後選取 [屬性]。 在 [一般] 頁面上,向下捲動至 [目標作業系統],然後選取 [Windows]。 在 [目標作業系統版本] 底下,選取版本 10.022631.2787 或更新版本。
請注意,本逐步解說會使用主控台應用程式,該應用程式在啟用提要時會顯示主控台視窗,從而便於簡單的偵錯。 當您準備好發佈摘要提供者應用程式時,您可以遵循將主控台應用程式轉換成 Windows 應用程式中的步驟,將主控台應用程式轉換成 Windows 應用程式。
新增對 Windows 應用程式 SDK NuGet 套件的參考
此範例會使用最新的穩定 Windows 應用程式 SDK NuGet 套件。 在 [方案總管] 中,以滑鼠右鍵按一下 [相依性],然後選取 [管理 NuGet 套件...]。在 NuGet 套件管理員中,選取 [瀏覽] 索引標籤並搜尋「Microsoft.WindowsAppSDK」。 在 [版本] 下拉式清單中選取最新的穩定版本,然後按一下 [安裝]。
新增 FeedProvider 類別以處理訂閱源操作
在 Visual Studio 的 [方案總管] 中,以滑鼠右鍵按一下 ExampleFeedProvider 專案,然後選取 [新增] > [類別]。 在 [新增類別] 對話方塊中,命名類別為「FeedProvider」,並按一下 [新增]。 在生成的 FeedProvider.cs 檔案中,更新類別定義,以表明其實作 IFeedProvider 介面。
建立 CLSID,用於識別 COM 啟動之用的供稿提供者。 在 Visual Studio 中,前往 [工具] -> [建立 GUID] 來產生 GUID。 將這個 GUID 儲存在文字檔中,以供稍後在封裝摘要提供者應用程式時使用。 請替換下列範例中的 FeedProvider 類別註釋中的 GUID。
// FeedProvider.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
...
[ComVisible(true)]
[ComDefaultInterface(typeof(IFeedProvider))]
[Guid("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx")]
public sealed class FeedProvider : IFeedProvider
實作 IFeedProvider 方法
在接下來的幾節中,我們將實作 IFeedProvider 介面的方法。
注意
傳遞至 IFeedProvider 介面的回呼方法的物件僅保證在回呼中有效。 您不應該儲存這些物件的參考,因為它們在回呼函式內容之外的行為未定義。
OnFeedProviderEnabled
當 Widgets Board 主機建立與提供程式相關聯的摘要時,將會呼叫 OnFeedProviderEnabled 方法。 在此方法的實作中,產生包含必要參數的查詢字串,這些參數將傳遞至提供饋送內容的 URL,其中包括任何必要的驗證權杖。 建立一個 CustomQueryParametersUpdateOptions 的實例,並傳入事件參數中的 FeedProviderDefinitionId,以識別已啟用的提要和查詢字串。 取得預設的 FeedManager,並呼叫 SetCustomQueryParameters 向 Widgets Board 註冊查詢字串參數。
// FeedProvider.cs
public void OnFeedProviderEnabled(FeedProviderEnabledArgs args)
{
Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was enabled.");
var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1¶m2");
FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}
当Feed提供者被禁用
當 Widgets Board 上此提供者的所有摘要來源都被停用時,會呼叫 OnFeedProviderDisabled。 資料提供者不需要執行任何動作來回應此方法呼叫。 方法調用可用於遙測目的,或視需要更新查詢字串參數或撤銷驗證權杖。 如果應用程式只支援單一摘要提供者,或應用程式支援的所有摘要提供者已停用,則應用程式可以結束以回應此回撥。
// FeedProvider.cs
public void OnFeedProviderDisabled(FeedProviderDisabledArgs args)
{
Console.WriteLine($"{args.FeedProviderDefinitionId} feed provider was disabled.");
}
OnFeedEnabled、OnFeedDisabled
啟用或停用摘要時,Widgets Board 會叫用 OnFeedEnabled 和 OnFeedDisabled。 推送供應商不需要執行任何動作來回應這些方法呼叫。 方法調用可用於遙測目的,或視需要更新查詢字串參數或撤銷驗證權杖。
// FeedProvider.cs
public void OnFeedEnabled(FeedEnabledArgs args)
{
Console.WriteLine($"{args.FeedDefinitionId} feed was enabled.");
}
// FeedProvider.cs
public void OnFeedDisabled(FeedDisabledArgs args)
{
Console.WriteLine($"{args.FeedDefinitionId} feed was disabled.");
}
當自定查詢參數被請求
當工具板判斷與摘要提供者相關聯的自訂查詢參數需要重新整理時,就會觸發 OnCustomQueryParametersRequested。 例如,如果從遠端網頁服務擷取資料流內容的作業失敗,可能會調用此方法。 傳遞至此方法的 CustomQueryParametersRequestedArgs 的 FeedProviderDefinitionId 屬性指定了正在請求查詢字串參數的摘要。 提供程式應該重新產生查詢字串,並藉由呼叫 SetCustomQueryParameters 將其傳遞回 Widgets Board。
// FeedProvider.cs
public void OnCustomQueryParametersRequested(CustomQueryParametersRequestedArgs args)
{
Console.WriteLine($"CustomQueryParamaters were requested for {args.FeedProviderDefinitionId}.");
var updateOptions = new CustomQueryParametersUpdateOptions(args.FeedProviderDefinitionId, "param1¶m2");
FeedManager.GetDefault().SetCustomQueryParameters(updateOptions);
}
實作類別工廠以按照要求實例化 FeedProvider
為了讓摘要主機與摘要提供者通訊,我們必須呼叫 CoRegisterClassObject。 此函式需要我們建立 IClassFactory 的實作,以建立 FeedProvider 類別的類別物件。 我們將在獨立協助程式類別中實作我們的 class factory。
在 Visual Studio 的 [方案資源管理器] 中,以滑鼠右鍵按一下 ExampleFeedProvider 專案,然後選取 [新增類別]>。 在 [新增類別] 對話方塊中,命名類別為「FactoryHelper」,並按一下 [新增]。
以下列程式碼取代 FactoryHelper.cs 檔案的內容。 此程式碼會定義 IClassFactory 介面,並實作其兩種方法 CreateInstance 和 LockServer。 此程式碼是實作類別工廠的典型樣板,並非專門針對摘要提供者的功能,但我們指出所建立的類別物件會實作 IFeedProvider 介面。
// FactoryHelper.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
using System.Runtime.InteropServices;
using WinRT;
namespace ExampleFeedProvider
{
namespace Com
{
static class Guids
{
public const string IClassFactory = "00000001-0000-0000-C000-000000000046";
public const string IUnknown = "00000000-0000-0000-C000-000000000046";
}
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid(Guids.IClassFactory)]
internal interface IClassFactory
{
[PreserveSig]
int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject);
[PreserveSig]
int LockServer(bool fLock);
}
static class ClassObject
{
public static void Register(Guid clsid, object pUnk, out uint cookie)
{
[DllImport("ole32.dll")]
static extern int CoRegisterClassObject(
[MarshalAs(UnmanagedType.LPStruct)] Guid rclsid,
[MarshalAs(UnmanagedType.IUnknown)] object pUnk,
uint dwClsContext,
uint flags,
out uint lpdwRegister);
int result = CoRegisterClassObject(clsid, pUnk, 0x4, 0x1, out cookie);
if (result != 0)
{
Marshal.ThrowExceptionForHR(result);
}
}
public static int Revoke(uint cookie)
{
[DllImport("ole32.dll")]
static extern int CoRevokeClassObject(uint dwRegister);
return CoRevokeClassObject(cookie);
}
}
}
internal class FeedProviderFactory<T> : Com.IClassFactory
where T : IFeedProvider, new()
{
public int CreateInstance(IntPtr pUnkOuter, ref Guid riid, out IntPtr ppvObject)
{
ppvObject = IntPtr.Zero;
if (pUnkOuter != IntPtr.Zero)
{
Marshal.ThrowExceptionForHR(CLASS_E_NOAGGREGATION);
}
if (riid == typeof(T).GUID || riid == Guid.Parse(Com.Guids.IUnknown))
{
// Create the instance of the .NET object
ppvObject = MarshalInspectable<IFeedProvider>.FromManaged(new T());
}
else
{
// The object that ppvObject points to does not support the
// interface identified by riid.
Marshal.ThrowExceptionForHR(E_NOINTERFACE);
}
return 0;
}
int Com.IClassFactory.LockServer(bool fLock)
{
return 0;
}
private const int CLASS_E_NOAGGREGATION = -2147221232;
private const int E_NOINTERFACE = -2147467262;
}
}
向 OLE 註冊 Feed 提供者類別物件
在可執行檔的 Program.cs 檔案中,我們將呼叫 CoRegisterClassObject 向 OLE 註冊我們的摘要提供者,讓 Widgets Board 可以與其互動。 將 Program.cs 的內容取代為下列程式碼。 這會使用我們在上一個步驟中定義的 FeedProviderFactory 介面來註冊 FeedProvider 協助程式類別。 為了進行偵錯,此範例會在預設 FeedManager 執行個體上呼叫 GetEnabledFeedProviders,以取得代表已啟用摘要提供者的 FeedProviderInfo 物件清單。 它會使用 EnabledFeedDefinitionIds 屬性,迴圈查看已啟用的摘要提供者,以列出所有已啟用的摘要識別碼。
// Program.cs
using Microsoft.Windows.Widgets.Feeds.Providers;
using Microsoft.Windows.Widgets.Providers;
using System;
using System.Runtime.InteropServices;
namespace ExampleFeedProvider
{
public static class Program
{
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[MTAThread]
static void Main(string[] args)
{
Console.WriteLine("FeedProvider Starting...");
if (args.Length > 0 && args[0] == "-RegisterProcessAsComServer")
{
WinRT.ComWrappersSupport.InitializeComWrappers();
uint registrationHandle;
var factory = new FeedProviderFactory<FeedProvider>();
Com.ClassObject.Register(typeof(FeedProvider).GUID, factory, out registrationHandle);
Console.WriteLine("Feed Provider registered.");
var existingFeedProviders = FeedManager.GetDefault().GetEnabledFeedProviders();
if (existingFeedProviders != null)
{
Console.WriteLine($"There are {existingFeedProviders.Length} FeedProviders currently outstanding:");
foreach (var feedProvider in existingFeedProviders)
{
Console.WriteLine($" ProviderId: {feedProvider.FeedProviderDefinitionId}, DefinitionIds: ");
var m = WidgetManager.GetDefault().GetWidgetIds();
if (feedProvider.EnabledFeedDefinitionIds != null)
{
foreach (var enabledFeedId in feedProvider.EnabledFeedDefinitionIds)
{
Console.WriteLine($" {enabledFeedId} ");
}
}
}
}
if (GetConsoleWindow() != IntPtr.Zero)
{
Console.WriteLine("Press ENTER to exit.");
Console.ReadLine();
}
else
{
while (true)
{
// You should fire an event when all the outstanding
// FeedProviders have been disabled and exit the app.
}
}
}
else
{
Console.WriteLine("Not being launched to service Feed Provider... exiting.");
}
}
}
}
請注意,此程式碼範例會匯入 GetConsoleWindow 函式,以判斷應用程式是否以主控台應用程式的形式執行,這是本逐步解說的預設行為。 如果函式傳回有效的指標,我們會將偵錯資訊寫入主控台。 否則,應用程式會以 Windows 應用程式的形式執行。 在此情況下,我們會等待OnFeedProviderDisabled方法中設定的事件,當已啟用的摘要提供者清單为空时,我們會退出應用程式。 如需將範例主控台應用程式轉換成 Windows 應用程式的資訊,請參閱將主控台應用程式轉換成 Windows 應用程式。
封裝您的饋送提供者應用程式
在目前的版本中,只有已封裝的應用程式可以註冊為摘要提供者。 下列步驟會引導您完成封裝應用程式並更新應用程式資訊清單的流程,以向作業系統將應用程式註冊為摘要提供者。
建立 MSIX 封裝專案
在 [方案總管] 中,以滑鼠右鍵按一下方案並選取 [新增] > [新增專案...]。在 [新增專案] 對話方塊中,選取「Windows 應用程式封裝專案」範本,然後按一下 [下一步]。 將專案名稱設定為「ExampleFeedProviderPackage」,然後按一下 [建立]。 出現提示時,將目標版本設定為組建 22621 或更新版本,然後按一下 [確定]。 接下來,以滑鼠右鍵按一下 ExampleFeedProviderPackage 專案,然後選取 [新增] > [專案參考]。 選取 ExampleFeedProvider 專案,然後按一下 [確定]。
將 Windows 應用程式 SDK 套件參考新增到封裝專案
您必須將 Windows 應用程式 SDK NuGet 套件的參考新增至 MSIX 封裝專案。 在 [方案總管] 中,按兩下 ExampleFeedProviderPackage 專案,以開啟 ExampleFeedProviderPackage.wapproj 檔案。 在專案元素中新增以下 xml。
<!--ExampleWidgetProviderPackage.wapproj-->
<ItemGroup>
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.5.231116003-experimentalpr">
<IncludeAssets>build</IncludeAssets>
</PackageReference>
</ItemGroup>
注意
請確定 PackageReference 元素中指定的版本 符合您在上一個步驟中所參考的最新穩定版本。
如果電腦上已安裝正確的 Windows 應用程式 SDK 版本,而且您不想在套件中搭配 SDK 執行時間,您可以在 ExampleFeedProviderPackage 專案的 Package.appxmanifest 檔案中指定套件相依性。
<!--Package.appxmanifest-->
...
<Dependencies>
...
<PackageDependency Name="Microsoft.WindowsAppRuntime.1.5.233430000-experimental1" MinVersion="2000.638.7.0" Publisher="CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" />
...
</Dependencies>
...
更新套件資訊清單
在 [方案總管] 中,右鍵按一下 Package.appxmanifest 檔案,然後選取 [檢視程式碼] 以開啟 manifest XML 檔案。 接下來,您需要為我們將使用的應用程式套件延伸模組新增一些命名空間宣告。 將下列命名空間定義新增至最上層 Package 元素。
<!-- Package.appmanifest -->
<Package
...
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
在 Application 元素內,建立名為 Extensions 的新空白元素。 請確定這會在 uap:VisualElements 的結尾標籤之後。
<!-- Package.appxmanifest -->
<Application>
...
<Extensions>
</Extensions>
</Application>
我們需要新增的第一個延伸模組是 ComServer 延伸模組。 這會向作業系統註冊可執行檔的進入點。 此延伸模組是已封裝的應用程式,相當於藉由設定登錄機碼來註冊 COM 伺服器,而且不是小工具提供者特有的。將下列 com:Extension 元素新增為 Extensions 元素的子系。 將 com:Class 元素的 Id 屬性中的 GUID 變更為您在定義 FeedProvider 類別的上一個步驟中產生的 GUID。
<!-- Package.appxmanifest -->
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="ExampleFeedProvider\ExampleFeedProvider.exe" Arguments="-RegisterProcessAsComServer" DisplayName="C# Feed Provider App">
<com:Class Id="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" DisplayName="FeedProvider" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
接下來,新增將應用程式註冊為摘要提供者的擴充功能。 將 uap3:Extension 元素貼入下列程式碼片段,做為 Extensions 元素的子系。 請務必將 COM 元素的 ClassId 屬性取代為您在先前步驟中使用的 GUID。
<!-- Package.appxmanifest -->
<Extensions>
...
<uap3:Extension Category="windows.appExtension">
<uap3:AppExtension Name="com.microsoft.windows.widgets.feeds" DisplayName="ContosoFeed" Id="com.examplewidgets.examplefeed" PublicFolder="Public">
<uap3:Properties>
<FeedProvider Icon="ms-appx:Assets\StoreLogo.png" Description="FeedDescription">
<Activation>
<!-- Apps exports COM interface which implements IFeedProvider -->
<CreateInstance ClassId="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" />
</Activation>
<Definitions>
<Definition Id="Contoso_Feed"
DisplayName="Contoso_Feed Feed"
Description="Feed representing Contoso"
ContentUri="https://www.contoso.com/"
Icon="ms-appx:Images\StoreLogo.png">
</Definition>
<Definition Id="Fabrikam_Feed"
DisplayName="Fabrikam Feed"
Description="Feed representing Example"
ContentUri="https://www.fabrikam.com/"
Icon="ms-appx:Images\StoreLogo.png">
</Definition>
</Definitions>
</FeedProvider>
</uap3:Properties>
</uap3:AppExtension>
</uap3:Extension>
</Extensions>
如需所有這些元素的詳細描述和格式資訊,請參閱摘要提供者套件資訊清單 XML 格式。
測試供稿來源
請確定您已從 [方案平台] 下拉式清單中選取符合您開發電腦的架構,例如「x64」。 在 [方案總管] 中,以右鍵按一下方案,然後選取 [建置解決方案]。 完成此動作後,以滑鼠右鍵按下您的 ExampleWidgetProviderPackage,然後選取 [部署]。 主控台應用程式應該會在部署時啟動,您會在主控台輸出中看到資料饋送已啟用。 開啟 Widgets Board,您應該會在動態區段頂端的索引標籤中看到新的動態。
對訊息提供者進行偵錯
釘選摘要之後,Widget 平台會啟動您的摘要提供者應用程式,以接收和傳送摘要的相關資訊。 若要偵錯執行中的摘要,您可以將偵錯工具附加至執行中的摘要提供者應用程式,或者您可以設定 Visual Studio 在啟動後自動開始偵錯摘要提供者流程。
若要附加至執行中的程序:
- 在 Visual Studio 按一下 偵錯 - 附加至處理序>。
- 篩選處理程序,並尋找您想要的訂閱供應商應用程式。
- 連結偵錯工具。
若要在一開始啟動偵錯程式時自動將偵錯程式附加至流程:
- 在 Visual Studio 中,按一下 >[偵錯] > [其他偵錯目標] [偵錯已安裝的應用程式套件]。
- 篩選套件,並尋找所需的資料源供應商套件。
- 請選取它,然後勾選標示為「不要啟動,而是在啟動時偵錯我的程式碼」的選項。
- 按一下 附加。
將主控台應用程式轉換為 Windows 應用程式
若要將本逐步解說中建立的主控台應用程式轉換為 Windows 應用程式,請以滑鼠右鍵按一下 [方案總管] 中的 ExampleFeedProvider 專案,並選取 [屬性]。 在 [應用程式] > [一般] 下,將 [輸出類型] 從 [主控台應用程式] 變更為 [Windows 應用程式]。
發佈您的資訊流提供者應用程式
在開發並測試您的摘要提供者之後,您可以在 Microsoft Store 上發佈您的應用程式,使用者才能在其裝置上安裝您的摘要。 如需發佈應用程式的逐步指引,請參閱在 Microsoft Store 中發佈您的應用程式。
資料流存放區集合
在 Microsoft 市集上發布您的應用程式之後,您可以要求您的應用程式包含在摘要市集集合中,以協助使用者探索具有 Windows 摘要的應用程式。 若要提交您的要求,請參閱 將您的摘要/面板提交以新增至 Store 集合。