次の方法で共有


Windows 8.1

Windows 8.1 でアラーム アプリをビルドする

Tony Champion

Windows 8.1 の多くの新機能の中に、アラーム アプリという考え方があります。簡単に言えば、アラーム アプリとは、トースト通知のスケジュールを秒単位に設定できる Windows ストア アプリです。トースト通知が Windows によって処理される方法が原因で、ほとんどのアプリのトースト通知はそれほど精度が高くありません。今回は、このアラーム アプリの考え方を調べ、アラーム アプリを独自に開発するために必要な事柄を見ていきます。

アラーム アプリとは

アラーム アプリのしくみを見る前に、優れたアラーム アプリとはどのようなアプリかを考えることが重要です。鍵になるのは通知を配信する精度です。たとえばカレンダー アプリでは、友人の誕生日を正確に秒単位で通知することは求められません。しかし、秒単位の精度が必要なアプリもあります。

最も顕著に精度が求められるのは昔ながらの目覚まし時計アプリです。ユーザーがアラームをセットしたら、ちょうどその時間に知らせる必要があります。アラーム アプリにより、より精度の高い時間管理アプリ (Pomodoro アプリなど) を作成できるようになります。また、トレーニングと休憩のタイミングが非常に重要な、短いインターバル トレーニング アプリ (Tabata など) にもアラーム アプリを利用できます。

Windows ストア アプリの開発者はすべて、Windows 8 のロック画面アプリの考え方にも慣れてください。ロック画面上に配置されるアプリは、ロック画面に更新を投稿できます。また、ロック画面アプリは、標準アプリよりも多くの機能にアクセスできます。アプリでロック画面を更新したり、利用可能なバックグラウンド タスクを多数実行する必要がある場合は、このロック画面アプリが重要になります。

パーフォーマンスを向上し、バッテリ寿命を延ばすには、ロック画面アプリに機能を追加する必要があり、その結果 Windows 8 に直接変更が加えられました。Windows は、アプリが使用されていないときはそのアプリを実行しないようにし、極力タスクを統合するように設計されています。そのため、バックグラウンド タスクや通知などの定期イベントは、常におおよその時間で実行されることになります。Windows では、このような更新がひとまとめにされ、プロセスの実行準備が整ったときに実行されます。

Windows 8 では、ある特定の時間にロック画面上に最高 7 つのアプリを定義でき、この 7 つのスロットには、詳細ステータス アプリ用に特殊なスロットが 1 つ含まれていました。デバイスにはバッジやテキストを表示できるロック画面アプリを 7 つ定義できるとしても、ロック画面にカスタム UI を提供できるアプリは 1 つだけです。Windows 8.1 でもこの設定は維持されますが、特別な種類のロック画面アプリとして新しくアラーム アプリが追加されます。図 1に示したのは [PC 設定] 画面の新しい [ロック画面に表示するアプリ] 設定機能です。詳細ステータスを表示するアプリ同様、各デバイスで同時に表示できるアラーム アプリは 1 つだけです。


図 1 [PC 設定] のロック画面設定

アラーム アプリと他のロック画面アプリの唯一の違いは、スケジュールを設定した配信時間になったら、ユーザーにアラーム トースト通知を提供する機能です。前述のように、Windows ストア アプリでトーストの送信やスケジュール設定を行っても、そのトーストが配信されるタイミングは保証されません。おおよその時間帯では配信されますが、正確な時間は Windows しだいです。ユーザーがアプリをアラーム アプリに指定した場合、スケジュールが設定されたトーストが時間どおりに正確に配信されます。

アラーム アプリを設定する

アプリのマニフェストを適切に構成しなければ、そのアプリはアラーム アプリとして選択できません。マニフェストに必要な機能が含まれていなければ、コード内でアプリをアラーム アプリに設定しようとしてもエラーが発生し、ユーザーがそのアプリを手動でアラーム アプリに設定するオプションはありません。

アラーム アプリはトーストのスケジュールを設定するので、まずはアプリケーション マニフェスト デザイナーの [アプリケーション UI] タブでトーストを有効にする必要があります。[トースト対応] ボックスが [ビジュアル資産] の下の [通知] セクションにあり、その [通知] セクションは [すべてのイメージ資産] および [バッジ ロゴ] サブグループにあります。そのアプリのトーストを有効にするには [トースト対応] ボックスを [はい] に設定します。

[通知] セクションのプロパティには、アプリのロック画面通知を有効にするプロパティもあります。前述のとおり、アラーム アプリは特別な種類のロック画面アプリなので、ロック画面に表示されるようにも構成する必要があります。[ロック画面通知] ボックスを [バッジ] または [バッジとタイル テキスト] のどちかに設定します。

アプリのロック画面通知を有効にしたら、マニフェストにいくつか項目を追加する必要があります。たとえば、アプリにバッジ ロゴを割り当てなくてはなりません。バッジ ロゴは 24 x 24 ピクセルの画像にする必要があり、Windows ストア アプリのすべてのロゴと同様、さまざまなスケール サイズを指定して Windows の解像度のスケール変化に対応できます。図 2は、トーストとロック画面通知を有効にしているアプリケーション マニフェスト デザイナーの例です。


図 2 アプリケーション マニフェスト デザイナーの [通知] セクション

アプリのロック画面通知を有効にしたら、そのアプリのマニフェストでバックグラウンド タスクを宣言することも必要です。この要件の興味深いところは、必要なのは宣言だけで、ロック画面アプリのバックグラウンド タスクを実際に実装する必要がないことです。

バックグラウンド タスクはアプリケーション マニフェスト デザイナーの [宣言] セクションで宣言します。[使用可能な宣言] ボックスで [バックグラウンド タスク] を選択して、[追加] をクリックします。ロック画面アプリのバックグラウンド タスクでは、コントロール チャネル、タイマー、プッシュ通知、または位置情報というタスクの種類のうちいずれかをサポートする必要があります。バックグラウンド タスクの [アプリケーションの設定] セクションでは、[エントリ ポイント] 値か [スタート ページ] 値のどちらかを設定します。バックグラウンド タスクを使用する XAML アプリでは、[エントリ ポイント] を IBackgroundTask インターフェイスを実装するクラスに設定します。アプリで実際にはバックグラウンド タスクを実行しない場合は、この値には任意の値を設定できます。図 3は、アプリをロック画面に追加できる適切なバックグラウンド タスクの構成を示しています。


図 3 [バックグラウンド タスク] の構成

アプリのマニフェスト構成の最後の手順は、アプリをアラーム アプリに指定することです。これを行うには、マニフェストにアラーム拡張を追加します。ただし、残念ながら、アプリケーション マニフェスト デザイナーでこの拡張を追加することはできません。手動で追加する必要があります。このためには、まずパッケージ マニフェストの基盤となる XML に手を加えます。そのためには、ソリューション エクスプローラーで [package.appxmanifest] を右クリックして、[コードの表示] をクリックします。

Windows 8.1 アプリ マニフェストの XML では 2 つの名前空間を使用します。最初の名前空間 (既定の名前空間) は、Windows 8 で定義される要素を含みます。プレフィックス m2 で識別される 2 つ目の名前空間を追加する必要があり、この名前空間は Windows 8.1 で行われた追加と変更を含みます。アラーム アプリ機能は Windows 8.1 で始めて導入されたため、Application 要素内の Extensions コレクションに "8.1" 拡張を追加する必要があります。この新しい拡張の Category プロパティに windows.alarm を設定します。以下は、新しい拡張と先ほど宣言したバックグラウンド タスクを指定した Extensions コレクションの例です。

アラームへのアクセス許可を要求する

適切な設定と宣言を行ったら、アプリをデバイスのアラーム アプリとして設定するためのアクセス許可を要求することができます。ユーザーは [PC 設定] から手動でこの要求を行うことができます。しかしアプリの場合は、Windows ランタイム (WinRT) 経由でアクセス許可を要求します。

Windows ランタイムの Windows.ApplicationModel.Background 名前空間に静的 AlarmApplicationManager クラスが含まれています。このクラスには、アプリをデバイスのアラーム アプリとして設定する許可をユーザーに求める RequestAccessAsync メソッドがあります (図 4 参照)。別のアプリが現在アラーム アプリに指定されている場合、ユーザーが [はい] をクリックすると、現在のアプリから置き換わります。


図 4 アラーム アプリのアクセス許可要求

RequestAccessAsync メソッドは、Denied、AllowedWithWakeupCapability、AllowedWithoutWakeupCapability という 3 つの有効な値を持つ AlarmAccessStatus 列挙型を返します。目覚まし時計のアラームを鳴らすなど、アラーム アプリを作成する場合は、このメソッドが返す値が重要になります。デバイスがスリープ モードのときにトースト通知によってデバイスを起動できる構成になっていなければ、アラームは発生しません。

Windows 8 ではデバイスの管理権限はユーザーにありました。図 1に示したように、ユーザーは簡単にアラーム アプリを変更できます。問題になるのは、各アプリが AlarmApplicationManager クラスからアクセス許可を要求できるのは 1 回だけという点です。同じユーザーとデバイスに対してアプリから 2 回目のアクセス許可の要求を行うと、ユーザーに許可を求めるのではなく、アプリの現在のアラーム ステータスが返されるだけです。アプリのステータスとして Denied が返る場合、アラーム アプリが別のアプリに置き換えられている場合、またはユーザーがアラーム アプリの設定を手動で解除している場合、実行できる選択肢は、アプリをそのデバイスのアラーム アプリに手動で戻すようにユーザーに依頼することだけです。

AlarmApplicationManager クラスには、コンピューターの現在のアラーム ステータスを返す GetAccessStatus メソッドもあります。RequestAccessAsync メソッド同様、GetAccessStatus メソッドは AlarmAccessStatus 列挙型を返すため、このメソッドでもデバイスの状況をは判断できます。たとえば、通知によってデバイスが起動されないことをアプリからユーザーに通知できます。

アラームのスケジュールを設定する

アラームとは、実際には少し機能が加わった定期トースト通知にすぎません。アラームのスケジュールを設定するプロセスは、トースト通知のスケジュール設定とまったく同じで、唯一の違いは通知 XML です。通知の定義に使用する XML には、含めるすべての機能についての情報と、外観についての情報を設定します。

トーストは Windows ランタイムが用意するテンプレートの 1 つを使って定義することにより、単なるテキスト、またはテキストと画像の組み合わせになります。現在 8 つの異なる XML テンプレートがあり、開発者はその中から使用するテンプレートを選択できます。この記事の執筆時点では、Windows 8.1 はカスタム トースト レイアウトをサポートしていないため、開発者は用意されているテンプレートのいずれかを選択する必要があります。

トーストの種類とレイアウトは XML の 1 つのブロック内に定義します。XML では、使用するトースト テンプレート、そのテンプレートに設定するテキストと画像、および後ほど説明するオプションをいくつか指定します。以下に基本的なトースト通知の例を示します。

Sample Toast App
       The is a sample message.

トースト テンプレートを生成する方法はいくつかあります。Windows ランタイムでは、ToastNotificationManager を使用して各テンプレートの XmlDocument を作成します。ToastNotificationManager は Windows.UI.Notification 名前空間にあります。ToastNotificationManager には、利用可能な各テンプレートに対応する値を含む ToastTemplateType 列挙型を受け取る静的 GetTemplateContent メソッドがあります。以下は先ほどの例の XmlDocument の取得方法の例です。

XmlDocument content =
   ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText02);
 content.DocumentElement.SetAttribute("duration", "long");
 var textLines = content.GetElementsByTagName("text");
 textLines[0].InnerText = "Sample Toast App";
 textLines[1].InnerText = "The is a sample message.";

これは出発点として優れていますが、用途によっては、やや面倒になることがあります。テンプレートへの追加や修正を通常 XmlDocument API を使用して行う理由はここにあります。ほんの少しの追加が非常に大量のコードになることがあります。このようなことから、テンプレートを完成後文字列として構築し、XmlDocument に読み込む XML を探すのも珍しいことではありません。図 5 は、文字列として XML を生成して、先ほどの例と同じトーストを実現する方法を示します。

図 5 XML を文字列として生成

string textLine1 = "Sample Toast App";
 string textLine2 = "This is a sample message.";
 string contentString =
   "\n" +
     "\n" +
       "\n" +
         "" + textLine1 + "\n" +
         "" + textLine2 + "\n" +
       "\n" +
     "\n" +
   "\n";
 XmlDocument content = new Windows.Data.Xml.Dom.XmlDocument();
 content.LoadXml(contentString);

この方法を採用する場合、2 つのことに注意します。第 1 に、必ず正しい形式の XML を生成します。文字列に含まれる特殊文字はすべてエスケープするように注意します。第 2 に、必ずトースト通知のスキーマに従います。このスキーマの完全な仕様については、Windows デベロッパー センター (bit.ly/172oYCO、英語) を参照してください。

上記の例にはすべて、既定のテンプレートには含まれていない要素が 1 つ含まれています。それは toast 要素の duration 属性です。値は long に設定されています。アラーム トースト通知を作成している場合、表示後にユーザーの操作なしでアラームが消えるのは好ましくありません。duration を long に設定すると、トーストは最長 25 秒間画面上に維持されます。

XML の構成を終え、XmlDocument に読み込んだら、トーストのスケジュールを設定できます。まず、ScheduledToastNotification のインスタンスを作成します。ScheduledToastNotification の作成には、トースト定義を含む XmlDocument とそのトーストのスケジュールに設定する時間の 2 つが必要です。

ScheduledToastNotification は ToastNotifier を使用してスケジュールが設定されます。ToastNotifier のインスタンスは ToastNotificationManager クラスの静的 CreateToastNotifier メソッドを使用して作成します。ToastNotifier の AddToSchedule メソッドを呼び出すことで、トーストの配信スケジュールを設定します。トーストは通常、ボタンのクリックなどのなんらかのユーザー アクション、またはアプリ内で発生したイベントの結果として作成されます。以下はトーストを作成して現在時刻の 1 分後にスケジュールを設定する例です。

ToastNotifier toastNotifier =
   ToastNotificationManager.CreateToastNotifier();
 var scheduledToast = new ScheduledToastNotification(
   content, DateTime.Now.AddMinutes(1));
 toastNotifier.AddToSchedule(scheduledToast);

ここで生成したトーストの出力結果を図 6 に示します。Windows で一般的なトーストとよく似ています。


図 6 基本的なトースト通知

トースト通知はいくつかの異なる理由で失敗することがあります。最もよくある理由は XML の形式が不適切なことです。これは、テンプレート ID が間違っていたり、必要な属性がすべて定義されていないことが原因になる可能性が高いため、必ず XML の形式が正しいことを確認します。

既に過ぎた時間にトーストのスケジュールを設定しようとすると、AddToSchedule の呼び出し時に例外がスローされます。トーストのスケジュールを数秒後に設定する場合、時間計算は設定作業の最後に行うようにします。時間を現在から 2 秒後に設定してから、トーストのスケジュール設定を実際に終えるのに 4 秒かかると、例外がスローされます。

最後に、アプリから同時にスケジュールを設定できるトーストは 4,096 個のみです。「4,096 個もあれば十分だと」まず考えるかもしれませんが、アラーム アプリでは考えているより簡単にこのような状況が起こります。毎日ユーザーにアラームを通知するようにスケジュールを設定しているアラーム アプリがあるとします。翌年毎日複数回のアラームを通知するようにスケジュールを設定すると、1 日あたり 12 個のアラームで限界に達します。つまり、アラームのスケジュールを設定するアルゴリズムをしっかりと考え、作成後はそのアラームを管理する必要があります。

アラームの管理と削除

アラーム アプリを正しくビルドするには、スケジュールが設定されているアラームを確認して削除する機能が必要です。確認と削除はどちらも、ToastNotifier を使って実現します。GetScheduledToastNotifications メソッドを呼び出すと、ScheduledToastNotifications の読み取り専用の一覧が返されます。このコレクションには現在のアプリの通知だけが含まれます。

スケジュールが設定された通知を削除するには、削除する通知を RemoveFromSchedule メソッドに渡します。一覧を取得してから削除するまでの間、スケジュールが設定されている通知を管理できます。投稿されている通知がユーザーによって閉じられると、アプリのコレクションには含まれなくなり、通知の許容最大数には数えられません。以下に、スケジュールが設定されている通知をすべて削除する方法を示します。

var toastNotifier = ToastNotificationManager.CreateToastNotifier();
 var notifications = toastNotifier.GetScheduledToastNotifications();
 // Remove each notification from the schedule
 foreach (var notification in notifications)
 {
   toastNotifier.RemoveFromSchedule(notification);
 }

たとえば、このコードを、[すべて削除] ボタンに関連付けらているコマンドやイベント ハンドラーに配置します。

コマンドを追加する

アプリが現在デバイスのアラーム アプリである場合、トーストを生成した先ほどの例 (図 6) は時間どおりに表示されます。しかし図 6 はあまりアラームらしく見えません。第 1 に、アラームに共通する再通知と解除の機能が欠けています。既定では、クリックするかスワイプすればアラームは解除されますが、もう少しわかりやすい操作にする必要があります。

要素は 子要素に加え 要素もサポートします。この要素では、定義済みのコマンドをトーストに追加できます。要素自体は、オプションとして scenario 属性だけをサポートします。scenario 属性には alarm または incomingCall のどちらかを設定できます。今回の目的では alarm に設定します。

要素には個別の 要素のコレクションを含めます。各コマンドにはどの種類のコマンドなのかを識別する id 属性が必要です。アラームの場合、この id 属性は snooze または dismiss のどちらかにする必要があります。先ほどのトーストに commands セクションを追加すると、トーストがもう少しアラームらしくなり、解除機能と再通知機能が備わります。以下は新しく生成したトースト コードです (このコードの出力結果が図 7 です)。

Sample Toast App
       The is a sample message.


図 7 アラーム トースト通知

再通知を設定する

Windows ではアラームの再通知時間の既定値は 9 分です。ただし、ScheduledToastNotification クラスでこの再通知時間を定義できます。このクラスには、2 つの追加パラメーターを受け取る 2 つ目のコンストラクターがあります。1 つ目の追加パラメーターは、再通知までの時間です。再通知の間隔は TimeSpan で定義し、1 ~ 60 分までの範囲で設定できます。

2 つ目の追加パラメーターは、ユーザーがアラームの再通知をクリックできるあ最大回数です。この値をゼロに設定すると、ユーザーは再通知を何回でもクリックできます。以下に再通知の頻度を設定する例を示します。

DateTime scheduledTime = DateTime.Now.AddMinutes(1);
 TimeSpan snoozeInterval = TimeSpan.FromMinutes(5);
 var scheduledToast = new ScheduledToastNotification(
   content, scheduledTime, snoozeInterval, 0);

アラームの音を変更する

ユーザーが通知音を有効にしていると、各トーストのトースト メッセージが表示されるときに、"ベル" 音が再生されます。これはアラーム アプリを作成するときにやや問題になります。第 1 に、ユーザーはすべての通知で同じ音を聞いているので慣れています。つまり、アラームが他の通知音にまぎれて際立たなくなります。第 2 に、通常、アラームはユーザーが認識するまで音を鳴らし続けます。そのため、アラーム音にはなんらかのループ処理が求められます。

さいわい、トースト定義ではトーストが表示時の再生音をカスタマイズできる 要素もサポートします。 要素には src と loop という 2 つの属性があります。音をカスタマイズできるといっても、src 属性の値は Windows が用意している定義済みの値のいずれかにしなければなりません。つまり、トースト通知にカスタム オーディオを提供することはできません。ただし、優れた音のコレクションが用意されていてそこから選択できます。

src の値は 25 種類の定義済み値のいずれかにする必要があります。定義済みの音はループするものと、ループしないものに分けられます。ループする音はシームレスにループするように構築されていて、ループするオーディオ通知を作成する際に使用します。ループするアラーム音が 10 種類あり、ループする着信音が 10 種類あります。定義済み音の完全な一覧については、bit.ly/16HV2xm(英語) を参照してください。

ループ音を再生するには loop 属性を true に設定します。また、音の再生時間を指定するには 要素の duration 属性を long に設定します。図 8 に、トーストにカスタム ループ音を設定する例を示します。

図 8 トーストのカスタム ループ音の設定

Sample Toast App
       The is a sample message.

トーストで音を再生しない場合は、silent 属性を true に設定します。この設定は、トーストの表示に関するあらゆる既定の設定よりも優先されます。図 9 にその使用方法を示します。

図 9 トーストで音を再生しないように silent 属性の設定

Sample Toast App
       The is a sample message.

追加機能について考える

アラーム アプリにはさまざまな使い途があります。各デバイスで使用できるアラーム アプリは 1 つだけなので、開発しているアプリ以外のアプリについても考えておく必要があります。アプリのスコープを限定しすぎると、ユーザーが別のアプリに置き換える可能性があります。これは、もちろん、アプリの目的と対象とするユーザーによります。他のアプリからもアラームのスケジュールを設定できるように、アプリから共有ターゲット コントラクトを使用することも検討します。

Windows 8.1 にアラーム アプリ機能が追加されたことにより、ユーザーが期待する時間の精度で広範なアプリを作成できるようになります。今回は、アラーム アプリについて把握しておくべき情報とその実行について説明しました。再通知ボタンをクリックするのを止め、目を覚まして、魅力的なアラーム アプリを作成してください。

Tony Champion は、Champion DS の代表取締役で、Microsoft MVP でもあります。彼は、講演、ブログ、書籍の執筆を通じて積極的にコミュニティに貢献しています。彼のブログは tonychampion.net(英語) から、電子メールは tony@tonychampion.net(英語のみ) にお送りください。

この記事のレビューに協力してくれた技術スタッフの Pete Brown (マイクロソフト) に心より感謝いたします。
Pete Brown はクライアントおよびデバイス エバンジェリズム チームのプログラム マネージャーで、あらゆる Windows デバイスで最新の XAML アプリを重点的に扱っています。彼の専門は、開発者が魅力的で、質が高く、想像力をかきたてるアプリをビルドするのをサポートすることです。彼の Twitter アカウントは @pete_brownで、Web は 10rem.net(英語) です。