酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

Azure Mobile Services(Azureモバイルサービス)の通知ハブに登録されているデバイス情報を取得する

とあるアプリのプッシュ通知の送信プラットフォームには、Azure Mobile Service(Azure モバイルサービス)を使っています。正確には、モバイルサービスを構成するうちのひとつのNotification Hub(通知ハブ)ですね。

iOSとWindows Phone(WinRTアプリ)を使って、プッシュ通知を受ける方法は過去に紹介したことがあります。

本記事では通知ハブに登録されているデバイス情報を取得する方法を紹介します。

事前準備

NuGet経由でMicrosoft Azure Service Busをインストールしておいてください。

通知ハブに登録されているすべてのデバイスを取得する

通知ハブにおける操作をおこなうには、NotificationHubClientクラスを使用します。

NotificationHubClientクラスのインスタンスを生成するには、接続文字列と通知ハブ名、そして環境がテスト環境であるか*1どうかを指定します。

// 接続文字列
var connnectionString = "Endpoint=sb://example-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=<your key>";

// ハブ名
var hubName = "<your hub name>";

// テスト送信か?
// Production(本番)にプッシュ通知を送信する場合は false
// Development(開発)にプッシュ通知を送信する場合は true
var enableTestSend = false;

// 接続文字列からNotificationHubClientオブジェクトを生成する
var hubClient = NotificationHubClient.CreateClientFromConnectionString(
    connnectionString, hubName, enableTestSend);

// 登録されているすべてのデバイスを取得する
var allRegistrations = await client.GetAllRegistrationsAsync(0);

上記のコードを実行してみると分かるのですが、デバイス情報は100件ずつしか取り出すことができません。

100件以降のデバイス情報を取得する場合にはContinuationTokenを指定して、続きからデバイス情報を取得する必要があります。100件ずつの取得を続けてContinuationTokenがnullを返すまで取得し続けることで登録されているデバイス情報を全件取得することが可能です。

つまり処理としては以下のようになります。

var devices = new List<RegistrationDescription>();

var token = default(string);
do {
    // 登録されているすべてのデバイスを取得する(実際には100件)
    var reg = await hubClient.GetAllRegistrationsAsync(token, 0);
    token = reg.ContinuationToken;

    devices.AddRange(reg);
} while (token != null);

通知ハブに登録されているiOSデバイスを取得する

通知ハブに登録されているデバイスのうち、iOSデバイスのみを取得しましょう。

登録されているデバイスがiOSデバイスかどうかを判別するにはオブジェクトがAppleRegistrationDescriptionクラスであるかどうかを調べます。

var devices = new List<RegistrationDescription>();

var token = default(string);
do {
    // 登録されているすべてのデバイスを取得する(実際には100件)
    var reg = await hubClient.GetAllRegistrationsAsync(token, 0);
    token = reg.ContinuationToken;

    // 取得した中からAppleデバイスのみを取得する
    devices.AddRange(reg.Where(r => r is AppleRegistrationDescription));
} while (token != null);

Android(Google)の場合はGcmRegistrationDescription、Amazonの場合はAdmRegistrationDescription、Windowsの場合はWindowsRegistrationDescriptionを指定すればよいと思います。

特定のタグを付与されているデバイス情報を取得する

タグに紐付いているデバイス情報を取得するにはGetRegistrationsByTagAsyncメソッドを使うことができます。

var tag = "userid:ch3cooh";

var count = 0;

var token = default(string);
do {
    // 通知ハブから取得する
    var reg = await hubClient.GetRegistrationsByTagAsync(tag, token, 0);

    token = reg.ContinuationToken;

    // 登録デバイス数を加算する
    count += reg.Count();

} while (token != null);

*1:iOSでいうところのProductionとDevelopmentに相当

Visual StudioのデータベースデザイナーでAzureのSQL Databaseにタイムアウトで接続できない問題

AzureのSQLデータベースで「VISUAL STUDIOで開く」をクリックすると、通常Visual Studioが起動してデータベースデザイナーが表示されます。

んで最近以下のように読み込み中に問題が発生するようになってしまった。

読み込み中の問題
デザイナーで、テーブル定義を読み込み中にエラーが発生しました。

少し前(2,3ヶ月くらい前?)までは発生していなかった記憶があるけどエビデンスが残っていないので正確な時期は分からない。たまに成功するときもあるんだけど大抵は失敗してしまう。今日まで問題解決できていない。

エラー 1 ターゲット データベース スキーマを取得できませんでした。データベースに再接続できません: Timeout に達しました。操作が完了する前にタイムアウト期間が過ぎたか、またはサーバーが応答していません。 hoge_db 0 0

エラー 2 データベース xxxxxxxxx.database.windows.net.hoge_db からスキーマ情報を取得できませんでした。 このデータベースに対して開いているエディターを閉じ、このデータベースへの接続を確認し、サーバー エクスプローラーでデータベースを更新してください。 hoge_db 0 0

No1さん(@kosmosebi)に「タイムアウトを伸ばせばいいんじゃない」と教えてもらったので、接続文字列を見てみると確かにConnect Timeout=60となっている。しかし、タイムアウト秒数を240秒に変えてみたものの、やはり同じくタイムアウトが発生してしまうみたい。

Azure Mobile Services(Azureモバイルサービス)の使い方まとめ

モバイルサービス(Azure Mobile Services)を使うにあたって、今後自分で使いそうなTipsをまとめています。

認証

テーブル操作

他のサービスを使って○○する

ファイルをアップロードする

連載

.NETバックエンド

伊豆大島内の路線バスの時間を調べる「大島とらふぃっく」を作りました

大島とらふぃっくというサービスを作りました。「出帆港」と「その時点の時刻」からその日の残りの路線バスの時刻を表示します。

先月、伊豆大島に観光に行ったことをブログに書きました。

1日目はバイクで移動していたからか、バスに乗っていなかったので大島の「出帆港」によって、お店の営業時間が変わったりバスのルートや時刻が異なることを知りませんでした。

出帆港とは、大島の場合は「元町港」と「岡田港」のことです。

伊豆諸島(それ以外の島でも同様だと思うけど)の島の大半は、火山の先っぽが海上に出ていて地上部分で人が暮らしています。その影響もあって断崖絶壁の部分が多く、大型船の接岸が難しいそうです。開発が比較的容易な場所は近世以前からある港町がそのまま発展して、接岸可能な桟橋を持っています。大島の場合は元町港に当たります*1

港があったとしても天候や海象等の条件で接岸できなくなるため、近代になってから崖を削ったりして雨風の影響を受けにくい場所に新しく港が作られることがあります。大島の場合は岡田港(おかた)に当たります。

路線バスのルートが決まる要因としては「出帆港」の他にも島内のイベントに合わせてか、バスの発着時間も「時期」によっても異なります。パターンとしては、4つあります。

  1. 毎日運行
  2. 出帆港によってルートと時間が変わる
  3. 期間によって時間が変わる
  4. 出帆港と期間によってルートと時間が変わる

観光地ならバスがあるからなんとかなるやろという慢心が結果的に三原山から元町港まで4km延々と歩くことになった*2のですが……

伊豆大島に観光に行かれる方がいれば是非「大島とらふぃっく」をお使いください。

*1:近代的な湾岸整備は岡田港の方が先だけど

*2:当日は出帆港が元町港ではなかったのでルート的にバスもタクシーも通っていない

「URLのコメント見るやつ」を作りました

@jz5が「リツイート直後のツイートを表示するやつ」を公開したようです。

本人に@を飛ばすほどではない時にTwitterでRTした後にコメントを書くエアリプみたいなことをすることがあります。Twitterに張り付いている時には構わないのですが、後々から言及されているのを拾い損ねることがあります。

「リツイート直後のツイートを表示するやつ」は、なかなか使いやすくって下図のようにRT後のツイートを拾って表示してくれます。

「○○を表示するやつ」ってフレーズが気に入ったので、僕もさっくりとサービスを作ってみました。「URLのコメント見るやつ」です。

  • (すでにサービスの提供を終了しています)

URLを入力してLoadボタンをクリックすると、そのURLについてのTwitterとはてなブックマークでの言及されているコメントを表示することができます。例えば、先ほどの「リツイート直後のツイートを表示するやつ」に関するコメントをみたい場合は以下のように指定します。

  • (すでにサービスの提供を終了しています)

こんな感じでコメントが表示されます。

思い付きで作ったサービスですが別用途での利用方法を思いついたので、しばらくメンテナンスを続けていく予定です。

Azure Mobile Services(モバイルサービス)の通知ハブに登録されているiOSデバイスに向けてAPNsを使ってプッシュ通知する

スマートフォンを使っていると当たり前の機能のうちに「プッシュ通知」があります。

たとえば、iPhoneやiPadでGmailアプリなどのメールアプリを使っていると、メールを受け取るとユーザーに向けて「メールを受信しました」とプッシュ通知されます。

プッシュ通知を送るための仕組みは、iOS(Apple)、Windows(Microsoft)、Android(Google)とプラットフォームごとに用意されています。当然、実装に必要のための手順がバラバラにも拘わらず、モバイルアプリは複数のプラットフォームでリリースするのも当たり前になっています。プッシュ通知を送るための実装が異なることで工数が増大して苦しんでいた方も多いと思います。

各プラットフォームでのプッシュ通知の実装をラッピングして、簡単にプッシュ通知とデバイスの管理ができるようにするサードパーティ製のサービスには「Parse」や「Amaozon SNS」というものがあります。それらのひとつに「Azure Mobile Service(モバイルサービス)」があります。*1

事前準備

Apple Push Notification Service(APNs)でプッシュ通知を送る場合の処理については、Appleからプログラミングガイドが出ていますのでこのドキュメントを読みます。

用語は異なりますが基本的には「Windows PhoneでAzure Mobile ServiceとNotification Hubを利用して2ステップでプッシュ通知機能を実装する #wpdev_jp - 酢ろぐ!」で説明しているイメージ図と同じです。APNsへプッシュ通知を送信するのにあたり、通知ハブの機能を利用するには「Azure Notification Hubs を使用して iOS アプリにプッシュ通知を送信する | Microsoft Docs」を参考にしてください。

プッシュ通知を受け取るための準備

アプリ側の実装

アプリ側では以下のように実装します。iOS 7.1以前とiOS 8以降で実装が異なります。

-(BOOL)application:(UIApplication *)application 
    didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ...

    // プッシュ通知を受けるためにデバイストークンの要求
    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)])
    {
        // iOS 8 以降
        UIUserNotificationType types = UIUserNotificationTypeBadge | UIUserNotificationTypeAlert;
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:types categories:nil];
        [application registerUserNotificationSettings:settings];
    } else {
        // iOS 7.1 以前
        UIRemoteNotificationType types = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge;
        [application registerForRemoteNotificationTypes:types];
    }
    
    return YES;
}

- (void)application:(UIApplication *)application 
    didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication*)application 
    didRegisterForRemoteNotificationsWithDeviceToken:(NSData*)deviceToken
{
    // サーバーにデバイストークンを設定する処理を実装する
    NSString* serviceUrl = @"https://{service_name}.azure-mobile.net/";
    NSString* appKey = @"{your application key}";
        
    MSClient* client = [MSClient clientWithApplicationURLString:serviceUrl
                                                 applicationKey:appKey];
                                                    
    // 通知ハブを使う場合は以下のように実装する
    [self.client.push registerNativeWithDeviceToken:deviceToken
        tags:nil completion:nil]; 
}

iOSデバイスに向けてプッシュ通知する

バッチ処理等でiOSデバイスに向けてプッシュ通知を送る場合の処理です。

// 接続文字列
var connnectionString = "Endpoint=sb://example-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=<your key>";

// ハブ名
var hubName = "<your hub name>";

// テスト送信か?
// Production(本番)にプッシュ通知を送信する場合は false
// Development(開発)にプッシュ通知を送信する場合は true
var enableTestSend = false;

// 接続文字列からNotificationHubClientオブジェクトを生成する
var hubClient = NotificationHubClient.CreateClientFromConnectionString(
    connnectionString, hubName, false);

// 通知を送信!!!!
var json = "{\"aps\":{\"alert\":\"hage\"},\"app\":{\"id\":\"kazuakix\"}}";
await client.SendAppleNativeNotificationAsync(json);

アプリで通知を受け取る

アプリでプッシュ通知を受け取った後の処理についてです。userInfoには送信されたプッシュ通知のペイロードがパースされた状態で格納されています。

-(void)application:(UIApplication *)application 
    didReceiveRemoteNotification:(NSDictionary *)userInfo 
    fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    if (application.applicationState == UIApplicationStateInactive) {
        // アプリプロセスがバックグラウンドで動作している状態
    } else if (application.applicationState == UIApplicationStateActive) {
        // アプリプロセスがフォアグランドで動作している状態
    }
    
    // pushのペイロードから読み取る
    NSDictionary *app = [userInfo objectForKey:@"app"];
    NSString *userId = [app objectForKey:@"id"];
    
    // 受け取ったよ!!!!!!
    UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"didReceiveRemoteNotification" 
        message:@"received!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
    [alertView show];
}

*1:Windowsに関しては当事者

Windows PhoneでAzure Mobile ServiceとNotification Hubを利用して2ステップでプッシュ通知機能を実装する #wpdev_jp

この記事は、「Windows Phone Advent Calendar 2014」の12日目の記事です。

Androidのマスコットといえばドロイド君ですが、Windows PhoneのマスコットといえばWindows Phoneマンです。これの現物を見たことがあるか、とあるシアトルルートから貰ったような気がするのですが、影も形もないので記憶違いなのかもしれません。

2011年から3回引っ越しをしているのでその際に紛失してしまったのかもしれません。いつもWindows Phoneマンの話をするときに探していますが見つかったことはありません。

f:id:ch3cooh393:20141205022744j:plain

Windows Foam 7 strikes back against Android mascot - MSPoweruser より

さて、本記事ではタイトルの通り、Windows Phoneアプリにプッシュ機能を追加する方法を紹介したいと思います。プッシュ機能を追加するためにはインフラ側(サーバー)を用意する必要があります。

サーバーを用意すること」と「プッシュ通知を送るシステムを用意すること」、その両方を準備するのはなかなか大変なので「Parse」をはじめ、沢山のサードパーティーのサービスがあります。Microsoft Azureというクラウドサービスを提供しているMicrosoft社でも「Azure Mobile Service」「Notification Hub(以下、通知ハブ)」といったサービスを提供しています。

通知ハブは、前述のParseと同様にマルチプラットフォームでプッシュ通知を管理することができるMicrosoft Azureのサービスのひとつです。

僕のMSCCの進捗はゼロですが、この記事を読んでいる方のMSCC用に開発中のアプリのひとアクセントになれば幸いです。

Windowsプッシュ通知サービスの簡単な仕組み

iPhoneやAndroidの浸透によって、当たり前のようにプッシュ通知が使われるようになりました。もちろんWindowsストアアプリとWindows Phoneアプリにもプッシュ通知を送るための機構が用意されています。この両者はユニバーサルアプリとして統合されたので、Windowsプッシュ通知サービス(以下、WNS)と呼ばれる共通の通知サービスが使用されます。

WNSの仕組みは下図の通りです。全体の流れとしてはWindowsストアアプリでも同じです(というかコード自体が同じ)。

f:id:ch3cooh393:20141212004505p:plain

上図を見て頂ければだいたいのプッシュ通知の流れが理解できると思います。Windowsストア/Windows Phoneアプリから「通知チャンネル」と呼ばれるデバイスとWNSとを関連付けたトークンを取得(①②)して、トークンを通知ハブに登録(③)する。

なんらかのイベントが発生したら通知ハブにプッシュ通知の送信を要求(④)すると、あとは通知ハブがWNSとのやり取りを肩代わり(⑤)してくれて、デバイスにプッシュ通知が送信(⑥)されるという流れです。

さて、Windows Phoneアプリにおけるプッシュ通知の仕組みが理解できたところで、実際にAzure Mobile Service(モバイルサービス)の通知ハブからWNSを経由して、Windows Phoneデバイスに対してプッシュ通知させてみましょう*1

あなたのアプリでプッシュ通知に対応させるためにやるべきこと

既にAzure Mobile Serviceを利用している場合、あなたのWindows Phoneアプリをプッシュ通知に対応させるには、下記のたった2ステップを実行するだけです*2

  • Visual Studioでプッシュ通知を受け取るための処理の追加
  • デバイスのチャンネルを通知ハブへ登録

たった2ステップだけであなたのWindows Phoneアプリがプッシュ通知機能が搭載されたWindows Phoneアプリになります。あとは通知ハブからWindows Phoneアプリ目掛けてプッシュを送りまくるだけです。

現在、Azure Mobile Serviceを利用していない方もたくさんいると思いますので、本記事では「Azure Mobile Serviceのサービスを新規作成する」と「通知ハブのデバッグからプッシュ通知を送る」についても触れたいと思います。

Azure Mobile Serviceのサービスを新規作成する

Microsoft Azureの管理ページにサインインします。管理ページのURLは以下の通りです。新ポータルの方にはモバイルサービスの操作はまだできません……。

管理ページに入ると、左下に[+新規]ボタンがあるのでクリックします。

f:id:ch3cooh393:20141211225246p:plain

ウィザードに従って、[コンピューティング]、[モバイルサービス]、[作成]の順にクリックしていきます。

f:id:ch3cooh393:20141211225251p:plain

名前は仮に「blog-notification」としました。

f:id:ch3cooh393:20141211225302p:plain

f:id:ch3cooh393:20141211225309p:plain

f:id:ch3cooh393:20141211225325p:plain

以上でMobile Serviceでのサービスの作成は完了です。

プッシュ通知を受け取るための処理

次にWindows Phoneアプリ側の処理を追加しましょう。App2という既存のアプリプロジェクトがあるとします。Visual Studioで開きます。

f:id:ch3cooh393:20141212022604p:plain

Visual Studioでプッシュ通知の追加

右ペインのソリューションエクスプローラーのApp2を右クリックします。コンテキストメニューが表示されるので、[追加(D)]、[プッシュ通知(P)...]の順に選択します。

f:id:ch3cooh393:20141212022628p:plain

あとはウィザードに従って必要な情報を設定していきます。

f:id:ch3cooh393:20141212022642p:plain

f:id:ch3cooh393:20141212022652p:plain

f:id:ch3cooh393:20141212022701p:plain

先ほど作成したサービスとアプリを関連付けます。

f:id:ch3cooh393:20141212022710p:plain

f:id:ch3cooh393:20141212022720p:plain

「プッシュ通知の追加」を実行すると、本来しなければいけない作業のほとんどを自動化することができます。

  • アプリケーションをWindowsストアとの関連付け
  • Windows Azure Mobile Service SDKを追加
  • Azure Mobile ServiceへWNSのクライアントトークンを登録

すごい横着した感がありますが、これでアプリでMobile Seviceのサービスを利用することができるようになりました。

App.xaml.csに通知チャンネルの登録処理を追加する

一通り設定作業が終わったので、「通知チャンネルの取得」と「通知チャンネルを通知ハブへ登録」の処理をApp.xaml.csのOnLaunchedメソッドに追加しましょう。

App.xaml.csを開き、下記のusingディレクティブが追加されていることを確認します。Microsoft.WindowsAzure.MobileServices名前空間を宣言しているのは拡張メソッドを利用するためです

// add
using Windows.Networking.PushNotifications;
using Microsoft.WindowsAzure.MobileServices;

Mobile Serviceとのやり取りをおこなうフィールド変数が追加されているのを確認します。

    /// <summary>
    /// 既定の Application クラスに対してアプリケーション独自の動作を実装します。
    /// </summary>
    public sealed partial class App : Application
    {
        // http://go.microsoft.com/fwlink/?LinkId=290986&clcid=0x411
        public static Microsoft.WindowsAzure.MobileServices.MobileServiceClient blog_notificationClient = new Microsoft.WindowsAzure.MobileServices.MobileServiceClient(
        "https://blog-notification.azure-mobile.net/",
        "<youre access key>");

通知チャンネルを取得し、取得したそれを通知ハブへ非同期で登録する処理を

        protected override async void OnLaunched(LaunchActivatedEventArgs e)
        {
#if DEBUG
            if (System.Diagnostics.Debugger.IsAttached)
            {
                this.DebugSettings.EnableFrameRateCounter = true;
            }
#endif

            // Add: 通知チャンネルを取得する
            var chanel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

            // Add: 取得した通知チャンネルを通知ハブへ登録する
            var push = blog_notificationClient.GetPush();
            await push.RegisterNativeAsync(chanel.Uri);

これでアプリ側の処理は完了です。Windows Phoneシミュレータでデバッグ実行して頂き、アプリを起動した状態にしておいてください(OnLaunchedメソッドを実行させて、通知チャンネルを通知ハブへ登録させるため)。

通知ハブのデバッグからプッシュを送る

Azureの管理ページにアクセスします。SERVICE BUSをクリックして、先ほど作成したblog-notificationを選択します。

f:id:ch3cooh393:20141212024022p:plain

通知ハブタブを選択して、blog-notification-hubを選択します。

f:id:ch3cooh393:20141212024029p:plain

デバッグタブを選択します。プラットフォームにはWindowsを選択して、通知の種類から「トースト」を選択すると、下図のようにテストメッセージのペイロードテンプレートが表示されると思います。

ページ下部中央の[送信ボタン]をクリックして、プッシュ通知を送ります。

f:id:ch3cooh393:20141212024204p:plain

送信すると1分かからずWindows Phoneシミュレータの方にプッシュ通知されます。

f:id:ch3cooh393:20141212023857p:plain

てれれれーん。

(おまけ)Azure Service Bus SDKを使ってコンソールアプリからプッシュを送信する

通知ハブにはSDKが提供されており、当然ですが自動で実行してくれるジョブを作成することができます。

ジョブから通知ハブに接続するために接続文字列が必要になります。接続文字列は、Azure管理ページの通知ハブを見ている時にタブバー(?)に表示されている[接続情報]のボタンをクリックします。

f:id:ch3cooh393:20141211234354p:plain

コンソールアプリプロジェクトにAzure Service Bus SDKをインストールして、以下のようなコードを書きます。XMLを組み立てる処理はもっと適切な方法がある気もしますが面倒なのでStringBuilderを使っています。

// 接続文字列
var connnectionString = "Endpoint=sb://example-ns.servicebus.windows.net/;SharedAccessKeyName=DefaultFullSharedAccessSignature;SharedAccessKey=<your key>";

// ハブ名
var hubName = "<your hub name>";

// テスト送信か?(WNSの場合はあまり関係なさそう)
// Production(本番)にプッシュ通知を送信する場合は false
// Development(開発)にプッシュ通知を送信する場合は true
var enableTestSend = false;

// 接続文字列からNotificationHubClientオブジェクトを生成する
var hubClient = NotificationHubClient.CreateClientFromConnectionString(connnectionString, hubName, enableTestSend);

// ここで「kazuakixの日記」が更新されているか調べる
var isUpdated = GetKazuakixNoNikki();
if (!isUpdated)
{
    // 更新されてなければプッシュは送らない
    return;
}

// ペイロード(メッセージ)を作成する
var message = "かずあきさんのブログが更新されたよ!見てね星";

var sb = new System.Text.StringBuilder();
sb.AppendLine("<?xml version=\"1.0\" encoding=\"utf-8\"?> ");
sb.AppendLine("<toast> ");
sb.AppendLine("<visual><binding template=\"ToastText01\">");
sb.AppendFormat("<text id=\"1\">{0}</text>", message);
sb.AppendLine();
sb.AppendLine("</binding>");
sb.AppendLine("</visual>");
sb.AppendLine("</toast>");
var payload = sb.ToString();

// 通知を送信!!!!
await hubClient.SendWindowsNativeNotificationAsync(payload);

上記の通知ハブのAPIを使用したサンプルコードを実行すると事前に登録していたWindowsデバイスに向けてプッシュでトースト通知されるはずです。

_人人人人人人人人人人人人人人人人人人人人人人人人_
> かずあきさんのブログが更新されたよ!見てね星 <
 ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄ ̄

おわり。

*1:なお、本記事ではSilverlightの方のWindows Phoneアプリの話はしません

*2:通知する処理まで入れると3ステップ