最新のモバイルWindowsプラットフォーム向けのクロスプラットフォームプログラミング

関連性



モバイルオペレーティングシステムの世界では、最初の2つの場所がAndroidとiOSで共有されています。 さまざまな企業のさまざまな測定基準と推定値によると、1つのオペレーティングシステムまたは別のオペレーティングシステムを1位にすることができますが、それらがリードしていることは間違いありません。 しかし、オリンピックのように、私たちはまだ青銅を持っています。 彼女を決めましょう。



数年前、あらゆる面でリーダーであったシンビアンは徐々に市場を去りました。 ブラックベリーは主にビジネスユーザーであり、主にアメリカです。 世界の他の地域ではそれほど一般的ではありません。 トレンドは、Windows Phoneが3位になったことを示しています。 そして、個人開発者であろうと会社であろうと、誰もが疑問を持っています。











答えは「はい!」です。そして今、その理由を説明します。 私の名前はVadim Balashovです。Windows8およびWindows Phoneのメール開発者であり、PocketPC 2003からモバイルWindowsを開発しています。



Windows Phoneの売上のシェアは拡大しています。 2012年には、2011年よりも速く成長しました。特に、Windows Phone 8がリリースされた最後の数か月のデータを見ると、成長はさらにダイナミックでした。 さらに、販売されたデバイスの数を推定するIDCによると、一部の国ではWindows Phoneが販売の10%を超えており、26か国の販売シェアはすでにBlackberryのシェアを上回っています。 同じIDCの予測によると、現時点でのWindows Phoneの売上の合計シェアは3.2%で、4年後には11.4%になります。 プラットフォームが勢いを増していることは間違いありません。







次に、Windows 8を見てみましょう。デスクトップシステムの市場は完全に異なります。ここでは、ユーザー数の推定値がわずかに異なります。 しかし、Windows 8の正式な発売から7か月後、つまり6月の初めにはすでに5.10%を占めています。 すでに最も人気のあるMac OS X 10.8以上のものです。







同時に、Windows 8のシェアは、減速することなく成長し続けています。







はじめに



モバイルWindowsの開発の見通しに疑問がなくなることを願っています。次に、これら2つのプラットフォームを同時に開発する方法についてお話します。



用語について少し。 WP7に関しては、プラットフォームの2つのバージョン-7.5と7.8を意味します。 場合によっては、Windows Phone 8についても個別に説明しますが、以前のバージョンとはいくつかの違いがあります。



Windows 8の用語では事態がさら​​に悪化しています。この記事では、最初にMetro UIと呼ばれたタッチコンポーネントについて説明します。 この場合、オペレーティングシステムのタブレットバージョン(モダンUIのみ)はWindows RTと呼ばれ、アプリケーションはストアアプリ(Windowsストア用のアプリケーション)と呼ばれます。 このさまざまな用語はすべて、Windows 8のリリース後に登場しましたが、実際には同じものを指しているため、この記事では単に「Windows 8」と言います。



物語



2010年10月にWindows Phone 7が導入されましたが、これは実際にMetroイデオロギーを実装した最初の製品でした。 このイデオロギーの基本は、Zune PlayerおよびX-Boxで以前に登場しましたが、まだ完全には定式化されていませんでした。 Windows Phone 7は、「実行方法」、「配置方法」、「実行しないこと」というガイドとともに既にリリースされています。 したがって、トレンドを設定したのは彼女でした。 歴史的に、次のものはWindows 8でした。これは、デスクトップシステムの特性により、独自の特性があります。これは、大きな画面で、アプリケーションに割り当てられたわずかに異なるタスクです。 そして最後のプルアップはWindows Phone 8で、もちろん、古いアプリケーションの下位互換性のためにWindows Phone 7 APIを完全に組み込みましたが、Store Appsを支えるWindows RTカーネルからAPIを部分的に吸収しました。







上の矢印は、3つのシステムすべてのAPIの共通サブセットを示しています。 つまり、このサブセットのAPIを使用して、3つのシステムのコードを同時に開発できます。



単一のプロジェクトの利点は明らかです。ビジネスロジックの単一の実装、単一の機能、異なるユーザーインターフェイスを備えた単一のユーザーエクスペリエンスです。 つまり、それが電話であろうとタブレットであろうと、ユーザーは同じアクションを実行しても同じ結果を取得し、もちろん満足しています。 製品の観点から見ると、3つのプラットフォームすべてが一度にカバーされるため、これは総開発時間の短縮になります。 もちろん、3つのプラットフォームを個別に使用する場合よりも多くの時間がかかりますが、合計時間は短くなります。

欠点の中でも、プロジェクトの開始時の複雑さの増大-アーキテクチャ全体をすぐに展開する必要があります。これについては以下で説明します。 プロジェクトのサポートおよび開発時には、アーキテクチャが少し複雑になります。 したがって、プロジェクトの維持管理はより難しく、新しい開発者を業務に導入することはより困難です。 また、機能について妥協する必要がある場合があります。プラットフォームの1つがまったくサポートしていない場合、可能であれば、不足している機能を独自に実装するか、すべてのプラットフォームの制限内に収まるようにプログラムの動作を変更する必要があります。



MVVM



MVVMパターンについて少し説明します。 iOSプラットフォームの同僚から既に2回質問がありました。「なぜサービスロケーターではないのですか?」。 MVVMは、おそらく「サービスロケーター」イデオロギーの次のステップであり、データとデータ処理メソッドが一緒に配置されます。 ここでそれらは分割されています。







モデルはデータのみです。つまり、 データを格納するフィールドのセットを含む最も単純なクラス。場合によっては、いくつかの単純なフィールド処理、またはFirstNameプロパティとLastNameプロパティを連結するFullNameフィールドなど、他のフィールドに基づいて計算されるフィールド。



ビューは、インターフェースでデータがどのように見えるか、つまり ユーザーに表示されるもの。



ViewModelは、ViewとModelを接続するものです。 実際には、UIでのデータ処理とプレゼンテーション。 ViewModelは、UIでの正しい表示のためにデータを準備し、ユーザーのアクションの結果としてモデルを変更します。







スキームを拡張して、ここにデータハンドラー(データを準備するメソッド)を追加しましょう。 LowLevel-これらは、クロスプラットフォームにできない最下位レベルの機能です。 この記事では、そのような機能の例として、ディスクおよびネットワーク機能があります。

メールアプリケーションの操作の例を使用して、このスキームの操作を考えてみましょう。 反時計回りの方向を取り、手紙を受け取る場合を考えます。



ユーザーがその手紙を本当に気に入ったとしたら、彼はそれにフラグを立てたいと思います。 私たちは反対方向に進みます:



クロスプラットフォーム開発とプラットフォーム依存コンポーネントについて説明しているため、最初の明示的な依存コンポーネントはViewです。 明らかに、タブレットデバイスと電話では、プログラムは異なって見えるはずです。 2番目の依存要素は低レベル関数です。 プラットフォームの仕様により、さまざまな機能を使用する必要があります。たとえば、ローカルストレージの操作とネットワークを介したデータ送信の実装方法は異なります。



プラットフォームに依存しないコンポーネントは、それぞれ、Model、ViewModel、およびDataHandlerです。



モデル 、つまり 携帯電話でもタブレットでも同じ文字。 1つの形式でサーバーから取得されます。 作業する特定のフィールドセットがあります。



ViewModelは、レターデータの処理とその表示の準備です。 HTMLでレターの本文をラップする必要がある場合-これはすべてのプラットフォームで実行する必要がありますが、少し異なります。 また、ユーザーの行動に対する反応は、単一のユーザーエクスペリエンスを作成するためにすべてのプラットフォームで同じでなければなりません。



データハンドラは、プログラムが動作するモデルで、ネットワークを介して送信されるか、ディスクに保存されるフォームからのデータの準備です。 たとえば、サーバーからJSONを受信した場合、すべてのプラットフォームでJSONが送信されます。 それを解析し、モデルを作成する必要があります。 それは常に同じように起こります。







図では、プラットフォームに依存するプロジェクトが青で強調表示され、プラットフォームに依存しないプロジェクトがオレンジで強調表示されて構造が視覚化されています。 実際、循環チェーンでは、極端な要素のみがプラットフォームに依存し、中間の要素はすべて独立しています。



それでは、もう少し高度なスキームに移りましょう。







プラットフォーム依存のプロジェクトが左側に表示されます。 これらは、Windows Phone 7、Windows Phone 8、およびWindows 8のプロジェクトです。図の右側には、プラットフォームに依存しないプロジェクトが示されています。 実際、これらは1つのソリューションに含まれる6つのプロジェクトです。 LowLevel関数は、個別のプロジェクトごとに独自の方法で実装されます。 3つの異なる実装があります。 さらにDataHandlersはモデル、Viewモデルを備えたモデル、およびViewモデルはView、つまりインターフェースを備えている必要があります。 したがって、3つのプロジェクトのインターフェースは異なるため、ViewModelsはそれぞれ各プロジェクトの特定のView実装で動作します。



クロスプラットフォームMVVMの実装



クロスプラットフォームの実装についてもう少し説明します。 ViewModelがデータが変更され、これらの変更を表示できることをユーザーインターフェイスに通知するには、ViewPropertyをIPropertyChangeインターフェイスから継承する必要があります。







ほとんどのアプリケーションには複数のViewModelがあるため、各ViewModelにこのインターフェイスを実装することは実用的ではなく、単一のViewModelBaseクラスを定義することをお勧めします。



特殊なケースはリストです。 リストの場合、ObservableCollectionを使用すると便利です。ObservableCollectionは、リストアイテムの構成の変更をUIに自動的に通知します。







このコンテナの利点は、何かが変更されたことをUIに個別に通知する必要がないことです。 欠点は、多数の操作を行うと、ビューが頻繁に更新されるため、アプリケーションのパフォーマンスに影響する可能性があることです。



反対の状況は、フラグ付きの場合のように、ViewModelのViewからコマンドを取得する必要がある場合です。







このようなコマンドは、ICommandインターフェイスから継承する必要があります。 状況はここでも同じです-基本的なCommandBaseコマンドを作成して、それを操作します。 どのプログラムでも、ViewModelsよりも多くのコマンドがあります。



次に、データハンドラについて説明します。 データプロセッサは、モデル内のネットワークを介して受信した生データの変換に実際に関与しています。 そして逆の状況は、ViewModelsからの変更またはコマンドを(フラグを設定する場合のように)サーバーへのコマンドに変換することです。



2番目のケースは、ストレージの使用です。 受け取った手紙はすべて、次回ネットワーク経由でアップロードしないように保存する必要があります。 ほとんどの場合、データを保存するとき、文字を保存する形式はネットワーク経由で送信するときと同じではありません。 保存するために、モデルはストリームまたはバイト配列にシリアル化され、低レベル関数に渡されます。



低レベル関数は、プラットフォームに依存しない関数であり、プラットフォームに依存することはできません。 できる限り少なくする必要があります。 それらは、実際にクロスプラットフォームにできない最小限の機能を搭載している必要があります。 たとえば、ディスク/ネットワークを操作するには、低レベルオブジェクトがSaveBytes / SendBytesとLoadBytes / ReceiveBytesの2つの関数を提供する必要があります。 その他の機能(整合性チェック、初期処理など)は、DataHandlerに転送する必要があります。



言い換えれば、LowLevel関数を一般的な関数から分離するには、DataHandlerに残してはならないものを理解する必要があります。 この最小値はLowLevel関数になります。



プラットフォーム依存のコンポーネント



4つのプラットフォーム固有のタスクを検討します。ネットワークでの作業、リポジトリでの作業、リポジトリでの作業(設定での作業)、フローのディスパッチの個別のケースです。



ポータブルクラスライブラリには、HttpRequestクラスとHttpWebRequestクラスが含まれています。 これらのクラスは、HTTPを介してサーバーとの作業を完全に実装するのに十分です。 ただし、使用できるすべての機能を備えていません。 たとえば、Windows 8のAPIにはHttpClientクラスがあり、これはトラフィックの圧縮をサポートし、さらにPOSTリクエストを処理するのに非常に便利です。 実際、オブジェクトはクラスに渡され、POST要求を生成します。 HttpRequestの場合、RFCに従ってPOST要求をほぼ手動で生成する必要があります。



したがって、プラットフォームごとにWebサービスを操作して、各プラットフォームの機能を最大限に活用することをお勧めします。 これには最初は少し手間がかかりますが、ユーザーは満足し、すべてがより速く、より安定して動作し、トラフィックが節約されます。



ローカルストレージ。 Windows PhoneはiPhoneのように機能し、すべてのプログラムはIsolatedStorageにのみアクセスできます。つまり、1つのプログラムは別のプログラムのデータにアクセスできません。 IsolatedStorageFileクラスを使用してファイルを操作します。

Windows 8は、これがデスクトップオペレーティングシステムから派生したブランチであるという事実により、電話へのアクセスほどハードドライブへのアクセスを制限しません。 ディスクでの作業には、ApplicationDataクラスがあります。



興味深い状況は、Windows Phone 8です。WindowsRTからAPIの一部を継承しているため、Windows Phone 8はIsolatedStorageFileとApplicationDataの両方を使用してストレージにアクセスできます。 データを保存する場所は完全にあなた次第です。 3つのプラットフォームすべてを開発している場合、Windows Phoneに同じストレージ、つまりIsolatedStorageFileを使用することをお勧めします。 アプリケーションを開発するプラットフォームとしてWindows Phone 7を考慮しない場合は、Windows 8およびWindows Phone 8用のApplicationDataを使用します。



別の状況は、設定を保存するタイミングです。 一般に、設定の保存は他のデータの保存と変わりません。 設定は同じディスクストレージに保存されます。 ただし、設定については、システムはラッパーを提供します。これにより、特別な労力をかけずにキーと値の辞書を保存できます。 状況はディスクストレージに似ています。WindowsPhoneの場合はIsolatedStorageSettings.ApplicationSettings、Windows 8の場合はApplicationData.Current.LocalSettingsです。 また、Windows Phone 8の興味深い状況:APIには設定を操作するための両方のクラスが含まれていますが、実際には、LocalSettingsに設定を保存しようとするとNotImplementedExceptionがスローされます。 つまり、設定クラスへのリンクがありますが、実際には、このリンクの背後には何もありません。







自分で設定を使って作業を行うことをお勧めします。設定辞書を作成し、お好みのシリアライザーでシリアル化し、ローカルドライブに保存します。



スレッドマネージャについて少し説明します。 Windows PhoneおよびWindows 8のLowLevel関数は、ネットワークまたはUIストリームのディスクにリクエストを送信しても、バックグラウンドストリームで答えが返されるように実装されています。 これは、長い操作でUIがブロックされないようにするためです。 便利なことに、開発者はネットワークにアクセスするためのバックグラウンドスレッドの作成について心配する必要がありません。 同時に、UIストリームのみのユーザーインターフェイスに(受信され、何らかの方法で既に処理された)データを表示できます。 ここで、「バックグラウンドスレッドからUIスレッドにどの時点で切り替える必要がありますか?」という疑問が生じます。



UIストリームへの移行は、データの表示準備ができたことをUIに通知するデリゲートの送信先であるDispatcherの呼び出しを通じて行われます。







問題は、ディスパッチャがプラットフォーム固有であることです。 Windows 8とWindows Phoneの両方にディスパッチャが含まれており、それらの作業の本質は、UIストリームのバックグラウンドストリームから転送されたデリゲートを実行するという事実にあります。 しかし同時に、それらは異なる方法で実装されます:それらは異なるNameSpace'ahに置かれ、呼び出しは異なる名前のメソッドに行き、異なるパラメーターを取ります。



スケジューリングを行うことができるポイントを考慮してください。 プラットフォームに依存するLowLevel関数で暗黙的なスケジューリングをすぐに行うことができます。データ処理の結果をディスパッチャーでラップし、UIストリームに既にあるDataHandlerに転送します。 DataHandler、Model、ViewModelがあると非常に便利です。ストリーム、ディスパッチャなどについて誰も何も知らないため、すべてがシンプルで透過的です。







設計面では高速ですが、使用面では低速です。 ネットワークから突然大量のデータを受信した場合、DataHandlerでのプライマリ処理が発生し、さらにViewModelでの追加処理が可能になるまで、UIスレッドは常にビジーになり、アプリケーションはフリーズします。 その瞬間にアプリケーションでアニメーションが実行された場合、それらはフリーズし、処理後に続行します。 ユーザーの観点から見ると、アプリケーションはスタックしているように見えます。



明示的なディスパッチの場合、ViewModelからディスパッチャーへのアクセス権が必要です。 これは、一部のViewModelLocator、つまりすべてのモデルを結合する場所で最も便利に行われ、すべてのモデルがこのロケーターにアクセスできます。 したがって、データの一次処理、モデルの形成、および表示用のデータの準備は、バックグラウンドストリームで実行できます。 ユーザーインターフェイスが応答し、進行状況バーが実行され、スピナーが回転し、ユーザーはプログラムがビジーであるがフリーズしていないことを理解します。 データの準備ができた瞬間、つまり、ViewModelを終了する前でも、UIストリームに制御を移し、データが更新されて表示できることをインターフェイスに伝える必要があります。







ディスパッチャへのクロスプラットフォームアクセスを取得する最も簡単な方法は、ViewModelLocatorでアクションタイププロパティ(DoDispatchedなど)を作成し、アプリケーションの起動時にこのプロパティを初期化することです。



Windows Phone 7および8の場合、次のように初期化されます。



DoDispatched = action => Dispatcher.BeginInvoke(action);







Windows 8の場合、ほとんど同じことを行いますが、呼び出しの詳細に従って、優先度を追加で示します。



DoDispatched = action => Dispatcher.RunAsync(priority, action.Invoke);







呼び出しの違いから、ディスパッチャはプラットフォームに大きく依存していることが明確にわかりますが、ViewModelをアクションでラップすると、違いが気にならない場合があります。 ViewModelはDoDispatchedを呼び出し、UIスレッドの実行に必要なもののデリゲートを渡すだけです。



DoDispatched(() =>





{











}







要約すると、プラットフォームに依存するコンポーネントは実際には多くないことに注意してください。 クロスプラットフォームアプリケーションの開発を開始するには、データ取得を処理するプラットフォーム依存のクラスを作成するネットワークリクエストファクトリを作成し、ローカルストレージと設定を処理する作業を抽象化するクラスを作成し、ディスパッチャにアクセスするだけで十分です。 これは実際には、クラウドで動作する最新のモバイルアプリケーションの普遍的なヒントです。



この記事を読んだ後、あなたがすでに質問に答えられることを願っています:










All Articles