酢ろぐ!

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

Windows Phone 8.1 Developer Previewが来週の頭に出るみたいですよ

昨日、Twitterで「Windows Phone 8.1 Developer Preview」がまだ出ていないことを教えて頂きました。元々4月前半という話だったので、Build 2014の次の日あたりに提供されているものだとてっきり勘違いしました。

Windows Phoneの責任者であるベルフィオーレ氏は11日、開発者向けバージョンである「Windows Phone 8.1 Developer Preview」を来週初めにリリースすることを明らかにしました。

Windows Phone 8.1開発者向け来週配布 | ガジェット速報

「Windows Phone 8.1 Developer Preview」を試す方法に関しては、こちらの記事(英語)が詳しいです。

Preview for Developers app is basically an app that configures your phone to receive developer previews of software updates that are yet to be released by Microsoft.

Download the app from this location and install it on your Windows Phone handset.

Getting Windows Phone 8.1 developer preview first; final version on the day it is released by MicrosoftTechie News

高橋忍さんが、Windows Phone 8.1 Developer Preview導入の際の注意点について自身のブログに書かれているので読んでおきましょう。

しかし、あまりCortanaに魅力を感じn……

Windows Phone 8.0でGoogle AdMob SDKを参照しようとするとエラーが発生して参照できない問題に対応する

Google AdMobでの収益っていつの間にかGoogle AdSenseに統合されていたんですね。気付きませんでした。Google AdSenseの商品別集計欄にGoogle AdMobの情報が載っていて驚きました。

さて、Google AdMobの広告をアプリ内に掲載するためには「Google Mobile Ads SDK」を使用します。iOS、Android(Gogole Play)、Windows Phone 8向けにそれぞれSDKが用意されています。

Windows Phone 8で広告を掲載するには、上記のURLから「googlemobileadssdkwindowsphone8.zip」をダウンロードして、zipを解凍してGoogleAds.dllを参照するだけなのですが、表題の通り僕の環境では何故かエラーが発生してしまっていました。

プロジェクトに追加できないエラーを発生させる

参照マネージャーで「GoogleAds.dll」を参照して、OKボタンを押します。

f:id:ch3cooh393:20140404174254p:plain

どーん。下図のようにエラーが発生します。

f:id:ch3cooh393:20140404174139p:plain

ダイアログには以下のように表示されていました*1

Microsoft Visual Studio

より新しいバージョンのアセンブリまたは互換性のないアセンブリへの参照は、プロジェクトに追加できません。

英語の場合は、下図のように表示されます。

f:id:ch3cooh393:20140404174144p:plain

ダイアログには以下のように表示されています。

Microsoft Visual Studio

A reference to a higher version or incompatible assembly cannot be added to the project.

これのダイアログを見て、「GoogleはVisual Studio 2012でビルドしたdllを作っているので、Visual Studio 2013では使えないんだな」と勝手に判断して、数ヶ月この問題を放置することとなりました……

疑問編

Twitterでたまたまアプリ内広告について話をしている時に、前述したエラー内容の旨をツイートすると、「Visual Studio 2013でGoogle AdMobの広告の表示問題なくできているよ」とリプライを頂きました。

再度、「Visual Studio 2013 Update」と「Google Mobile Ads SDK for Windows Phone 8 v6.5.11」 の組み合わせで試してみるとやはりエラーが発生しました。

エラーダイアログの内容を改めて吟味すると、一昨日リリースされたばかりのVisual Studio 2013 Updateを使っているのに、それよりも新しいバージョンのアセンブリへの参照は、プロジェクトに追加できません。とエラーが発生するのはおかしいのではないかと疑問が湧いてきました。

解決編

原因は、セキュリティブロックが有効になっているのが原因でした。ブロックを解除することでVisual StudioからGoogleAds.dllを参照することができるようになります。

ネイティブのエクスプローラで、GoogleAds.dllを右クリックしてコンテキストメニューを表示させて、プロパティを単託します。

f:id:ch3cooh393:20140404174518p:plain

プロパティダイアログの一番下にセキュリティの項目があります。「ブロックを解除」をクリックすれば、GoogleAds.dll を参照することができるようになります。

f:id:ch3cooh393:20140404174526p:plain

おわり。

*1:あまり見かけないエラーダイアログのせいなのか和訳がちょっとおかしい気がする

Windowsストアアプリで使えるポータルクラスライブラリ(Portable Class Library/PCL)について

サーバーサイドでの「ASP.NET」からスマートウォッチと呼ばれる腕時計などの組み込み機器向けの「.NET Micro Framework」まで、あらゆる分野で.NET Frameworkや各デバイス向けにカスタマイズされた.NET Frameworkのサブセットが存在しています。

.NET Frameworkのテクノロジーを使ってアプリの開発が可能なプラットフォームがこの2,3年で急激に拡大しています。もっとも勢いがあるのはタブレットアプリとスマートフォンアプリの分野でしょう。マイクロソフト社自身がデバイスと開発環境を提供する「Windowsストアアプリ」、「Windows Phone」はその筆頭です。

そして、.NET Framework互換のフレームワークである「Mono」から派生したXamain社のスマートフォンプロダクト「Xamarin.Android」「Xamarin.iOS」が勢いを後押ししています。2012年9月には、マイクロソフト社はXamarin社と提携を発表し、C#を使ったスマートフォンアプリ開発を強化しています。

さて、デスクトップWindowsやWindowsストアアプリ、Windows Phoneなどの様々なプラットフォームでのアプリ開発にVB.NETやC#を使うことができるようになったというのは前述した通りです。開発に使うプログラミング言語を統一することができれば、マルチプラットフォームを対象にして同一タイトルのアプリやゲームを提供することになった場合、プラットフォームに依存しない処理に関してはソースコードを共有することが可能です。

とある機能をひとつ追加しようとすると、通常、設計・実装・テストのフェーズを経て、プロダクトに組み込まれます。それぞれのフェーズでコストが掛かりますが、それを複数のプラットフォームで対応しなければいけないとなればその分だけコストが掛かってきます。

可能な限り開発や保守を効率化するためにコードを最大限に「再利用」しようとします。「最大限再利用する」というのはどういうことかというと、「最大限」の解釈は多々あるかと思いますが、1回実装して1回テストしたコードが複数のプラットフォームで使えるということではないでしょうか。現時点での最大限再利用したいという問いの解のひとつに「ポータブルクラスライブラリ(Portable Class Library)」があります。

例えば、デスクトップWindows向けアプリでの処理とWindowsストアアプリとロジックを共有したいという要望があったとします。これらのコードを書くコストを抑えるためにはどうしたらよいでしょうか。

本記事では、ソースコードの共有方法についていくつか紹介したのち、ポータブルクラスライブラリを使ったマルチプラットフォームでソースコードの共有方法について紹介します。

プラットフォームごとにコードを実装する

それぞれのプラットフォームに最適化されたロジックを実装します。 この手段を使ってコードの共有をする場合は、実際に別々のプラットフォームで同じコードをフルスクラッチで実装するケースは少ないと思われます。プロジェクトAとプロジェクトBがあり、プロジェクトAが開発したソースコードをプロジェクトBで取り込む場合に使われるのではないかと思います。

よくあるケースとしては、デスクトップWindows向けのアプリで実装していたコードを流用しようとWindowsストアアプリにソースファイルをコピー&ペーストする場合です。

f:id:ch3cooh393:20140422152422j:plain

Windowsストアアプリ側でソースファイルを取り込んでしまってから、新規にデスクトップWindowsアプリに追加したクラスやメソッドを取り込みたい場合、手動で取り込まないといけないデメリットがありますが、これは片一方での修正や変更に影響されないメリットにもなります。

完全に同じロジックを使用するのであれば、後述する[リンクとして追加]によるソースファイルの共有や、ポータブルクラスライブラリプロジェクトの共有をすべきでしょう。

[リンクとして追加]によるソースコード共有

2つのプロジェクトからそれぞれ同じ1つのソースファイルを共有します。 [リンクとして追加]によるソースコードの共有は、.NET Frameworkを使った開発でスタンダードなソースコードの共有方法のひとつです。Visual Studioでファイルを追加する際に、[リンクとして追加]を選択してファイルを参照して、1つのファイルを複数のプロジェクトで共有します。

下図は「[リンクとして追加]によるソースコード共有」を示したイメージ図です。

f:id:ch3cooh393:20140422152429j:plain

この方法でソースコードの共有をおこなうメリットとしては、それぞれのプラットフォームに依存している一部分のロジック以外は同じコードで良いところです。プラットフォームに依存するコードは、#if 〜 #endif を使って切り分けます。

f:id:ch3cooh393:20140424221921j:plain

例えば、アプリの設定値を保存することを考えてみましょう。開発の対象はWindowsストアアプリとWindows Phoneアプリです。

プラットフォームに依存するコードは、#if 〜 #endif を使って切り分けます。 適当にテンプレートを使ってプロジェクトを作ってみました。プロジェクトのプロパティを見てみましょう。

Windowsストアアプリでは「NETFX_CORE」となっていることが確認できますWindows Phoneの場合は「WINDOWS_PHONE」となっています。

Windowsストアアプリでは、アプリの設定値の保存にはWindows.Storage名前空間の「ApplicationData.Current.LocalSettingsクラス」を使用します。SilverlightやWindows Phone (Silverlight)アプリにはLocalSettingsクラスが存在していないので、代わりにSystem.IO.IsolatedStorage名前空間の「IsolatedStorageSettings.ApplicationSettingsプロパティ」を使用します。

さてどのようなコードになるでしょうか。Settingsクラスを作ってみました。まず名前空間が異なるなるため、usingディレクティブで省略する名前空間を #if NETFX_COREで使い分けしています。

#if NETFX_CORE && !WINDOWS_PHONE
using Windows.Storage;
#elif WINDOWS_PHONE
using System.IO.IsolatedStorage;
#endif

public static class Settings
{
  public static void Set<T>(string key, T value)
  {
#if NETFX_CORE && !WINDOWS_PHONE
    ApplicationData.Current.LocalSettings.Values[key] = value;
#elif WINDOWS_PHONE
    IsolatedStorageSettings.ApplicationSettings[key] = value;
    IsolatedStorageSettings.ApplicationSettings.Save();
#endif
  }
}

前述したソースコードではファイルにアクセスするロジックがあったため、[リンクとして追加]によるソースコードの共有するのが最適でした。

もし共有したいソースコードが、プラットフォームで使用可能な.NET Framework APIのサブセットで記述されているのであれば、共有したいロジックを後述する「ポータブルクラスライブラリ」にまとめてしまって、そのプロジェクトを共有するのが良いでしょう。

ポータルクラスライブラリによるプロジェクト共有

ポータブルクラスライブラリとは、.NET Framework 4.0から利用できるようになった機能でデスクトップWindows、Windowsストアアプリ、Windows Phone、Xbox 360向けアプリ/ゲームから利用することができる「ポータブルクラスライブラリ」を作成できます。

ポータブルクラスライブラリのアセンブリは、プロジェクトの作成時または開発中にアセンブリを利用する側のプラットフォーム(ターゲットと呼ばれる)を選択します。選択されたターゲットのサブセットが自動的にサポートされます。

ポータブルクラスライブラリを使用することができるプラットフォームは下表の通りです。Visual Studio 2013 Update2にてポータブルクラスライブラリのプロジェクトを新規に作成した場合にデフォルトで選択されているターゲットの横に(*)を付けています。

f:id:ch3cooh393:20160115151403p:plain

Visual Studio 2012では選択できた「Xbox 360」が、Visual Studio 2013のポータルブルクラスライブラリの一覧からが削除されています。Xamarin Studioがインストールされていると「Xamarin.Android」と「Xamarin.iOS」が追加されます。

Visual Studio 2012 Pro以上のバージョンで、プロジェクト作成時にウィザードからテンプレートを選択することが可能です。

f:id:ch3cooh393:20140422155447j:plain

参照

Visual Studio 2013向けの多言語アプリツールキット

Visual Studio 2012からWindowsストアアプリとWindows Phoneの多言語対応が楽になるツールが公式で用意されている。

今までのアプリ(WPFとかだと今でもかな)だと多言語対応する際に、言語ごとにリソースファイルを用意する必要があった。

多言語アプリツールキットを使うと、ベースとなるリソースファイル(英語が良いと思う)を作成するとビルドする度に、有効にしている言語のリソースファイルを生成してくれる。

すごい便利なツールなんだけど、ググっても出てくるのはVisual Studio 2012向けの記事ばかりなので、メモ側に書いておく。

ちなみにVisual Studio 2012向けの多言語ツールキットはこっち。

多言語アプリツールキットの使い方はこちらからどうぞ。

Windows Phoneでアプリリソースのファイルを分離ストレージにコピーする

アプリケーション内に存在しているビルドアクションを「コンテンツ」にした画像ファイルを、分離ストレージにコピーします。

f:id:ch3cooh393:20141210003556p:plain

アプリリソースとして存在しているimage01.gif〜image07.gifのストリームを取得して、分離ストレージのユーザーストアにファイルを作成して、データを書き込みます。

// アプリリソースの画像ファイルを分離ストレージにコピーする
void CopyData()
{
    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        for (int i = 1; i <= 7; i++)
        {
            // ファイル名を作成
            var fileName = string.Format("image{0:d2}.gif", i);

            // 同名のファイルが存在している場合、ファイルを削除する
            if (store.FileExists(fileName)) {
                store.DeleteFile(fileName);
            }

            var uri = new Uri(fileName, UriKind.Relative);
            using (var strmReader = Application.GetResourceStream(uri).Stream)
            using (var strmWriter = store.OpenFile(fileName, FileMode.CreateNew))
            {
                // アプリリソースのストリームを読み出す
                var bytes = new byte[strmReader.Length];
                strmReader.Read(bytes, 0, bytes.Length);

                // 分離ストレージに保存する
                strmWriter.Write(bytes, 0, bytes.Length);
            }
        }
    }
}

関連記事

blog.ch3cooh.jp

Windows Phoneでmarkdownで書いたテキストをhtmlに変換して表示する

この記事は、Windows Phone Advent Calendar 2013の8日目です。

markdownって知っていますか?

普段のメモもはてダ記法で書くくらい傾倒していた私ですが、markdownに触れてからというものこのブログ「酢ろぐ!」やWordPressで運用している「SOFTBUILD」でmarkdownで書く癖がついてしまいました。

ネタがなくて困っていたところ、たなかさんが、「はてなブログに予約投稿するクライアントを作ろうかなーmarkdownライブラリがあったらエディタ作っちゃおうかなー」と言っていましたので、勢いでmarkdownをhtmlに変換するライブラリをWindowsストアアプリでも使えるように移植してしまいました。

今、見返したら全然そんなこと言ってなかった……。

WindowsストアアプリとWindows Phone 8では同じコードがほぼそのまま使うことができるため、移植した「Markdown4winrt」ではついでにWindows Phone 8対応もおこないました。Windows Phone 8対応と言ってもユニットテストのテキストファイルを読み込む処理を書き換えた位です。

と、ここまでがWindows Phone Advent Calendarでmarkdownについて書こうと思った経緯になります。そして本題。

markdownライブラリだけではなくて、フロント側も僕が作ることになってました(汗

そんな高機能なものは作れないので、markdownを入力したらその結果を表示させるような簡単なWindows Phoneアプリを作ってみましょう。

アプリの仕様を考えてみよう

面倒くさいので保存機能は一切なしという漢らしい仕様でいきましょう。

ただ漢であっても電話着信や瞬断で記入中のテキストが消えてしまうのは、きっと悲しいと思うので、エディタページとプレビューページとの切り替え時だけ保存してあげるようにしましょう。

markdownを解釈する機能はどうするか

これは冒頭でも紹介した通り、僕があらかじめ用意しています。

GitHub/CH3COOH/Markdown4winrtからダウンロードしてください。右側メニューに「Download ZIP」と書かれたボタンがあるので、クリックすると最新のソースコードを取得することができるはずです。

このMarkdown4winrtのfork元はMarkdownSharpです。このライブラリをWinRT/WP8向けで動かさられるように移植しました。テストコードも一通り移植してチェックしているので機能的な差異はないと思います。

markdownエディタを実装しよう

さて、早速アプリを作っていきます。

ソリューションの新規作成

Visual Studio 2013を起動します。新規プロジェクトの作成を選択して、テンプレートから「Windows Phone ピボット アプリ」を選択します。

f:id:ch3cooh393:20131204101701p:plain

名前はそのまんま「MarkdownEditor」にしました。

Markdown4winrtプロジェクトの参照

アプリからmarkdownライブラリを使いたいので、MarkdownEditorプロジェクトからMarkdown4winrtプロジェクトを参照します。

先ほどダウンロードしてきたZIPファイルを任意のフォルダへ解凍しておいてくださいね。

まずは、Markdown4winrtプロジェクトをソリューションに追加します。

ソリューションエクスプローラーでソリューション 'MarkdownEditor'を右クリックします。コンテキストメニューから追加既存のプロジェクトを選択します。

先ほどダウンロードしたMarkdownプロジェクトを追加します。

f:id:ch3cooh393:20131204101723p:plain

次にMarkdownEditorプロジェクトからMarkdownプロジェクトを参照します。

MarkdownEditorプロジェクトの参照設定を右クリックします。参照の追加を選択すると参照マネージャーダイアログが表示されます。

f:id:ch3cooh393:20131204101733p:plain

これでMarkdownEditorプロジェクト側からMarkdown4winrtの機能が使えるようになりました。

画面を作ろう

画面を作りましょう!とは言っても、ベースのテンプレートにピボットアプリを選択しているので、このレベルの画面でしたらすぐに作ることができます。

f:id:ch3cooh393:20131204230220p:plain

実質やったことと言えば、以下の通りです。

  • アプリケーション名を変更
  • PivotItemのHeaderを変更
  • PivotItemに元々入っている中身(ListViewとか)を削除
  • PivotItemにTextBoxとWebBrowserを追加

もうすでにXAMLを用意しておきました。上図の画面はこのようなXAMLで構成されています。

<phone:PhoneApplicationPage
    x:Class="MarkdownEditor.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://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:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"  Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <Grid x:Name="LayoutRoot" Background="Transparent">

        <phone:Pivot x:Name="pivot" Title="MARKDOWN EDITOR" 
                SelectionChanged="pivot_SelectionChanged">

            <!-- 編集領域 -->
            <phone:PivotItem Header="edit">
                <TextBox x:Name="editorArea" AcceptsReturn="True" />
            </phone:PivotItem>

            <!-- プレビュー領域 -->
            <phone:PivotItem Header="preview">
                <phone:WebBrowser x:Name="previewArea" />
            </phone:PivotItem>

        </phone:Pivot>

        <Image Source="/Assets/AlignmentGrid.png" VerticalAlignment="Top" 
            Height="800" Width="480" Margin="0,-32,0,0" Grid.Row="0"
            IsHitTestVisible="False" />
    </Grid>

</phone:PhoneApplicationPage>

これで画面の実装が完了しました。

ページ遷移時に保存してからmarkdownへの変換

Pivotはフリックでページを左右する際に、SelectionChangedイベントが発生します。MainPageではそのSelectionChangedイベントハンドラ内で、ユーザーが記述したテキストの保存とmarkdownへの変更をおこないます。

MainPage.xaml.csは、下記のようになっています。ここから手を入れていきましょう。

using Microsoft.Phone.Controls;
using System.IO;
using System.IO.IsolatedStorage;
using System.Windows.Controls;

namespace MarkdownEditor
{
    public partial class MainPage : PhoneApplicationPage
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private async void pivot_SelectionChanged(object sender, 
            SelectionChangedEventArgs e)
        {
            var pivot = sender as Pivot;
            if (pivot == null)
            {
                return;
            }

            // ここにページ遷移時の処理を書く
        }
    }
}

まずは、テキストの保存をおこないましょう。Windows Phoneアプリでテキストを保存するには分離ストレージ(IsolatedStorage)を使います。

SaveTextAsyncメソッドでテキストを保存する処理を実装します。

SaveTextAsyncメソッドでは、IsolatedStorageFileクラスのGetUserStoreForApplicationメソッドでストレージの管理オブジェクトを取得します。あとはOpenFileメソッドでファイルを作成しテキスト情報を保存しています。

ページの切り替わりイベントハンドラのpivot_SelectionChangedメソッドにて、入力されているテキストを保存する処理の実装ができました。

        private async Task SaveTextAsync(string text)
        {
            var store = IsolatedStorageFile.GetUserStoreForApplication();
            using (var strm = store.OpenFile("log.txt", FileMode.OpenOrCreate))
            using (var writer = new StreamWriter(strm))
            {
                await writer.WriteAsync(text);
            }
        }

        private async void pivot_SelectionChanged(object sender, 
            SelectionChangedEventArgs e)
        {
            var pivot = sender as Pivot;
            if (pivot == null)
            {
                return;
            }

            // 入力されているテキストを保存する
            await SaveTextAsync(editorArea.Text);
        }

次は、markdownを変換してみましょう。こちらの方が簡単かもしれません。

MarkdownSharp.Markdownクラスのインスタンスmarkdownを生成します。MarkdownクラスのTransformメソッドにユーザーが入力したテキストを渡すと、markdownをHTMLに変換したテキストを得ることができます。

HTMLを表示させるにはWebBrowserコントロールのNavigateToStringメソッドを使います。

        private async void pivot_SelectionChanged(object sender, 
            SelectionChangedEventArgs e)
        {
            var pivot = sender as Pivot;
            if (pivot == null)
            {
                return;
            }

            // 入力されているテキストを保存する
            await SaveTextAsync(editorArea.Text);

            // markdownからhtmlに変換してプレビューページに表示する
            var markdown = new MarkdownSharp.Markdown();
            var transHtml = markdown.Transform(editorArea.Text);
            previewArea.NavigateToString(transHtml);
        }

これでmarkdownをHTMLに変換して表示させるWindows Phoneアプリができました。

こんな感じになりました

実際にWindows Phoneエミュレータで動かしてみましょう。エディタページで下記の文章を入力しました。

* 近い
  * ch3cooh
* 遠い
  * 🐱

ピボットをフリックして、プレビューページで見た時にどのようになっているか確認しましょう。

f:id:ch3cooh393:20131204230233p:plain

入力した通り綺麗にプレビューで表示されているのが確認できます。

おわり。

Windows Phoneでネットワーク接続状況が変わったイベントを取得する(接続状態の変化を検出する)

System.Net.NetworkInformation名前空間のNetworkChangeクラスを使用することで、Windowsストアアプリ内でネットワーク接続状況が変わったのを取得する事ができます。

NetworkChange.NetworkAvailabilityChangedイベントにイベントハンドラを設定することで、ネットワークへの接続状況が変化するとイベントが発生します。

// using System.Net.NetworkInformation;

public static void Main()
{
    NetworkChange.NetworkAvailabilityChanged += new 
        NetworkAvailabilityChangedEventHandler(AvailabilityChangedCallback);
}

static void AvailabilityChangedCallback(object sender, EventArgs e)
{
    // IPアドレスが変わったのを検知する
}

参考

関連記事

blog.ch3cooh.jp