解析の問題を伴うWindows 8.1アプリのWindows Phone 8.0への移植





例として単純なWindows 8.1アプリケーションを使用して、WinRT(Windows 8.1)からSilverlight(WP8.0)にアプリケーションを転送するのがいかに簡単か、そしていくつかの落とし穴を分析する方法を見てみましょう。





Windows / Windows Phoneアプリケーションを開発する高度な方法-ユニバーサルアプリについて聞いたことがあると思います。 このアプローチは堅牢ですが、WP8.1の市場シェアは成長し始めており、アプリケーションを今すぐ実行する必要があるため、WP8.0(Silverlight)に焦点を当てましょう。 利点:WP8.0とWP8.1の両方のデバイスのサポート、黒いバーのないすべてのタイプの画面のサポート(WP7アプリケーションとは異なります)、安定したサードパーティライブラリなど



ソースアプリケーションについて簡単に





実験的なウサギは、基本的な為替レートを表示するためのほとんどすぐに使える単一ページのWindows 8.1アプリケーションになります。



アプリケーションは無料で広告がないため、機能は厳密に制限されています。 最も必要な機能のみ:平均為替レート(USD、EUR、RUB)の表示、過去30日間の変動グラフ、銀行レートの表示、通貨コンバーター、ライブタイルのサポート。

サーバー部分は舞台裏に残します。 面白いものは何もありません。



プロジェクト構造





ユニバーサルアプリに注目すると、メインブロックはユーザーコントロールに転送され、データクラスはポータブルライブラリに転送され、データの受信を担当するコードはUIから分離されます。



Windows Phone 8.0へのコードの転送


空のプロジェクトを作成し、MainPageから余分なものをすべて捨て、必要な参照とNuGetパッケージを追加します。 まず、クラスファイルとして追加します(追加->既存のアイテム-> リンクとして追加 )。Windows8プロジェクトのデータを処理するためのクラスファイルです。



問題は次のとおりです。


namespace名前空間が収束することを期待する必要はありません(WinRTとSilverlight)。したがって、ウォームチューブ#if #endifを使用すると、次のようになります。

#if NETFX_CORE using Windows.Web.Http; using System.Runtime.InteropServices.WindowsRuntime; using Windows.Networking.BackgroundTransfer; #endif #if WINDOWS_PHONE using System.Net.Http; #endif
      
      





ユニバーサルアプリは使用していませんが、Visual Studio 2013 Update 2を使用すると、プラットフォームごとに#if #endifを使用した作業が大幅に簡素化されることに注意する必要があります。 コードのすぐ上に別のドロップダウンリストが表示され、ファイルを再度開かずにプラットフォームをすばやく切り替えることができます。 IntelliSenseがクラッシュすることはなくなり、Resharperは最も不適切な瞬間に脱落しなくなりました。 もう「このドキュメントは別のプロジェクトによって開かれています。」など



WP8.0では使用できないHttpClient(後でHttpClientを使用する理由が明らかになる)を使用してデータを読み込むため、Microsoft.Net.HttpパッケージNuGetを追加します。 しかし、ここでは、驚くことなく、#ifなしではできません。

  var client = new HttpClient(); byte[] buff; #if NETFX_CORE var ibuff = await client.GetBufferAsync(uri); buff = ibuff.ToArray(); #endif #if WINDOWS_PHONE buff = await client.GetByteArrayAsync(uri); #endif
      
      





バックフィルの質問、HttpClientの公式実装はいくつ知っていますか?



received受信したデータをデバイスのメモリに保存します。これにより、インターネットに接続していないときに次回表示するものが表示されますが、...

 #if NETFX_CORE var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(LOCAL_DATA_FILENAME, CreationCollisionOption.ReplaceExisting); await FileIO.WriteTextAsync(file, json); #endif #if WINDOWS_PHONE var fs = await ApplicationData.Current.LocalFolder.OpenStreamForWriteAsync(LOCAL_DATA_FILENAME, CreationCollisionOption.ReplaceExisting); using (StreamWriter streamWriter = new StreamWriter(fs)) { await streamWriter.WriteAsync(json); } #endif
      
      





ここでは、LocalFolderとLocalCache(WP8.1以降)の違いを覚えておく価値があります。主な違いは、LocalCacheとは異なり、LocalFolderは組み込みのバックアップ/復元(ローミングと混同しないでください)の対象であり、その結果、データが完全に異なるデバイスにある可能性があることです(またはいくつか)それが意味するすべてのもの。 この仕組みの詳細については、 こちらをご覧ください 。 私たちの場合、WP8.0のLocalCacheは使用できないため、使用しているものを使用します。



◊これとは別に、データ暗号化のサポートに言及する価値があります。歴史的に、プロジェクト間をさまようAESを使用した自己記述クロスプラットフォームバイナリ互換暗号化クラスが既にありました。 このクラスの説明はこの記事の範囲を超えています。WP8.0では素晴らしいクラスAesManagedがあり、WinRTではネイティブ実装にマッパーを使用しているとだけ言います。

 #if NETFX_CORE using Windows.Security.Cryptography; using Windows.Security.Cryptography.Core; using Windows.Storage.Streams; #else using System.Security.Cryptography; #endif
      
      







UIをWindows Phone 8.0に移植する






補助コードが移植され、正常にコンパイルされた後、インターフェイスを取り上げます。 なぜなら 電話、タブレット、デスクトップは同じものではありません。 したがって、アプリケーションは異なって見えます。 このため、Windows 8およびWindows Phoneプロジェクトには独自のMainPageがあり、ユーザーコントロールをリンクとして追加します(リンクとして追加、将来的にはこれはすべて共有プロジェクトに移動します )。 さらに、コントロール自体は、使用可能なスペースの幅などの状況に適応します(Windows 8のスナップモードを忘れないでください)。



問題は次のとおりです。


first最初に行うことは、同じ#if #endifを使用してクラスの背後にあるコード内の名前空間を分離することです。例は示しません。赤の下線付きのすべてに対してShift + Alt + F10を使用します。



so WP8.0にはDataContextChangedイベントがなかったため、それを取り除くためにロジックを少し変更しました。



WP WP8.0では、「SymbolThemeFontFamily」、「BaseTextBlockStyle」、「BodyTextBlockStyle」などのWinRTのXAMLからの組み込みスタイルがないため、WP8.0プロジェクトで別のResourceDictionaryを作成します。 「c:\ Program Files(x86)\ Windows Kits \ 8.1 \ Include \ winrt \ xaml \ design \ generic.xaml」を開き、必要なものをすべて削除して、新しく作成されたResourceDictionaryに入れ、同時にサポートされていないものを置換または破棄します電話で(CharacterEllipsis-> WordEllipsis、SemiLight-> Light、Typography。*-> c:\ NUL)。

次に、この参照をApp.xamlに保持します。

  <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="CommonStyles.xaml"/> </ResourceDictionary.MergedDictionaries> <local:LocalizedStrings xmlns:local="clr-namespace:BXFinanceWP" x:Key="LocalizedStrings"/> </ResourceDictionary> </Application.Resources>
      
      





Application.Resourcesに既に何かがある場合(たとえば、LocalizedStrings、最初の段階でそれを捨てなかった場合)、上記のようにResourceDictionary内に置く必要があります。



why理由はわかりませんが、IValueConverterインターフェイスはWinRTとSilverlightでわずかに異なるため、プロジェクトにあるすべての一般的な(リンクとして追加された)コンバーターを修正します。

  public object Convert(object value, Type targetType, object parameter #if NETFX_CORE ,string language #endif #if WINDOWS_PHONE ,System.Globalization.CultureInfo culture #endif )
      
      







next次に対処しなければならなかったのは、XAMLでサードパーティの名前空間を宣言する際の違いでした。 WinRTでは、名前空間は「using:」で記述され、Silverlightでは「clr-namespace:」で記述されます。例:

 xmlns:Common="using:BXFinanceDashboard.Common" xmlns:Common="clr-namespace:BXFinanceDashboard.Common"
      
      





この問題に対する多くの解決策はなく、XAML用の#ifdefという単一の良い解決策もありません。 そのような場合、特定の状況に基づいて、コード内に必要なコントロールを作成し、カスタムビルドアクションに煩わされたり、スタイル設定可能なすべてのものを作成したり、インターフェースを一般的なプラットフォーム依存ファイルに分割したりできます。 最後の手段としてコピーアンドペースト。

しかし、私たちの場合、すべてがそれほど複雑なわけではありません。 ほとんどの場合、コンバーターを接続するには名前空間のアナウンスが必要でした。 そこで、各プロジェクトでResourceDictionaryを1つ作成し、そこでコンバーターを宣言しました。 また、アプリケーションは大きくないため、App.xamlでグローバルに接続しました。 さらに、コンバーターは再作成されませんが、名前はグローバルになり、繰り返し使用できないことに注意してください。

念のため、WinRT(Windows 8.1)のリストを提供します。

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Common="using:BXFinanceDashboard.Common"> <Common:HighlightValueConverter x:Key="HighlightUSDBuyConverter" HighlightBrush="#FFFF4646" /> <Common:HighlightValueConverter x:Key="HighlightUSDSellConverter" HighlightBrush="#FFFF4646" /> <Common:HighlightValueConverter x:Key="HighlightEURBuyConverter" HighlightBrush="#FFFF4646" /> <Common:HighlightValueConverter x:Key="HighlightEURSellConverter" HighlightBrush="#FFFF4646" /> <Common:HighlightValueConverter x:Key="HighlightRUBBuyConverter" HighlightBrush="#FFFF4646" /> <Common:HighlightValueConverter x:Key="HighlightRUBSellConverter" HighlightBrush="#FFFF4646" /> <Common:BoolToVisibilityConverter x:Key="BoolVisibilityConverter"/> <Common:BoolToVisibilityConverter x:Key="BoolNotVisibilityConverter" IsReversed="True"/> <Common:OpacityConverter x:Key="OpacityConverter"/> <Common:OpacityConverter x:Key="OpacityNotConverter" IsReversed="True"/> </ResourceDictionary>
      
      





Silverlight(WP8.0):

 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:Common="clr-namespace:BXFinanceDashboard.Common"> <Common:HighlightValueConverter x:Key="HighlightUSDBuyConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:HighlightValueConverter x:Key="HighlightUSDSellConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:HighlightValueConverter x:Key="HighlightEURBuyConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:HighlightValueConverter x:Key="HighlightEURSellConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:HighlightValueConverter x:Key="HighlightRUBBuyConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:HighlightValueConverter x:Key="HighlightRUBSellConverter" HighlightBrush="#FFFF4646" NormalBrush="{StaticResource PhoneForegroundBrush}" /> <Common:BoolToVisibilityConverter x:Key="BoolVisibilityConverter"/> <Common:BoolToVisibilityConverter x:Key="BoolNotVisibilityConverter" IsReversed="True"/> <Common:OpacityConverter x:Key="OpacityConverter"/> <Common:OpacityConverter x:Key="OpacityNotConverter" IsReversed="True"/> </ResourceDictionary>
      
      







surprise驚きは、WindowsとWindows Phoneのフォントの違いでした。 何らかの理由で、「Segoe UIシンボル」から#128314 /#128315を選択してコース変更矢印を表示しましたが、それらが「上/下向きの赤い三角形」と呼ばれることはわかりませんでした。 Windowsでは、見た目どおりに表示されます。WindowsPhoneでは、両方とも再描画されていないため赤く表示され、さらに文字はすでに広くなっています。 まだ急いでいると、より適切な#9650 /#9660が見つかりました。 何が問題なのかすぐにはわかりませんでした。電話で比較する必要さえありました。





ちなみに、自分の写真ではなく、グリフ(特にアプリバーのボタン)を使用することを忘れないでください。 たとえば、Nokia 1520を使用した別のアプリケーションの画面など、さまざまなDPIの下で多数の画像を生成することにうんざりします。





アプリケーションを電話用に適合させます



アプリケーションは正常にアセンブルされていますが、停止しないでください。 それでも、モバイルはタブレットやデスクトップと同じではありません(ちなみに、デスクトップ上のアプリケーション自体が画面にハングアップすると更新され、あらゆる種類の情報パネルに便利です)。



レイアウト


コースチャート、銀行のリスト、通貨コンバーターを切り替えるために、Windows Phoneでよく知られているピボットコントロールを使用します。 トレイの電源を入れ(正当な理由なしにトレイを隠すのは悪いことです)、上部のインデントを調整して、トレイが多くのスペースを消費しないようにします。 幸いなことに、トレイを備えたWP8では、WP7よりも問題が少なく、ジャンプの頻度は低くなりますが、コードでは、Page.Loadedより早くトレイの色を指定できることを忘れないでください。 トレイとページの間のいストリップを避けるために、透明度を0.99に設定します。



携帯電話の画面はすでに広くなっているため、すべてのメインコントロールをそれに合わせて調整する必要があります(これはデスクトップのスナップモードにも役立ちます)。



銀行のリストには、十分なスペースがない場合に自動的に1つの通貨のみが表示され、下部にスイッチが表示されます。 さらに、ここでの重要な要件は、通貨を切り替えたときにリストのスクロールが保持されることでした。 つまり 必要な銀行に振り替える必要はありません。





次に、通貨コンバーターはいくつかの要素をラップし、幅を揃えます:





たとえば、状態を使用してこの動作を実現する方法はいくつかありますが、今回はコントロール自体にHorizo​​ntalAlignmentプロパティを追加しました。主なことは、StackPanelではなくグリッドで要素を散布することです。 例:

 <UserControlx:Name="Parent" HorizontalAlignment="Left"> <Grid x:Name="RootPanel"><Grid Grid.Column="1" HorizontalAlignment="{Binding HorizontalAlignment, ElementName=Parent}"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <ToggleButton x:Name="btnActionSell" Content="" Grid.Column="0" VerticalAlignment="Center" /> <ToggleButton x:Name="btnActionBuy" Content="" Grid.Column="1" VerticalAlignment="Center" /> </Grid>
      
      





そして、電話のMainPageにStretchを追加します。

 <Controls:CurrencyConverter x:Name="currencyConverterControl" HorizontalAlignment="Stretch" />
      
      





また、使いやすさの観点から、サポートされているすべてのDPIでキーボードが選択ボタンを閉じないことが非常に望ましいものでした。 さらに、金額を入力(または貼り付け)するときに、キーボードでドル記号またはユーロ記号を直接押すことができる(キーボードとフォントにはルーブル記号がまだない )ことを、対応する通貨切り替えで追加しました。





ライブタイル


アプリケーションはWindows Phone 8.0の下にあるので、 WNSについて考える必要はありません。そのため、電話では古き良き定期的バックグラウンドエージェントを使用します。 コードに違いはありません。最初の起動時に、ユーザーがバックグラウンドで更新を受信するかどうかを確認することを忘れないでください。 エージェントを使用することの副次的な効果は、たとえば、ユーザーが外出中にインターネットに接続していない場合、表示する古いデータがまだないことです(Windows 8.1では、この問題を少し異なって解決します。以下を参照)。 タイル用の画像を準備する場合、Windows Phoneではロゴが厳密に中央に(署名の有無にかかわらず)配置され、Windows 8ではわずかに上にシフトされることに注意してください。





グラフ


それとは別に、ゆらぎグラフの転送に言及する価値があります。 Windowsでの習慣から、グラフはControls.DataVisualizationを使用して実装されました(アプリケーションはUniversal Appsを念頭に置いて作成されましたが、Telerikコントロールはまだリリースされていません(執筆時点)。 そして判明したように、Windows Phone 8.0では通常のDataVisualizationポートはありません。 WinRT(Windws 8およびWindows Phone 8.1)にはWinRTXamlToolkitがあり、Windows Phone 7でも通常のSilverlightのいずれかを使用できました。 しかし、WP8.0では何もありません(WPToolkitでは、WP8への移植時にDataVisualizationは失われました)。 一般に、WP7以降、WPToolkitは「お願い」をやめません。

一般に、検索に30分を費やした後、彼は電話でTelericコントロールを投げ(おそらくWindows 8ではUniversal Appsのポートに行きます)、外観を調整し、悪い夢のように忘れていました。





キャッシング


Windows 8.1(WP8.1にはありません)では、すばらしい機能が登場しました。キャッシュするURLをOSに伝えることができます。 つまり 星が収束する場合(または、アプリケーションが定期的に使用される場合)、Windowsはアプリケーションの起動前に必要なデータをキャッシュします。 このことをContent Prefetcherと呼びます。 サーバーから特定のURLまたはxmlファイルリストを追加できます(データがニュースなどの動的な場合)。 簡単な例:

  public static void RegisterPrefetchUrls() { if (!ContentPrefetcher.ContentUris.Any(u => u.AbsoluteUri == LIVE_DATA_URL)) { ContentPrefetcher.ContentUris.Clear(); ContentPrefetcher.ContentUris.Add(new Uri(LIVE_DATA_URL)); } }
      
      





したがって、HttpClientを介して通常どおりデータをロードします。 ただし、 Windows.Web.Http.HttpClientでのみ機能します (WinInetを介して機能するものは、HttpClientの他の実装と混同しないでください)。 キャッシュからのみデータをロードする必要がある場合は、 Filters.HttpCacheReadBehavior.OnlyFromCacheフィルターを適用します。

ちなみに、VS Update 2には便利なメニューが表示され、OSがコンソールからのみデータをキャッシュする前に、デバッグのためにデータをキャッシュするように強制しました。 ただし、URLを示すために、アプリケーション自体を最初に起動することを忘れないでください。詳細はこちら





利用統計



今回は、Flurryではなく、Google Analyticsを接続することが決定されました。 Flurryは、( 私のものだけでなく )自身の統計と比較して間違った数値を表示することを傷つけます。 さらに、iOS / Android以外のプラットフォームのサポートが不十分で、Webパネルが非常に鈍い(再起動ごとに80を超えるHTTPリクエスト)。 私に関しては、Flurryはクロスプラットフォームゲームにのみ使用するのが理にかなっています。 インストール、アプリ内などを追跡するための非常に便利なツールがあります。



Windows / Windows Phoneには、既製のライブラリ「 Windows 8およびWindows Phone用のGoogle Analytics SDK 」があります。 統合は簡単ですが、例のようにOnNavigatedTo()からではなく、ユーザーが戻るボタンで戻るときにインプレッションをカウントするためにPage.LoadedからSendView()を呼び出すことをお勧めします。 また、analytics.xmlのバージョンフィールドにプラットフォームを追加しました。

 <appVersion>1.0.0.0 (WP)</appVersion>
      
      





アプリケーションの詳細に応じて、カスタムイベント(SendEvent())を追加することは理にかなっています。 例として、実際に通貨コンバーターを使用するユーザーの数や、Live Tileを無効にしたユーザーの割合は疑問です。



最後の仕上げ



アプリケーションページを作成します。ユーザーがIEメニューからアプリケーションを配置できるように、 msApplication-IDをメタタグに追加することを忘れないでください。 必要に応じて、ユーザーがWeb検索結果ページ(Windows 8.1 / Windows Phone 8.0 / 8.1)からアプリケーションを直接インストールできるように、アプリケーションをBingに登録します。

動揺する唯一のことは、Windows Phoneストア用のロシア語の「ダウンロード」ボタンがないことです(MSの担当者がコメントするかもしれません)。 マイクロソフトブランドを使用するためのルールに従う場合は、既製のイメージのみを使用する必要があり、それらを使用する場所と方法についてのガイドもあります。 その結果、ロシア語ではWindows Phoneストアにはボタンがなく、Windowsストアには「ダウンロード」という単語がないボタンはありません。 私はボタンの英語版を使用する必要があります:





おわりに



おもしろい点だけを選んでみましたが、何とか長くて混longとしました。 あなたが何かを見逃した場合は、コメントで尋ねてください。



All Articles