Xamarin.Forms プロジェクトのPCLを .NET Standard 化する方法を調べていくと、Visual Studio 2017 のリリース前だったりするので、project.json の変更があって「あれ?」となってしまうので、ちょっと記録的に。
ちなみに、この記事も半年ぐらい経つと意味がなくなるような気がするので、まあ、そのときはそのときで。
Xamarin.Formsでプロジェクトを作る
普通にXamarin.FormsでPCLを使ったプロジェクトを作ります。
Visual Studio 2017 の場合は、コード共有で「ポータブルクラスライブラリ」のほうを選択。
.NET Standard のクラスライブラリを追加する
[Visual C#]→[.NET Standard]で、「クラスライブラリ(.NET Stanrdard)」を追加
.NET Standardのプロジェクトを編集して、PackageTargetFallbackの部分を追加。これがないと、NuGetからXamarin.Formsを取り込めません。
1 2 3 4 5 | < Project Sdk = "Microsoft.NET.Sdk" > < PropertyGroup > < TargetFramework >netstandard1.6</ TargetFramework > < PackageTargetFallback >$(PackageTargetFallback);portable-net45+win8+wp8+wpa81;</ PackageTargetFallback > </ PropertyGroup > |
その後で、NuGetからXamarin.Formsをインストールします。
PCLプロジェクトからファイルをコピー
ソリューションエクスプローラで、「App.xaml」と「MainPage.xaml」をマウスでドラッグして、.NET Standardのプロジェクトにコピーします。
csprojファイルを開いて、ItemGroupのところをコピーしてもよいです。
Properties/AssemblyInfo.cs ファイルだけはコピーしません。内部的に、AssemblyTitle やらが作らている模様。
ちなみに、.NET Standardプロジェクトを追加したあとで、PCLプロジェクトをアンロードすると二度とロードできないという現象が発生します。なんだかなー。そういうときは、一度、.NET Standardプロジェクトを外して、PCLプロジェクトをロードします。
この手順を逆にして、.NET Standardプロジェクトのcsprojの内容を、PCLプロジェクトのほうにコピーしてもOKです。
Xamarin.iOS/Adnroidプロジェクトの参照を変更する
Xamarin.iOS/AdnroidプロジェクトからPCLプロジェクトが参照されているところを、.NET Standardプロジェクトのほうに変更します。
と、同時に Xamarin.Forms のバージョンも合わせておきます。
これでやっとこさ、Xamarin.Formsで.NET Standardが使える状態が完了です。まあ、ここまで作れたものをXamarin.Formsのプロジェクトテンプレートとして置いておけばよいので、一度作れると後は楽かも。
試しにファイルアクセスさせる
MainPage.xaml をこんな感じで修正しておいて、
1 2 3 4 5 6 | < StackLayout > < Label Text = "Welcome to Xamarin Forms!" /> < Button Text = "save" Clicked = "Save_Clicked" ></ Button > < Button Text = "load" Clicked = "Load_Clicked" ></ Button > < Label x:Name = "text1" Text = "output" /> </ StackLayout > |
Save/Loadボタンをクリックしたときのイベントがこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | private async void Save_Clicked( object sender, EventArgs e) { var path = "/data/user/0/App18.Android/files/" ; var st = System.IO.File.Open(path + "sample.txt" , FileMode.OpenOrCreate); using ( var sw = new StreamWriter(st)) { await sw.WriteLineAsync( "sample data" ); } } private async void Load_Clicked( object sender, EventArgs e) { var path = "/data/user/0/App18.Android/files/" ; var st = System.IO.File.Open(path + "sample.txt" , FileMode.Open); using ( var sr = new StreamReader(st)) { var text = await sr.ReadToEndAsync(); text1.Text = text; } } |
Xamarim.iOS/Androidであれば、「System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments)」と書くところが、パスを直書きになっているのがアレですね。iOS/Androidの場合分けが必要でしょう。どうやって書くのか判りませんが。
Xamarin.Forms の場合は、System.IO.Fileがないので、これが使えるということは無事 .NET Standard 化しているということです。
Androidエミュレータで実行すると、こんな感じになります。
じゃあ、PCLは.NET Standardに完全に置き換わるのか?
standard/docs/netstandard-20 at master ・ dotnet/standard
https://github.com/dotnet/standard/tree/master/docs/netstandard-20
を見る限り、「No PCL left behind. Dakota can consume a PCL based assembly from a .NET Standard-based library without having to jump through hoops.」とあるので、生のままでPCLを使うことは少なくなるんでしょう。少なくともProfileの順列組み合わせ状態は激減するかなと。現状、あまり意味がないし。
その後は、.NET Standard が肥大化しちゃうか、機種依存な機能が漏れてしまうかのところなんだけど、いまのところXamarin.Formsに関しては下回りのPCLは必須な感じがします。