Dela via


Snabbstart: Appaviseringar i Windows App SDK

En skärmdump som visar ett appmeddelande ovanför aktivitetsfältet. Meddelandet är en påminnelse för en händelse. Appens namn, händelsenamn, händelsetid och händelseplats visas. En markeringsinmatning visar det valda värdet

I den här snabbstarten skapar du ett Windows-skrivbordsprogram som skickar och tar emot lokala appaviseringar, även kallade popup-meddelanden, med hjälp av Windows App SDK.

Important

Meddelanden för en app med administratörsbehörighet stöds inte för närvarande.

Prerequisites

Sample app

Den här snabbstarten beskriver kod från exempelapparna för meddelanden som finns på GitHub.

API reference

Api-referensdokumentation för appmeddelanden finns i Microsoft.Windows.AppNotifications Namespace.

Steg 1: Lägga till namnområdesdeklarationer

Lägg till namnområdet för Windows App SDK-appaviseringar Microsoft.Windows.AppNotifications.

using Microsoft.Windows.AppNotifications;

Steg 2: Uppdatera appens manifest

Om din app är uppackad (dvs. den saknar paketidentitet vid körning) går du vidare till steg 3: Registrera dig för att hantera en appavisering.

Om din app är paketerad (inklusive paketerad med extern plats):

  1. Öppna din Package.appxmanifest.
  2. Lägg till xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" och xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" namnområden i <Package>
  3. Lägg till <desktop:Extension> för windows.toastNotificationActivation för att deklarera din COM-aktivator CLSID-. Du kan hämta ett CLSID genom att gå till Skapa GUID- under Tools i Visual Studio.
  4. Lägg till <com:Extension> för COM-aktivatorn med samma CLSID.
    1. Ange din .exe-fil i attributet Executable. Den .exe-filen måste vara den samma processen som anropar Register() när du registrerar din app för meddelanden, vilket beskrivs mer i Steg 3. I exemplet nedan använder vi Executable="SampleApp\SampleApp.exe".
    2. Ange Arguments="----AppNotificationActivated:" för att säkerställa att Windows App SDK kan bearbeta meddelandets nyttolast som appnotifieringstyp.
    3. Ange en DisplayName.

Important

Varning! Om du definierar en Windows.Protocol- app-extensibilitetstyp i ditt appx-manifest med <uap:Protocol>, kommer klick på aviseringar att starta nya processer av samma app, även om appen redan körs.

<!--Packaged apps only-->
<!--package.appxmanifest-->

<Package
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Specify which CLSID to activate when notification is clicked-->   
        <desktop:Extension Category="windows.toastNotificationActivation">
          <desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" />
        </desktop:Extension>

        <!--Register COM CLSID-->    
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:ExeServer Executable="SampleApp\SampleApp.exe" DisplayName="SampleApp" Arguments="----AppNotificationActivated:">
              <com:Class Id="replaced-with-your-guid-C173E6ADF0C3" />
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>
    
      </Extensions>
    </Application>
  </Applications>
 </Package>

Steg 3: Registrera dig för att hantera ett appmeddelande

Registrera din app för att hantera meddelanden och avregistrera sedan när appen avslutas.

I filen App.xaml, registrera AppNotificationManager::Default().NotificationInvoked, och anropa sedan AppNotificationManager::Default().Register. Ordningen på dessa samtal är viktig.

Important

Du måste anropa AppNotificationManager::D efault(). Registrera innan du anropar AppInstance.GetCurrent.GetActivatedEventArgs.

När appen avslutas anropar du AppNotificationManager::D efault(). Avregistrera() för att frigöra COM-servern och tillåta efterföljande anrop för att starta en ny process.

// App.xaml.cs
namespace CsUnpackagedAppNotifications
{

    public partial class App : Application
    {
        private Window mainWindow;
        private NotificationManager notificationManager;
        
        public App()
        {
            this.InitializeComponent();
            notificationManager = new NotificationManager();
            AppDomain.CurrentDomain.ProcessExit += new EventHandler(OnProcessExit);
        }

        protected override void OnLaunched(LaunchActivatedEventArgs args)
        {
            mainWindow = new MainWindow();

            notificationManager.Init();
            
            // Complete in Step 5
            
            mainWindow.Activate();
        }

        void OnProcessExit(object sender, EventArgs e)
        {
            notificationManager.Unregister();
        }
    }
}


// NotificationManager.cs
namespace CsUnpackagedAppNotifications
{
    internal class NotificationManager
    {
        private bool m_isRegistered;

        private Dictionary<int, Action<AppNotificationActivatedEventArgs>> c_map;

        public NotificationManager()
        {
            m_isRegistered = false;

            // When adding new a scenario, be sure to add its notification handler here.
            c_map = new Dictionary<int, Action<AppNotificationActivatedEventArgs>>();
            c_map.Add(ToastWithAvatar.ScenarioId, ToastWithAvatar.NotificationReceived);
            c_map.Add(ToastWithTextBox.ScenarioId, ToastWithTextBox.NotificationReceived);
        }

        ~NotificationManager()
        {
            Unregister();
        }

        public void Init()
        {
            // To ensure all Notification handling happens in this process instance, register for
            // NotificationInvoked before calling Register(). Without this a new process will
            // be launched to handle the notification.
            AppNotificationManager notificationManager = AppNotificationManager.Default;

            notificationManager.NotificationInvoked += OnNotificationInvoked;

            notificationManager.Register();
            m_isRegistered = true;
        }

        public void Unregister()
        {
            if (m_isRegistered)
            {
                AppNotificationManager.Default.Unregister();
                m_isRegistered = false;
            }
        }

        public void ProcessLaunchActivationArgs(AppNotificationActivatedEventArgs notificationActivatedEventArgs)
        {
            // Complete in Step 5
        }

    }
}       

Steg 4: Visa ett appmeddelande

appmeddelande med knapp

Du MÅSTE slutföra steg 3: Registrera dig för att hantera en notis från appen innan du fortsätter.

Nu visas ett enkelt appmeddelande med en appLogoOverride bild och en knapp.

Skapa din appavisering med hjälp av klassen AppNotificationBuilder och anropa sedan Show. Mer information om hur du skapar din appanmälan med XML finns i exemplen på Toast-innehåll och Meddelande XML-schema.

Note

Om din app är paketerad (inklusive paketerad med extern lagring) hämtas appens ikon i meddelandets övre vänstra hörn från package.manifest. Om appen inte är paketerad hämtas ikonen först från genvägen och därefter från resursfilen i appens process. Om alla försök misslyckas används windows-standardappikonen. De ikonfiltyper som stöds är .jpg, .png, .bmpoch .ico.

// ToastWithAvatar.cs
class ToastWithAvatar
{
    public const int ScenarioId = 1;
    public const string ScenarioName = "Local Toast with Avatar Image";

    public static bool SendToast()
    {
        var appNotification = new AppNotificationBuilder()
            .AddArgument("action", "ToastClick")
            .AddArgument(Common.scenarioTag, ScenarioId.ToString())
            .SetAppLogoOverride(new System.Uri("file://" + App.GetFullPathToAsset("Square150x150Logo.png")), AppNotificationImageCrop.Circle)
            .AddText(ScenarioName)
            .AddText("This is an example message using XML")
            .AddButton(new AppNotificationButton("Open App")
                .AddArgument("action", "OpenApp")
                .AddArgument(Common.scenarioTag, ScenarioId.ToString()))
            .BuildNotification();

        AppNotificationManager.Default.Show(appNotification);

        return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }

    public static void NotificationReceived(AppNotificationActivatedEventArgs notificationActivatedEventArgs)
    {
        // Complete in Step 5   
    }
}

// Call SendToast() to send a notification. 

Steg 5: Bearbeta en användare som väljer ett meddelande

Användare kan välja meddelandets brödtext eller knapp. Appen måste bearbeta anropet som svar på att en användare interagerar med ditt meddelande.

Det finns två vanliga sätt att bearbeta detta:

  1. Du väljer att låta din app startas i en specifik användargränssnittskontext ELLER
  2. Du väljer att låta appen utvärdera ett åtgärdsspecifikt beteende (till exempel en knapptryckning i meddelandetexten) utan att återge något användargränssnitt. Kallas även för en bakgrundsåtgärd.

Kodexemplet nedan, som inte kommer från exempelappen, visar båda sätten att bearbeta en användargenererad åtgärd. Lägg till ett launch värde (motsvarar användaren som klickar på meddelandetexten), ett input-element (snabbsvarstextruta) och en knapp med ett arguments värde (motsvarar användaren som klickar på knappen) till xml-nyttolasten för meddelandet. I ditt ProcessLaunchActivationArgs, behandla varje argument.

Important

Inställningen activationType="background" i xml-nyttolasten för meddelanden ignoreras för skrivbordsappar. Du måste i stället bearbeta aktiveringsargumenten och bestämma om du vill visa ett fönster eller inte, enligt vad som anges i det här steget.

App-meddelande med svar

// Example of how to process a user either selecting the notification body or inputting a quick reply in the text box. 

// Notification XML payload
//<toast launch="action=openThread&amp;threadId=92187">
//  <visual>
//      <binding template="ToastGeneric">
//          <image placement="appLogoOverride" hint-crop="circle" src="C:\<fullpath>\Logo.png"/>
//          <text>Local Toast with Avatar and Text box</text>
//          <text>This is an example message using</text>
//      </binding>
//  </visual>
//  <actions>
//      <input id="replyBox" type="text" placeHolderContent="Reply" />
//      <action
//          content="Send"
//          hint-inputId="replyBox"
//          arguments="action=reply&amp;threadId=92187" />
//  </actions>
//</toast>

void ProcessLaunchActivationArgs(const winrt::AppNotificationActivatedEventArgs& notificationActivatedEventArgs)
{
    // If the user clicks on the notification body, your app needs to launch the chat thread window
    if (std::wstring(notificationActivatedEventArgs.Argument().c_str()).find(L"openThread") != std::wstring::npos)
    {
        GenerateChatThreadWindow();
    }
    else // If the user responds to a message by clicking a button in the notification, your app needs to reply back to the other user with no window launched
    if (std::wstring(notificationActivatedEventArgs.Argument().c_str()).find(L"reply") != std::wstring::npos)
    {
        auto input = notificationActivatedEventArgs.UserInput();
        auto replyBoxText = input.Lookup(L"replyBox");

        // Process the reply text
        SendReplyToUser(replyBoxText);
    }
}

Följ riktlinjerna nedan:

  1. Om ett meddelande har valts av användaren och appen inte körs förväntas appen startas och användaren kan se förgrundsfönstret i meddelandets kontext.
  2. Om en avisering väljs av användaren och din app är minimerad, förväntas det att appen åter visas i förgrunden och att ett nytt fönster öppnas i aviseringens kontext.
  3. Om en meddelandebakgrundsåtgärd anropas av användaren (t.ex. användaren svarar på ett meddelande genom att skriva i meddelandetextrutan och trycka på svar) bearbetar appen nyttolasten utan att återge ett förgrundsfönster.

Se exempelappkoden som finns på GitHub- för ett mer detaljerat exempel.

Steg 6: Ta bort meddelanden

Ta bort meddelanden när de inte längre är relevanta för användaren.

I det här exemplet har användaren sett alla meddelanden från en gruppchatt i din app, så du rensar alla meddelanden från gruppchatten. Sedan stänger användaren av en vän så att du rensar alla meddelanden från vännen. Du har först lagt till egenskaperna Group och Tag i meddelandena innan du visar dem för att identifiera dem nu.


void SendNotification(winrt::hstring const& payload, winrt::hstring const& friendId, winrt::hstring const& groupChatId)
{
    winrt::AppNotification notification(payload);

    // Setting Group Id here allows clearing notifications from a specific chat group later
    notification.Group(groupChatId);

    // Setting Tag Id here allows clearing notifications from a specific friend later
    notification.Tag(friendId);

    winrt::AppNotificationManager::Default().Show(notification);
}

winrt::Windows::Foundation::IAsyncAction RemoveAllNotificationsFromGroupChat(const std::wstring groupChatId)
{
    winrt::AppNotificationManager manager = winrt::AppNotificationManager::Default();
    co_await manager.RemoveByGroupAsync(groupChatId);    
}

winrt::Windows::Foundation::IAsyncAction RemoveAllNotificationsFromFriend(const std::wstring friendId)
{
    winrt::AppNotificationManager manager = winrt::AppNotificationManager::Default();
    co_await manager.RemoveByTagAsync(friendId);    
}

Additional features

Skicka ett meddelande från en molnbaserad app

Om du vill skicka ett appmeddelande från molnet följer du Skicka ett appmeddelande från molnkällan i snabbstarten : Push-meddelanden i Windows App SDK.

Ange en förfallotid

Ange en förfallotid för din appavisering med hjälp av egenskapen Expiration om meddelandet i meddelandet endast är relevant under en viss tidsperiod. Om du till exempel skickar en kalenderhändelsepåminnelse anger du förfallotiden till slutet av kalenderhändelsen.

Note

Standard och maximal förfallotid är 3 dagar.

class ToastWithAvatar
{
    public static bool SendToast()
    {

        var appNotification = new AppNotificationBuilder()
            .SetAppLogoOverride(new System.Uri("ms-appx:///images/logo.png"), AppNotificationImageCrop.Circle)
            .AddText("Example expiring notification")
            .AddText("This is an example message")
            .BuildNotification();


        appNotification.Expiration = DateTime.Now.AddDays(1);
        AppNotificationManager.Default.Show(appNotification);

        return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }
}

Se till att meddelanden upphör att gälla vid omstart

Ange egenskapen ExpiresOnReboot till True om du vill att meddelanden ska tas bort vid omstart.

class ToastWithAvatar
{
    public static bool SendToast()
    {

        var appNotification = new AppNotificationBuilder()
            .SetAppLogoOverride(new System.Uri("ms-appx:///images/logo.png"), AppNotificationImageCrop.Circle)
            .AddText("Example ExpiresOnReboot notification")
            .AddText("This is an example message")
            .BuildNotification();


            appNotification.ExpiresOnReboot = true;
            AppNotificationManager.Default.Show(appNotification);

            return appNotification.Id != 0; // return true (indicating success) if the toast was sent (if it has an Id)
    }
}

Skicka och uppdatera ett meddelande i förloppsindikatorn

Du kan visa förloppsindikatorrelaterade uppdateringar i ett meddelande:

meddelande med förloppsindikatorn

Använd AppNotificationProgressData-konstruktion för att uppdatera förloppsindikatorns meddelande.

const winrt::hstring c_tag = L"weekly-playlist";
const winrt::hstring c_group = L"downloads";

// Send first Notification Progress Update
void SendUpdatableNotificationWithProgress()
{
    auto notification{ winrt::AppNotificationBuilder()
            .AddText(L"Downloading this week's new music...")
            .AddProgressBar(winrt::AppNotificationProgressBar()
                .BindTitle()
                .BindValue()
                .BindValueStringOverride()
                .BindStatus())
            .BuildNotification() }

    notification.Tag(c_tag);
    notification.Group(c_group);

    // Assign initial values for first notification progress UI
    winrt::AppNotificationProgressData data(1); // Sequence number
    data.Title(L"Weekly playlist"); // Binds to {progressTitle} in xml payload
    data.Value(0.6); // Binds to {progressValue} in xml payload
    data.ValueStringOverride(L"15/26 songs"); // Binds to {progressValueString} in xml payload
    data.Status(L"Downloading..."); // Binds to {progressStatus} in xml payload

    notification.Progress(data);
    winrt::AppNotificationManager::Default().Show(notification);
}

// Send subsequent progress updates
winrt::Windows::Foundation::IAsyncAction UpdateProgressAsync()
{
    // Assign new values
    winrt::AppNotificationProgressData data(2 /* Sequence number */ );
    data.Title(L"Weekly playlist"); // Binds to {progressTitle} in xml payload
    data.Value(0.7); // Binds to {progressValue} in xml payload
    data.ValueStringOverride(L"18/26 songs"); // Binds to {progressValueString} in xml payload
    data.Status(L"Downloading..."); // Binds to {progressStatus} in xml payload

    auto result = co_await winrt::AppNotificationManager::Default().UpdateAsync(data, c_tag, c_group);
    if (result == winrt::AppNotificationProgressResult::AppNotificationNotFound)
    {
        // Progress Update failed since the previous notification update was dismissed by the user! So account for this in your logic by stopping updates or starting a new Progress Update flow.
    }
}

Resources