5/23 追記… //build 2015から一か月経ち、MSDNのドキュメントも大分整備されているので…ここの古い記述よりも、MSDNやBuild セッション等、MSの一次情報を見て頂いたほうがいいかと思います。
Build2015 Day1 Session 視聴メモ
http://ddlgjp.blogspot.jp/2015/05/build2015-session.html
Build2015 Day2 Session 視聴メモ
http://ddlgjp.blogspot.jp/2015/05/build2015-day2-session.html
(三日目は見る前にMSDN側の文書が出てきたので結局見てないです)
↓のメモ、そんなに外してはいないのですが… 一個大きく外しているのはデバイスファミリの扱いです。結局
ファミリを直で読めるAPIは存在しており、ファミリ毎に別個のUIを作ることができます。
ただBuildのセッションを見ていると、デバイスファミリとUIの持ち方については場合によりけりなのかな、という感じがします。
XAML Teamのセッションで強く打ち出されていたのは、各デバイスファミリで共通のXAML を使用し、
画面サイズのみに依存して画面構成をAdaptiveに変更することで
基本的にはいける、という考え方でした。
ファミリ毎に異なるUIを複数持つのは手間であり、また、Continuumのように「Win10 Mobileで動作するが、大きなモニタに接続した場合はWin10 Desktop『のような』UIを表示したい」 場合を考えると、安易にデバイスファミリ毎にUIを別に持つのは確かに危ない感じがあります。
一方、「SurfaceHub」…80インチの巨大画面を持つWin10システム、デバイスファミリは「Windows Team」…に合わせたアプリを書こう、というセッションは、あっさりデバイスファミリで場合分けして別UIをもりもり作る、というデモでした。 SurfaceHubの場合 Win10 Desktop / Mobile とはアプリのUsage Model が大きく異なるため、これもまた理にかなった書き方なのだろうと思います。
※ ContinuumについてはXAMLのUI Elementに怪しい感じのPropertyが生えているようなので…この先説明がされると思うんですが、現状まだよくわからん所はあります。
以下は4月頭時点での記述です。
-----
Windows 10 UAP について、2015年4月4日現在で一番詳しく書いているのはこの文書と思われます。
Guide to Windows universal apps
https://msdn.microsoft.com/library/windows/apps/dn894631.aspx
これを読んで自分なりに気の付いた所をまとめたよというお勉強メモです。//Build 前でもあり、
予想・憶測が多めに含まれているのでご注意下さい。
※分量が多くて全部見切れていないのですが、Microsoft Virtual Academyの動画
A Developer's Guide to Windows 10 Preview
http://www.microsoftvirtualacademy.com/training-courses/a-developers-guide-to-windows-10-preview
こちらではみんな大好きJerry Nixon がかなり突っ込んだ所まで動画で説明してくれてるようです。これもお勧め。字幕が無くてつらいけども。
※2015.04.19 - デバイスファミリをRuntimeに見分ける件について追記しました
※2015.04.25 - 複数のXAMLでCodeBehindをShareする件について追記しました
★★★
Win8.1 / WP8.1 "Universal" app
まず、今までの「Universal」Appについて軽く復習して何が違うのか理解の助けにしようと。
- Win・WPそれぞれの実行バイナリは別、プロジェクトも別
- 両者を1つのソリューション内に整理し、共用コードはShared フォルダに納める
- Shared内での差分はIFDEFで吸収
物凄く雑に言うと、二つの別バイナリを楽に作るための仕組み。
こう書くと結局設計時に分けてるだけで全然別じゃん?という印象であるが、実際作ってみるとUI等非共用部でも…WinRTとしては同じところが凄く多いので簡単ではある。
ただ、似たコードが増えるので保守的にはあまり宜しく無い。
CodeBehind から又ViewModel として共通部分を分離していけば綺麗にはなるが、毎回毎回MVVMだなんだと頑張るのもちょっとなーという所はあった。
Win10 UAP
実行時にデバイスのCapabilityを見て使うAPIを判断する、One Binary形式。
ルートにいるのがUniversal。
子供の各デバイスは全てUniversal App Platform としての機能と、加えてデバイス特有の機能を「Contract」として持つ。
※各Contract は排他では無い事に注意。例えばWindows.Devices.SmartCards.SmartCardDeviceContract はPC・電話両方に同じものが存在する。
VS2015 でテンプレート「Win10 UAP」で作成したアプリは「.NET for Windows Store App」と「Universal App Platform」をReferenceとして持つ。
このUniversal App Platform のNamespace範囲内で書く分には、それは上に挙げた全部で「動作」する。
(「動作」…動くけども、UIとして各デバイス用に作りこむかはまた別の話と思われる。この辺りの話は下のほうで又触れる。)
今までのWin8.1 / WP8.1 で言えば、例えばWindows.Storage, Windows.Storage.Stream 、それとUI…GridViewであるとか。そういう基本的な所はUniversal App Platform に格納されており、これらだけを使う分には Win10 では全てのDevice で使う事ができる。はず。
各デバイス特有の機能を使う場合、設計時にプロジェクトへExtension 単位で追加することになる。
現在使用できるのは
- Windows Desktop Extension SDK (所謂Win32 DesktopApp の事ではなく、PC・タブレットの事)
- Windows Mobile Extension SDK (電話 だがドキュメント読んでると、こっちに入る小さなタブレットも想定には入っているようだ)
の二つ。
例えば
PC・電話両方で動くOne Binary なアプリを作る場合、上二つのExtension 両方をReference として追加する事になる。
それぞれのデバイスが対応するContract 一覧はSDKManifest.xmlに書いてある。XBOX・IoT のExtensionはまだ拾えていない。
|
Desktop…PC・タブレット等 がサポートするContract |
|
Mobile 電話がサポートするContract |
実行時のCapability 確認
設計時から分かれているWin8.1/WP Universal とは対照的にUAP はOne binaryであるため、実行時にDevice のCapability を確認する作業が必要になる。
そのためのAPIが
Windows.Foundation.Metadata.ApiInformation。
型・イベント・メソッド単位で「これは現在実行中のデバイスで使用可能か」を取得し、OKなら使ってよし、という書き方が可能
Windows.Foundation.Metadata.ApiInformation
IsTypePresent
IsEventPresent
IsMethodPresent
...
ただメソッド単位とかやってられんので、
IsApiContractPresent 、Contract 単位で見るのが現実的な感じ。
手元のVS2015で試してみた様子
例えば、PC・電話 両方のExtension を追加したアプリで、電話だけにある機能 Windows.Phone.StartScreen.DualSimTile を
「PC上で」使おうとした場合…
var obj = new Windows.Phone.StartScreen.DualSimTile();
実はこれはPCで実行してもエラーにならない。
こいつを
await obj.UpdateAsync();
とすると、ここで初めて例外となる(DualSimTile ではたまたまコンストラクタで何もしてないからエラーにならないだけかも。ただインスタンスとして作れてしまうことは判る)。
勿論、正しい書き方は上で出たAPIを使い、
if( Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Phone.StartScreen.DualSimTileContract", 1, 0)
{
// hogehoge
}
というように、デバイスのCapability を見ることになる。
なお、Windows.Foundation.Metadata.ApiInformation には特にメタデータ変わったイベント等は無いので…アプリ動作中にデバイスが変わる心配はしなくて良い、はず。
Extension と Contract …デバイス間の境界はどこにあるのか
ここまでで気づくのは、設計時と実行時でCapability の粒度が異なる所。
- 設計時 Extension デバイス種別単位
- 実行時 Contractが最大 各機能単位
(おそらく)実行時にコード上で
「もしデバイスが電話なら」「もしPCなら」と切り分けができるようなAPI は用意されていないように見える。最大の単位はContract。
※もしあったらごめんなさい。ただ今回の見ててもそれっぽいのがなく、またWin8.1/WP8.1の時もWindows.Security.ExchangeActiveSyncProvisioning.EasClientDeviceInformation みたいな妙な所にしか無かったので…意図的に作って無い感じがするんですよねこれ。One Windows だから?
※2015/04/19 追記
以下の記事によると、
Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().QualifierValues の
Key"DeviceFamily" にファミリ名が入っているとの事です。実機でみた所、PCでは"Desktop", 電話では"Mobile"が入っていました。
Using Custom Visual State Triggers
http://www.sharpgis.net/post/2015/03/24/Using-Custom-Visual-State-Triggers
※2015/04/25 追記
以下の記事によると、
特定のDeviceFamily用にXAMLを持つことが可能であり、またXAMLは一つのCodeBehindを共有できるとの事です。
デバイスファミリ名のフォルダを作り、そこに同名のXAML(のみ)を置く
例)フォルダ'DeviceFamily-Mobile' 内に’MainPage.xaml'を置く
CodeBehindはRootのMainPage.xaml.csをシェア
又は
XAMLのファイル名をIdentifier付きにする
既定のDeviceFamily用→「MainPage.xaml」
特定のDeviceFamily用→「MainPage.DeviceFamily-Mobile.xaml」
(記事にある「XAML Viewの追加」メニューは僕のVS2015CTP6には無く、手動でフォルダにXAMLをコピーする必要がありました。)
Building adaptive layout in Windows 10 with RelativePanel and AdaptiveTrigger
http://blog.galasoft.ch/posts/2015/04/building-adaptive-layout-in-windows-10-with-relativepanel-and-adaptivetrigger/
|
電話用のMainPage.xaml がフォルダ DeviceFamily-Mobileに置いてある様子 |
|
XAMLのファイル名にIdentifierつけるのもアリ
CodeBehindは共通のMainPage.xaml.cs
|
|
既定の3カラムレイアウトがDesktopで動いている様子 |
|
電話用1カラムが動いている様子
(ScreenCaptureが動かないので写真です…) |
例えば実行時にExtension 単位で見分けることが出来れば便利かもしれないが、Extension は結局Reference であるため…
設計時にそれを追加したという話でしかない。つまり「アプリが走っているこのデバイスで使用可能かどうか」という情報では無い。
今回追加になったContract ではWindows.Fountation.Metadata.ApiInformationによってデバイスがその機能を実行可能かどうか、(アプリ)実行中に知ることができるようになったと。そんな理解で良いのではないかと思う。
また、Contract がこのように実行時にCapability を提供できるということは、デバイス自身がメタデータとして「自分は何を実行できるのか」情報を持っているという事でもある。
今のところは電話・PCで大別して「電話ならこれらのContractを全てサポート」という切り方だけども、将来的には「電話だけどこのコントラクトをAdditionalにサポート」みたいなデバイスも作ることはできるのかもしれない(出す出さないでなく、APIのありかたとして可能という意味)
UIと入力
ここまで見てきたCapability についてはデバイスにより有り・無しの厳然とした違いがあり、コードは実行時に確認することができた。
だがしかし、UIと入力については様子が随分異なる。
新規に追加されたRelativePanel と、拡張されたVisualState とInkCanvas 等を駆使して
Unifiedな一つのXAMLを、対象とするデバイス全てについて動かそうという考え方に見える。つまり、XAMLを「分ける」…Win8.1/WP Universal Appの様な「電話用XAML・PC用XAML」的な作り方はあまり想定されていないように見える。
勿論、電話用・PC用XAMLを作り分けページ遷移時に切り分ける、という方法はテクニカルには可能かもしれない。
だけれども、上のExtension とContract の扱いで分かるように、Win10 UAP では実行時環境を「デバイス単位」で切り分ける手段が(おそらく)無いため、間接的に「電話にしかないContract があるから電話」という切り方にならざるを得ず…この方法は可能だが正しいとは言いづらい。DualSimTile を持つPCが出てこないとは言えない。
むしろ、作り分けをせざるを得ないのならそもそもアプリを一つにまとめるのが無理な話で、アプリ別々に作ればいいのでは?と。UAP はそういうスタンスなのだろう、多分。
ストアへのDeploy(まだ情報が出て無い部分)
ここはまだ情報が出ていない。
1バイナリのUAPが完成したとして、それをストアへデプロイする際デバイス種別はどうなるの?ストアが勝手に分ける?その場合スクリーンショットは全デバイスで撮るの?全部で撮るんなら超めんどくせえな!!的な謎な部分は多い。
上の例で言えば、UAPの範囲内で作ったので動かせば全デバイスで動作はしてしまうけども、UIのサイズとしては電話しか想定していないアプリ、というのは当然存在するはずで、デプロイ時に開発者が「このアプリはこのデバイス用」と宣言する、のが自然な形なのではと思う。
また、Win8.1/WP Universalのように「バイナリ・パッケージは別だが、AppIDを共有しているので購入情報やRoaming Storageを同期している」電話用・PC用 Win10 UAP、という形もサポートされていると便利だと思うけど。どうなのかな。
余談
結局、Win8.1 / WP8.1 の 「Universal」Appは僅か1年でお役御免となった訳ですが…というか、MFC で10年以上ご飯食べられていた時代を思うとびっくりしちゃいますね。