Xamarin.Forms で .NET Standard を利用してファイルアクセスするまで

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を取り込めません。

<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 をこんな感じで修正しておいて、

<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ボタンをクリックしたときのイベントがこんな感じ。

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は必須な感じがします。

カテゴリー: 開発, Xamarin パーマリンク