Skip to content

5. Notification with Action

Elvin Thudugala edited this page Mar 29, 2026 · 8 revisions

Notification Actions Guide

This guide explains how to add interactive actions to your local notifications, allowing users to respond directly from the notification. (Available from version 7.0.0 and above)

Table of Contents

  1. Overview
  2. Setting Up Actions
  3. Implementing in .NET MAUI
  4. Android Inline Reply (Direct Reply)
  5. iOS Text Input Actions
  6. iOS Category Options
  7. Handling Action Responses
  8. Platform-Specific Considerations

Overview

Notification actions allow users to interact with your notifications without opening the app. Common use cases include:

  • Accepting/Rejecting invitations
  • Marking tasks as complete
  • Quick replies / inline text input
  • Snoozing reminders

Setting Up Actions

Action Categories

Actions are grouped into categories. Each category can contain multiple actions and is identified by a NotificationCategoryType.

Action Properties

Each action has these key properties:

  • Id: Unique identifier for the action
  • Title: Display text for the action button
  • LaunchAppWhenTapped: Whether to open the app when action is tapped
  • Platform-specific settings for Android (Android) and iOS/macOS (Apple)

.NET MAUI Implementation

1. Configure Actions in MauiProgram.cs

using Plugin.LocalNotification;
using Plugin.LocalNotification.Core.Models;
using Plugin.LocalNotification.Core.Models.AndroidOption;
using Plugin.LocalNotification.Core.Models.AppleOption;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseLocalNotification(config =>
            {
                // Define a Status category with multiple actions
                config.AddCategory(new NotificationCategory(NotificationCategoryType.Status)
                {
                    ActionList = new HashSet<NotificationAction>
                    {
                        // Positive action that launches the app
                        new NotificationAction(100)
                        {
                            Title = "Accept",
                            Android =
                            {
                                LaunchAppWhenTapped = true,
                                IconName = { ResourceName = "accept_icon" }
                            },
                            Apple = { Action = AppleActionType.Foreground }
                        },
                        // Destructive action that doesn't launch the app
                        new NotificationAction(101)
                        {
                            Title = "Decline",
                            Android =
                            {
                                LaunchAppWhenTapped = false,
                                IconName = { ResourceName = "decline_icon" }
                            },
                            Apple = { Action = AppleActionType.Destructive }
                        }
                    }
                });
            });
        return builder.Build();
    }
}

2. Create a Notification with Actions

using Plugin.LocalNotification;
using Plugin.LocalNotification.Core.Models;

var notification = new NotificationRequest
{
    NotificationId = 100,
    Title = "Meeting Invitation",
    Description = "Team meeting at 2 PM",
    CategoryType = NotificationCategoryType.Status  // This links the notification to the action category
};

await LocalNotificationCenter.Current.Show(notification);

Android Inline Reply (Direct Reply)

Android inline reply lets users type a response directly from the notification shade, without opening the app.

1. Add an AndroidActionInput to the action

using Plugin.LocalNotification.Core.Models.AndroidOption;

var replyAction = new NotificationAction(200)
{
    Title = "Reply",
    Android =
    {
        LaunchAppWhenTapped = false,
        Inputs =
        [
            new AndroidActionInput
            {
                Label = "Type your message…",
                AllowFreeFormInput = true,         // allow free-form typing (default)
                // Choices = ["Yes", "No", "Later"] // optional quick-reply chips
            }
        ]
    }
};

2. Register the category

config.AddCategory(new NotificationCategory(NotificationCategoryType.Status)
{
    ActionList = new HashSet<NotificationAction> { replyAction }
});

3. Handle the reply in NotificationActionTapped

When the user sends an inline reply, the typed text is available via e.Input:

private void OnNotificationActionTapped(NotificationActionEventArgs e)
{
    if (e.ActionId == 200 && e.Input is not null)
    {
        // e.Input contains the text the user typed
        Console.WriteLine($"User replied: {e.Input}");
    }
}

AndroidActionInput Properties

Property Type Default Description
Label string "" Hint text shown inside the text field
AllowFreeFormInput bool true Allow free-form typing in addition to choices
Choices string[]? null Pre-defined quick-reply chips shown above the keyboard

iOS Text Input Actions

On iOS and macOS, you can create a text-input action (a UNTextInputNotificationAction) by setting TextInputButtonTitle on an AppleAction. This adds a text field to the notification and displays a send button.

1. Define a text-input action

var replyAction = new NotificationAction(200)
{
    Title = "Reply",
    Apple =
    {
        Action = AppleActionType.Background,
        TextInputButtonTitle = "Send",           // triggers UNTextInputNotificationAction
        TextInputPlaceholder = "Type a message…" // optional placeholder
    }
};

2. Handle the reply

The typed text is available in e.Input, the same property as Android:

private void OnNotificationActionTapped(NotificationActionEventArgs e)
{
    if (e.ActionId == 200 && e.Input is not null)
    {
        Console.WriteLine($"User replied: {e.Input}");
    }
}

AppleAction Properties

Property Type Default Description
Action AppleActionType None Background / Foreground / Destructive
Icon AppleActionIcon System or template icon (iOS 15+)
TextInputButtonTitle string? null When set, creates a text-input action; this value is the send-button label
TextInputPlaceholder string? null Placeholder text for the text field

iOS Category Options

NotificationCategory.AppleOptions maps to UNNotificationCategoryOptions and controls how the category behaves on iOS and macOS.

using Plugin.LocalNotification.Core.Models.AppleOption;

config.AddCategory(new NotificationCategory(NotificationCategoryType.Status)
{
    AppleOptions = AppleCategoryOptions.CustomDismissAction | AppleCategoryOptions.HiddenPreviewShowTitle,
    ActionList = new HashSet<NotificationAction> { /* … */ }
});

AppleCategoryOptions Values

Value iOS Native Description
None No special options (default)
CustomDismissAction CustomDismissAction Fire the dismiss action when the user explicitly dismisses the notification
AllowInCarPlay AllowInCarPlay Allow this category in CarPlay environments
HiddenPreviewShowTitle HiddenPreviewShowTitle Show the notification title even when previews are hidden
HiddenPreviewShowSubtitle HiddenPreviewShowSubtitle Show the notification subtitle even when previews are hidden
AllowAnnouncement AllowAnnouncement Allow Siri to announce the notification (iOS 13+)

Handling Action Responses

Subscribe to Action Events

public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        LocalNotificationCenter.Current.NotificationActionTapped += OnNotificationActionTapped;
        MainPage = new MainPage();
    }

    private async void OnNotificationActionTapped(NotificationActionEventArgs e)
    {
        switch (e.ActionId)
        {
            case 100: // Accept action
                await HandleAcceptAction(e.Request);
                break;

            case 101: // Decline action
                await HandleDeclineAction(e.Request);
                break;

            case 200: // Inline reply (Android or iOS text input)
                if (e.Input is not null)
                    await HandleReply(e.Request, e.Input);
                break;
        }
    }

    private async Task HandleAcceptAction(NotificationRequest request)
    {
        await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            await Shell.Current.DisplayAlert("Action Taken", $"Accepted: {request.Title}", "OK");
        });
    }

    private async Task HandleDeclineAction(NotificationRequest request)
    {
        await LocalNotificationCenter.Current.Cancel(request.NotificationId);
    }

    private async Task HandleReply(NotificationRequest request, string userInput)
    {
        await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            await Shell.Current.DisplayAlert("Reply received", userInput, "OK");
        });
    }
}

Platform-Specific Considerations

Android

  • Action icons must be added to the Android project's drawable resources.
  • Use AndroidActionInput on NotificationAction.Android.Inputs to enable inline reply.
  • The typed text is delivered in NotificationActionEventArgs.Input.
  • On Android 7+ (API 24+), inline replies appear directly in the notification shade.

iOS / macOS

  • Set TextInputButtonTitle on NotificationAction.Apple to activate a text-input action (UNTextInputNotificationAction).
  • The typed text is delivered in NotificationActionEventArgs.Input.
  • Use NotificationCategory.AppleOptions (AppleCategoryOptions flags) to control category-level behaviour such as dismiss actions and CarPlay support.
  • Action types:
    • Foreground: Opens the app
    • Destructive: Red-coloured action for destructive operations
    • Background: Handles action without opening the app

Best Practices

  1. Keep action titles short and clear.

  2. Use meaningful action IDs.

  3. Handle all action responses, including e.Input for reply actions.

  4. Consider platform-specific behaviours when testing.

  5. Test actions in different app states (foreground / background / terminated).

         .UseLocalNotification(config =>
         {
             // Define a Status category with multiple actions
             config.AddCategory(new NotificationCategory(NotificationCategoryType.Status)
             {
                 ActionList = new HashSet<NotificationAction>
                 {
                     // Positive action that launches the app
                     new NotificationAction(100)
                     {
                         Title = "Accept",
                         Android =
                         {
                             LaunchAppWhenTapped = true,
                             IconName = { ResourceName = "accept_icon" }
                         },
                         Apple = { Action = AppleActionType.Foreground }
                     },
                     // Destructive action that doesn't launch the app
                     new NotificationAction(101)
                     {
                         Title = "Decline",
                         Android =
                         {
                             LaunchAppWhenTapped = false,
                             IconName = { ResourceName = "decline_icon" }
                         },
                         Apple = { Action = AppleActionType.Destructive }
                     }
                 }
             });
         });
     return builder.Build();
    

    } }


### 2. Create a Notification with Actions

```csharp
using Plugin.LocalNotification;
using Plugin.LocalNotification.Core.Models;

var notification = new NotificationRequest
{
    NotificationId = 100,
    Title = "Meeting Invitation",
    Description = "Team meeting at 2 PM",
    CategoryType = NotificationCategoryType.Status  // This links the notification to the action category
};

await LocalNotificationCenter.Current.Show(notification);

Xamarin.Forms Implementation

1. Register Action Categories

LocalNotificationCenter.Current.RegisterCategoryList(new HashSet<NotificationCategory>
{
    new NotificationCategory(NotificationCategoryType.Status)
    {
        ActionList = new HashSet<NotificationAction>
        {
            new NotificationAction(100)
            {
                Title = "Accept",
                Apple = { Action = AppleActionType.Foreground }
            },
            new NotificationAction(101)
            {
                Title = "Decline",
                Apple = { Action = AppleActionType.Destructive }
            }
        }
    }
});

Handling Action Responses

1. Subscribe to Action Events

public partial class App : Application
{
    public App()
    {
        InitializeComponent();
        LocalNotificationCenter.Current.NotificationActionTapped += OnNotificationActionTapped;
        MainPage = new MainPage();
    }

    private async void OnNotificationActionTapped(NotificationActionEventArgs e)
    {
        switch (e.ActionId)
        {
            case 100: // Accept action
                await HandleAcceptAction(e.Request);
                break;

            case 101: // Decline action
                await HandleDeclineAction(e.Request);
                break;
        }
    }

    private async Task HandleAcceptAction(NotificationRequest request)
    {
        await MainThread.InvokeOnMainThreadAsync(async () =>
        {
            await Shell.Current.DisplayAlert(
                "Action Taken",
                $"Accepted: {request.Title}",
                "OK");
        });
    }

    private async Task HandleDeclineAction(NotificationRequest request)
    {
        // Cancel the notification
        await LocalNotificationCenter.Current.Cancel(request.NotificationId);
        
        // Additional decline handling logic
    }
}

Platform-Specific Considerations

Android

  • Action icons must be added to the Android project's drawable resources
  • Actions can be configured to launch the app or handle in the background
  • Consider using appropriate icon resources for actions

iOS

  • Supports different action types:
    • Foreground: Opens the app
    • Destructive: Red-colored action for destructive operations
    • Background: Handles action without opening app
  • Actions appear in the expanded notification view

Best Practices

  1. Keep action titles short and clear
  2. Use meaningful action IDs
  3. Handle all action responses appropriately
  4. Consider platform-specific behaviors
  5. Test actions in different app states (foreground/background)

Visual Examples

Android Notification Actions

Android Notification Action

iOS Notification Actions

iOS Notification Action

Clone this wiki locally