Xamarin.iOS の動的な通知アクション ボタン
iOS 12 では、通知は、関連付けられているアクション ボタンを動的に追加、削除、および更新できます。 このようなカスタマイズにより、通知のコンテンツとユーザーの操作に直接関連するアクションをユーザーに提供できます。
サンプル アプリ: RedGreenNotifications
このガイドのコード スニペットは、Xamarin.iOS を使用して iOS 12 の通知アクション ボタンを操作する方法を示すサンプル アプリからのものです。
このサンプル アプリは、赤と緑の 2 種類のローカル通知を送信します。 アプリで通知を送信したら、3D Touch を使用してカスタム ユーザー インターフェイスを表示します。 次に、通知のアクション ボタンを使用して、表示されるイメージを回転させます。 イメージが回転すると、必要に応じて [回転のリセット] ボタンが表示されたり消えたりします。
このガイドのコード スニペットは、このサンプル アプリからのものです。
既定のアクション ボタン
通知のカテゴリによって、既定のアクション ボタンが決まります。
アプリケーションの起動中に通知カテゴリを作成して登録します。
たとえば、サンプル アプリでは、AppDelegate
の FinishedLaunching
メソッドは次の処理を行います。
- 赤の通知用に 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
をその完了ハンドラーに渡します。 これは、通知のインターフェイスが開いたままであることを意味します。