Windows Azure アプリへの通知機能の実装

更新日: 2011 年 11 月 16 日

Zip Fileダウンロード (Zip、1.43 MB)

本ドキュメントでは Push 通知をうけとる Windows Phone アプリの作り方を解説します。

Windows Phone アプリを作成するには、Windows Phone SDK が必要です。Windows Phone SDK は Visual Studio 2010 がインストールされているときは Visual Studio 2010 のテンプレートなどを拡張し、インストールされていないときは Visual Studio 2010 Express for Windows Phone をインストールします。つまり、手元の環境に最適な Windows Phone アプリ構築環境を手軽に構築できます。

Step 1: 新規プロジェクト作成
Step 2: 基本となるパノラマ アプリケーションの作成
Step 3: クーポン画面の追加
Step 4: Push 通知用 URI 取得コードの追加
Step 5: Push 通知用 URI 登録コードの追加
Step 6: Push 通知を受け取った時の動作

Step 1: 新規プロジェクト作成

Visual Studio を起動したら [ファイル] - [新規作成] - [プロジェクト] メニューをクリックして新規プロジェクトの作成を行います。

図: Visual Studio メニュー

[新しいプロジェクト] 画面で [名前] 欄に「AkibanoJisacouponCs」と入力して「Windows Phone パノラマ アプリケーション」を選択して [OK] ボタンをクリックします。

図: [新しいプロジェクト] ダイアログ

画面は Visual Studio 2010 のものなので Visual Studio 2010 Express for Windows Phone の実行時と異なる部分がありますが、Windows Phone アプリ作成部分については差異はありません

ページのトップへ


Step 2: 基本となるパノラマ アプリケーションの作成

今回のサンプルではメイン画面のパノラマで「お買い得情報通知を受信する」をタップすると Push 通知の登録をするようにします。
パノラマ アプリケーションの「メニュー」 PanoramaItem に「/CouponPage.xaml」への HyperLinkButton を追記します。

図: MainPage.xaml

XAML 定義全体をみてみましょう。

<phone:PhoneApplicationPage 
    x:Class="AkibanoJisacouponCs.MainPage"
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800" 
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"  Orientation="Portrait"
    shell:SystemTray.IsVisible="False">
    <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!--パノラマ コントロール-->
        <controls:Panorama Title="マイ アプリケーション">
            <controls:Panorama.Background>
                <ImageBrush ImageSource="PanoramaBackground.png"/>
            </controls:Panorama.Background>
            <controls:PanoramaItem Header="メニュー">
                <StackPanel>
                    <HyperlinkButton Content="このアプリケーションについて" NavigateUri="/AboutPage.xaml" HorizontalAlignment="Left" VerticalAlignment="Top" />
                    <HyperlinkButton Content="お買い得情報通知を受信する" NavigateUri="/CouponPage.xaml" HorizontalAlignment="Left" VerticalAlignment="Top" />
                </StackPanel>
            </controls:PanoramaItem>
            <controls:PanoramaItem Header="ニュース">
                <Grid >
                </Grid>
            </controls:PanoramaItem>
        </controls:Panorama>
    </Grid>
</phone:PhoneApplicationPage>

ページのトップへ


Step 3: クーポン画面の追加

「お買い得情報通知を受信する」をタップしたときに表示する Coupon.xaml を追加しましょう。
ソリューション エクスプローラーで [AkibanoJisacouponCs] プロジェクトを右クリックして [追加] - [新しい項目] メニューをクリックします。

図: ソリューション エクスプローラー

「Windows Phone 縦向きのページ」を選択して [名前] 欄に「Coupon.xaml」と入力して [追加] ボタンをクリックします。

図: [新しい項目の追加] ダイアログ

追加された Coupon.xaml の LayoutRoot 部を次のように編集しましょう。

<Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock x:Name="ApplicationTitle" Text="秋葉野自作商会 お買い得情報" Style="{StaticResource PhoneTextNormalStyle}"/>
            <TextBlock x:Name="PageTitle" Text="クーポン" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>
        <!--ContentPanel - 追加コンテンツをここに入力します-->
        <StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <phone:WebBrowser HorizontalAlignment="Left" Name="webBrowser1" VerticalAlignment="Top" Foreground="Black" IsEnabled="True" Height="600" Width="454" IsScriptEnabled="True" Source="https://localhost:8000/special/coupon.html" />
        </StackPanel>
    </Grid>

ページのトップへ


Step 4: Push 通知用 URI 取得コードの追加

画面が完成したので主要コード部分の 1 つめである Push 通知用 URI の取得コードを作成しましょう。
ソリューション エクスプローラーで「Coupon.xaml」を右クリックして [コード] メニューを選択するとコードエディタが開きます。

namespace AkibanoJisacouponCs
{
    public partial class CouponPage : PhoneApplicationPage
    {
        public CouponPage()
        {
            InitializeComponent();
        }
    }
}

まずはディレクティブを追加しておきましょう。ディレクティブは xaml.cs ファイルの一番先頭に記述するものでディレクティブを書いておくとクラスの参照を省略できます。

本来はディレクティブがない状態でつくりはじめ、ある程度できたところでよく使うクラス参照をディレクティブに書いてコードを見やすくして (このような見易さだけを考えてコードを書き換える作業をリファクタリングといいます) またコードの続きを書くようなループを繰り返していきます。

using System;
using System.Net;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Notification;
namespace AkibanoJisacouponCs
{
    public partial class CouponPage : PhoneApplicationPage
    {
        public CouponPage()
        {
            InitializeComponent();
        }
    }
}

では、実際にコードを書いていきましょう。
public CouponPage() の中にある InirializeComponet(); の後ろで [Enter] キーを押して改行したら、「this.Loaded += 」と入力して TAB キーを 2 回押して画面がロードされた時のイベント プロシージャを定義します。

public CouponPage()
        {
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(CouponPage_Loaded);
        }
        void CouponPage_Loaded(object sender, RoutedEventArgs e)
        {
            throw new NotImplementedException();
        }

Visual Studio の機能で自動生成した Couponage_Loaded イベント プロシージャは、そのままだと NotImplementedException 例外が発生します。これは「throw new NotImplementedException();」の部分を書き換え忘れないようにするための親切機能です。

throw で始まる行を「GetUri();」に書き換えましょう。
すると「GetUri」の部分に赤い波線が引かれるので右クリックして [生成] - [メソッドスタブ] メニューを選択して GetUri メソッドの空定義 (スタブ) を生成します。

図: [メソッドスタブ] を選択

void CouponPage_Loaded(object sender, RoutedEventArgs e)
        {
            GetUri();
        }
        private void GetUri()
        {
            throw new NotImplementedException();
        }

次にやるべきことはもう明確ですね。「throw new NotImplementedException();」の部分を書き換える作業です。

private Microsoft.Phone.Notification.HttpNotificationChannel PushChannel;
        private const string Title = "AkibanoJisacoupon";
        private void GetUri()
        {
            PushChannel = HttpNotificationChannel.Find(Title);
            if (PushChannel == null)
            {
                PushChannel = new HttpNotificationChannel(Title);
                PushChannel.ChannelUriUpdated += new EventHandler<NotificationChannelUriEventArgs>(PushChannel_ChannelUriUpdated);
                PushChannel.ErrorOccurred += new EventHandler<NotificationChannelErrorEventArgs>(PushChannel_ErrorOccurred);
                PushChannel.Open();
            }
            else
            {
                if (PushChannel.ConnectionStatus == ChannelConnectionStatus.Connected)
                {
                    SetUri(PushChannel.ChannelUri.ToString());
                }
            }
            if (!PushChannel.IsShellTileBound)
            {
                PushChannel.BindToShellTile();
            }
            if (!PushChannel.IsShellToastBound)
            {
                PushChannel.BindToShellToast();
            }
        }
        private void PushChannel_ChannelUriUpdated(object sender, NotificationChannelUriEventArgs e)
        {
            Dispatcher.BeginInvoke(() =>
            {
                SetUri(e.ChannelUri.ToString());
            });
        }

一見難しそうに見えるコードも順番に理解していけば簡単です。

(1) Microsoft.Phone.Notification.HttpNotificationChannel.Find(Title)
Push 通知チャネル名がすでに定義されているかどうかを確認するのがこの行の役目です。定義されていた場合はその情報を PushChannel 変数に設定します。

(2) new Microsoft.Phone.Notification.HttpNotificationChannel(Title)
Push 通知チャネル名がないとき(== null のとき)は、その名前で new を使って新しい Push 通知チャネルを生成します。
生成したチャネルは PushChannel.Open() を実行して Microsoft Push Notification Service に登録します。登録用の通信は非同期に行われるので事前に「PushChannel.ChannelUriUpdated += 」を使って URI が取得できたときに発生する ChannelUriUpdated イベントで呼び出す PushChannel_ChannelUriUpdated イベント プロシージャを登録しておきます。

(3) PushChannel_ChannelUriUpdated イベント プロシージャ
コードの順番は前後しますが、ChannelUriUpdated イベントで呼び出すイベント プロシージャの内容を確認してみましょう。このイベント プロシージャの目的は単純明快で Microsoft Push Notification Service から渡されてきた URI を取得する事です。ノウハウとしてはパラメタに設定されてくる URI をそのまま取得できず Dispatcher.BeginInvoke を使って URI を取得するという手間の部分です。これは非同期通信が別スレッドで動作しているからですがまずはこのように取得するものとして覚えておき時間があるときにスレッドについて調べてみると良いでしょう。

(4) PushChannel.ChannelUri.ToString()
Push 通知チャネル名があるときは、その名前で登録されている URI を取得します。

(5) PushChannel.BindToShellTile()
Push 通知チャネルをタイル通知と結び付けます。

(6) PushChannel.BindToShellToast ()
Push 通知チャネルをトースト通知と結び付けます。

ここまでの流れで覚えておきたい点は、生成した Push 通知チャネルは一定期間の間 Windows Phone OS 自身が覚えており、その間は Microsoft Push Notification Service に問い合わせるのではなく保存された URI を使うという点です。

では、続きを作っていきましょう。


Step 5: Push 通知用 URI 登録コードの追加

URI が取得できたのでこれを自分たちのシステムに登録する部分をつくります。

登録先や登録方法には様々な手法がありますが、このサンプルでは Windows Azure の WebRole で動いているアプリに登録するので、Push 通知用 URI をパラメタにして WCF Web サービスを呼び出すようにしましょう。

private WebClient WebClient = new WebClient();
        private const String ServiceUri = "https://localhost:8000/ChannelService.svc/SetChannelUri";
        private void SetUri(String channelUri)
        {
            String uri = "userID=Claudia&uri=" + HttpUtility.UrlEncode(channelUri);
            WebClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(WebClient_DownloadStringCompleted);
            WebClient.DownloadStringAsync(new Uri(ServiceUri + "?" + uri));
        }
        private void WebClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            MessageBox.Show("OK", "Set Channel Uri", MessageBoxButton.OK);
        }

WCF Web サービスを呼び出すといっても難しく考える必要はありません。ブラウザーを使って Web ページを指定するのと同じように

https://localhost:8000/ChannelService.svc/SetChannelUri? userID=Claudia&uri=xxxxxxxxxxxxxxxxxxxxx

という宛先に対して DownloadStringAsync で文字列のダウンロードを依頼すればよいのです。

もちろん、Windows Phone での通信ですから非同期通信となるのでダウンロードが完了したときの DownloadStringCompleted イベントが発生したときにイベント プロシージャの登録もわすれずにおこないます。

ページのトップへ


Step 6: Push 通知を受け取った時の動作

さてこれで Windows Phone 側はすべて完成です。「あれ? Push 通知を受け取った時のコードは?」と思うかもしれませんが、そこの部分はすべて Windows Phone OS 側での制御になりプログラム コードは 1 行もかかなくていいのです。

図: アプリや OS 動作

なので、本当にこれで完成なのです。


執筆者紹介: 初音玲 (はつねあきら)

Windows Phone は以前から注目しており日本発売前から実機を個人輸入して使用していたりするガジェット好き。大手 SIer の開発者。
Microsoft MVP for Visual Basic 受賞者であり、Windows Phone コミュニティ Arch のメンバー
ブログ: http://blogs.wankuma.com/hatsune/

ページのトップへ