次の方法で共有


Xamarin.iOS の動的な通知アクション ボタン

iOS 12 では、通知は、関連付けられているアクション ボタンを動的に追加、削除、および更新できます。 このようなカスタマイズにより、通知のコンテンツとユーザーの操作に直接関連するアクションをユーザーに提供できます。

サンプル アプリ: RedGreenNotifications

このガイドのコード スニペットは、Xamarin.iOS を使用して iOS 12 の通知アクション ボタンを操作する方法を示すサンプル アプリからのものです。

このサンプル アプリは、赤と緑の 2 種類のローカル通知を送信します。 アプリで通知を送信したら、3D Touch を使用してカスタム ユーザー インターフェイスを表示します。 次に、通知のアクション ボタンを使用して、表示されるイメージを回転させます。 イメージが回転すると、必要に応じて [回転のリセット] ボタンが表示されたり消えたりします。

このガイドのコード スニペットは、このサンプル アプリからのものです。

既定のアクション ボタン

通知のカテゴリによって、既定のアクション ボタンが決まります。

アプリケーションの起動中に通知カテゴリを作成して登録します。 たとえば、サンプル アプリでは、AppDelegateFinishedLaunching メソッドは次の処理を行います。

  • 赤の通知用に 1 つのカテゴリを定義し、緑の通知用にもう 1 つのカテゴリを定義します
  • 以下を呼び出して、これらのカテゴリを登録します: UNUserNotificationCenter の SetNotificationCategories メソッド
  • 単一の UNNotificationAction を各カテゴリにアタッチします

このしくみを示すサンプル コードを次に示します。

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
    // Request authorization to send notifications
    UNUserNotificationCenter center = UNUserNotificationCenter.Current;
    var options = UNAuthorizationOptions.Alert | UNAuthorizationOptions.Sound | UNAuthorizationOptions.Provisional | UNAuthorizationOptions.ProvidesAppNotificationSettings;
    center.RequestAuthorization(options, (bool success, NSError error) =>
    {
        // ...
        var rotateTwentyDegreesAction = UNNotificationAction.FromIdentifier("rotate-twenty-degrees-action", "Rotate 20°", UNNotificationActionOptions.None);

        var redCategory = UNNotificationCategory.FromIdentifier(
            "red-category",
            new UNNotificationAction[] { rotateTwentyDegreesAction },
            new string[] { },
            UNNotificationCategoryOptions.CustomDismissAction
        );

        var greenCategory = UNNotificationCategory.FromIdentifier(
            "green-category",
            new UNNotificationAction[] { rotateTwentyDegreesAction },
            new string[] { },
            UNNotificationCategoryOptions.CustomDismissAction
        );

        var set = new NSSet<UNNotificationCategory>(redCategory, greenCategory);
        center.SetNotificationCategories(set);
    });
    // ...
}

このコードに基づいて、Content.CategoryIdentifier の通知が "red-category" または "green-category" の場合、既定で Rotate 20° アクション ボタンが表示されます。

通知アクション ボタンのアプリ内処理

UNUserNotificationCenter には IUNUserNotificationCenterDelegate 型の Delegate プロパティがあります。

サンプル アプリで、AppDelegate はそれ自体を FinishedLaunching のユーザー通知センターの委任として設定します。

public override bool FinishedLaunching(UIApplication application, NSDictionary launchOptions)
{
    // Request authorization to send notifications
    UNUserNotificationCenter center = UNUserNotificationCenter.Current;
    var options = // ...
    center.RequestAuthorization(options, (bool success, NSError error) =>
    {
        center.Delegate = this;
        // ...

次に、AppDelegate で次を実装します: アクション ボタン タップを処理するための DidReceiveNotificationResponse:

[Export("userNotificationCenter:didReceiveNotificationResponse:withCompletionHandler:")]
public void DidReceiveNotificationResponse(UNUserNotificationCenter center, UNNotificationResponse response, System.Action completionHandler)
{
    if (response.IsDefaultAction)
    {
        Console.WriteLine("ACTION: Default");
    }
    if (response.IsDismissAction)
    {
        Console.WriteLine("ACTION: Dismiss");
    }
    else
    {
        Console.WriteLine($"ACTION: {response.ActionIdentifier}");
    }

    completionHandler();
        }

この DidReceiveNotificationResponse の実装は通知の Rotate 20° アクション ボタンを処理しません。 代わりに、通知のコンテンツ拡張機能は、このボタンのタップを処理します。 次のセクションでは、通知アクション ボタンの処理の詳細について説明します。

通知コンテンツ拡張機能のアクション ボタン

通知コンテンツ拡張機能には、通知のカスタム インターフェイスを定義するビュー コントローラーが含まれています。

このビュー コントローラーでは、次の GetNotificationActions メソッドと SetNotificationActions メソッドを使用できます: 通知のアクション ボタンにアクセスして変更するための ExtensionContext プロパティ。

サンプル アプリでは、通知コンテンツ拡張機能のビュー コントローラーは、既存のアクション ボタンのタップに応答する場合のみアクション ボタンを変更します。

Note

通知コンテンツ拡張機能は、IUNNotificationContentExtension の一部として宣言された、ビュー コントローラーの DidReceiveNotificationResponse メソッド内のアクション ボタン タップに応答することができます。

前述DidReceiveNotificationResponse メソッドと名前を共有しますが、これは別のメソッドです。

通知コンテンツ拡張機能がボタン タップの処理を完了した後、同じボタン タップを処理するようにメイン アプリケーションに指示するかどうかを選択できます。 これを行うには、UNNotificationContentExtensionResponseOption の適切な値を完了ハンドラーに渡す必要があります。

  • Dismiss は、通知インターフェイスを無視する必要があり、メイン アプリがボタン タップを処理する必要がないことを示します。
  • DismissAndForwardAction は、通知インターフェイスを無視する必要があり、メイン アプリもボタン タップを処理する必要があることを示します。
  • DoNotDismiss は、通知インターフェイスを無視する必要がなく、メイン アプリがボタン タップを処理する必要がないことを示します。

コンテンツ拡張機能の DidReceiveNotificationResponse メソッドは、タップされたアクション ボタンを決定し、通知のインターフェイスでイメージを回転させ、[リセット] アクション ボタンを表示または非表示にします。

[Export("didReceiveNotificationResponse:completionHandler:")]
public void DidReceiveNotificationResponse(UNNotificationResponse response, Action<UNNotificationContentExtensionResponseOption> completionHandler)
{
    var rotationAction = ExtensionContext.GetNotificationActions()[0];

    if (response.ActionIdentifier == "rotate-twenty-degrees-action")
    {
        rotationButtonTaps += 1;

        double radians = (20 * rotationButtonTaps) * (2 * Math.PI / 360.0);
        Xamagon.Transform = CGAffineTransform.MakeRotation((float)radians);

        // 9 rotations * 20 degrees = 180 degrees. No reason to
        // show the reset rotation button when the image is half
        // or fully rotated.
        if (rotationButtonTaps % 9 == 0)
        {
            ExtensionContext.SetNotificationActions(new UNNotificationAction[] { rotationAction });
        }
        else if (rotationButtonTaps % 9 == 1)
        {
            var resetRotationAction = UNNotificationAction.FromIdentifier("reset-rotation-action", "Reset rotation", UNNotificationActionOptions.None);
            ExtensionContext.SetNotificationActions(new UNNotificationAction[] { rotationAction, resetRotationAction });
        }
    }

    if (response.ActionIdentifier == "reset-rotation-action")
    {
        rotationButtonTaps = 0;

        double radians = (20 * rotationButtonTaps) * (2 * Math.PI / 360.0);
        Xamagon.Transform = CGAffineTransform.MakeRotation((float)radians);

        ExtensionContext.SetNotificationActions(new UNNotificationAction[] { rotationAction });
    }

    completionHandler(UNNotificationContentExtensionResponseOption.DoNotDismiss);
}

この場合、メソッドは UNNotificationContentExtensionResponseOption.DoNotDismiss をその完了ハンドラーに渡します。 これは、通知のインターフェイスが開いたままであることを意味します。