nuget初心者がPlugins for Xamarinを利用して、nugetパッケージを作ってみた

# はじめに・・

Xamarin向けに以下の要件でライブラリを作る必要がありました。

* IF部分はPCLじゃなくて、.NET Standard2.0対応してほしい
* プラットフォーム依存な部分はDIじゃなくて、Plugins for Xamarinみたいな機構を使って欲しい
* nugetパッケージ化してほしい

ほぅ、、、全然わからんぞ・・。
ということで、四苦八苦しながら、nugetパッケージ化までしたので、やった事とか調べたことを書きます。

# Plugins for Xamarin？

そもそも「Plugins for Xamarinってなんぞ？」と思ったので、
google先生に聞きました。

[この記事](http://ticktack.hatenablog.jp/entry/2016/04/08/180321)とか[本家のページ](https://docs.microsoft.com/ja-jp/nuget/guides/create-packages-for-xamarin)が参考になります。

Plugins for Xamarinは「Xamarin.AndroidやXamarin.iOS向けの固有機能を上手くIF化して、抽象化レイヤーで利用できるようにしたライブラリ」となります。
※ライブラリというかプロジェクトのテンプレートかな。

Plugins for Xamarinのリポジトリは[こちら](https://github.com/xamarin/XamarinComponents)。

利用するためにプロジェクトテンプレートをVisual Studio（※1）に取り込む必要があります。
※[こちら](https://marketplace.visualstudio.com/items?itemName=vs-publisher-473885.PluginForXamarinTemplates)から、テンプレートをダウンロード出来ます。

vsixのため、Visual Studio for Macではインポート出来ません。。（まずここにはまる・・）
Windows版でライブラリ開発はしましょう！って事ですかね・・。

# Plugins for Xamarinで試しにプロジェクトを作ってみる

試しに「SamplePlugin」という名前でPlugins for Xamarinのテンプレートを作って、サンプルのプロジェクトを作ると以下の構成になります。

1. Plugin.SamplePlugin (PCL)
2. Plugin.SamplePlugin.Abstractions (PCL)
3. Plugin.SamplePlugin.Android
4. Plugin.SamplePlugin.iOS
※本当はUWPとかも出来ますが、今回は不要だったので、削除しました。

とりあえず自分が思った感想は、
「ほぅ、、こんな感じなのか。そもそも、これどうやってプラットフォームごとにAPI（の中身）変わってるんだ？」
と思ったので、調べてみました。

# Plugins for XamarinのAPI切り替えについて

平たく言うと「Bait and Switch」という仕組み？を使って、APIの切り替え（正確にはdllを切り替え）をしています。

前述したサンプルのプロジェクトを例にあげると、以下のようになっています。
* 2のAbstractionsはIFのみを提供（もしくは抽象化したクラス）
* 1はPCLなプロジェクトから呼び出し可能
* 3はXamarin.Androidなプロジェクトから呼び出し可能
* 4はXamarin.iOSなプロジェクトから呼び出し可能

1.3.4ではIFの実体を提供するCrossSamplePluginというクラスが定義されていて、同じファイルを参照しています。

実体については、ビルド時のオプションで変わるようになっています。
※1の場合は実体はなしとし、3,4の場合はプラットフォームに応じたIFを実装したImplementationクラスを返すようになっている。

その結果何が起こるかというと、1.3.4のdllは全て同じ名前（完全修飾名が同じ）となります。
実行時はプラットフォーム毎に見るDLLを変えることが出来ます。
※上手く説明出来ないので、、[ここ](https://www.buildinsider.net/mobile/insidexamarin/13)とか[ここらへん](https://blog.fenrir-inc.com/jp/2015/12/xamarin_plugin.html)を参考にしてみてください。

# Plugins for Xamarinの.NET Standard対応について

さて、ここまででベースとなるプロジェクトは出来ました。
でも、Plugins for Xamarinの抽象化部分（サンプルで言う所の1と2）はPCLで出来ているため、まだ要件をみたせていません。

.NET Standard2.0へ置き換えが必要となります。

# .NET Standard？

[ここ](https://onedrive.live.com/view.aspx?resid=5C622397E11C979D!1394524&ithint=file%2cpptx&app=PowerPoint&authkey=!AGB-V6Pq8LQxoCs)が参考になりました。

# PCLを.NET Standard2.0に置き換える

「ふむ、プロパティ変えるだけで済むやろ」
と、思った時期が私にも有りました・・・・涙

単純にプロジェクトのプロパティからTargetFrameworkの変更では出来ませんでした・・。
なので、以下の手順を踏みます

* プロジェクトファイルをいじって、.NET Standardなプロジェクトに変更する
* 不要なファイルやフォルダを削除する

ちなみにいじるプロジェクトはサンプルで言う所の1と2になります。
※1と2を.NET Standard2.0にすれば良いです。

## プロジェクトファイルの変更

それぞれ以下のように直しました。
※自分は直接いじりましたが、.NETStandardなクラスのプロジェクトを作って、差し替えるほうが楽かもです。

```Plugin.SamplePlugin.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <GeneratePackageOnBuild>true</GeneratePackageOnBuild>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>TRACE;DEBUG;NETSTANDARD2_0;PORTABLE</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <!-- A reference to the entire .NET Framework is automatically included -->
    <ProjectReference Include="..\Plugin.SamplePlugin.Abstractions\Plugin.SamplePlugin.Abstractions.csproj">
      <Project>{6edb0588-ffc5-4ef5-8a99-9e241d0f878d}</Project>
      <Name>Plugin.SamplePlugin.Abstractions</Name>
    </ProjectReference>
  </ItemGroup>
</Project>
```

```Plugin.SamplePlugin.Abstractions.csproj
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <DefineConstants>TRACE;DEBUG;NETSTANDARD2_0;</DefineConstants>
  </PropertyGroup>
</Project>
```

## 不要ファイルの削除

.NET StandardなプロジェクトではAssemblyInfoとかは不要そうなので、削除しました。
※削除しないとビルドエラーになっちゃう。

# nugetパッケージの作成

先程あげた[このページ](http://ticktack.hatenablog.jp/entry/2016/04/08/180321)を見ると、Plugins for Xamarinのテンプレートを入れた段階で「Plugins for Xamarin NuSpec」があるらしいのですが、、私は見つからず。。

血の涙を流しながら、一からパッケージを作ろう！と決意しました。

## nugetパッケージってどうやって作る？

色々とgoogle先生に聞いて、作ってみました。
[ここ](http://cointoss.hatenablog.com/entry/2017/03/15/071926)とか[ここ](https://docs.microsoft.com/en-us/nuget/guides/create-packages-for-xamarin)

簡単な構成のプロジェクトであれば、nuspecを作るまでもなく、実は以下でパッケージ化出来ます。
```
nuget pack SamplePlugin.csproj
```

ただ上記だと、Plugins for Xamarinの構成ではパッケージ化しても、上手く動作しません。
※手元でやった感じではダメでした・・。実は出来るのだろうか・・？

そのため、nuspecを書いて、明示的にnugetパッケージの構成を決めるようにしました。

## nuspec？

nuspecとは「nugetパッケージ化する際に、どのようにパッケージ化するか？」という情報を記載した仕様ファイルとなります。（たとえば、バージョン情報とか依存関係とか）

今回のサンプルの場合だと以下のようなnuspecファイルを作成しました。

```Plugin.SamplePlugin.nuspec

<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
  <metadata>
    <id>Plugin.SamplePlugin</id>
    <version>1.0.0</version>
    <title>SamplePlugin</title>
    <authors>shota.sakamoto</authors>
    <owners>shota.sakamoto</owners>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>sample plugin</description>
    <releaseNotes>Test</releaseNotes>
    <copyright>Copyright 2018</copyright>
    <tags>sampleplugin</tags>
    <dependencies>
    </dependencies>
  </metadata>
  <files>
    <!-- Cross-platform reference assemblies -->
    <file src="Plugin.SamplePlugin\bin\Debug\netstandard2.0\Plugin.SamplePlugin.dll" target="lib\netstandard2.0\Plugin.SamplePlugin.dll" />
    <file src="Plugin.SamplePlugin\bin\Debug\netstandard2.0\Plugin.SamplePlugin.deps.json" target="lib\netstandard2.0\Plugin.SamplePlugin.deps.json" />
    <file src="Plugin.SamplePlugin.Abstractions\bin\Debug\netstandard2.0\Plugin.SamplePlugin.Abstractions.dll" target="lib\netstandard2.0\Plugin.SamplePlugin.Abstractions.dll" />
    <file src="Plugin.SamplePlugin.Abstractions\bin\Debug\netstandard2.0\Plugin.SamplePlugin.Abstractions.deps.json" target="lib\netstandard2.0\Plugin.SamplePlugin.Abstractions.deps.json" />

    <!-- iOS reference assemblies -->
    <file src="Plugin.SamplePlugin.iOS\bin\iPhone\Debug\Plugin.SamplePlugin.dll" target="lib\xamarinios\Plugin.SamplePlugin.dll" />
    <file src="Plugin.SamplePlugin.Abstractions\bin\Debug\netstandard2.0\Plugin.SamplePlugin.Abstractions.dll" target="lib\xamarinios\Plugin.SamplePlugin.Abstractions.dll" />

    <!-- Android reference assemblies -->
    <file src="Plugin.SamplePlugin.Android\bin\Debug\Plugin.SamplePlugin.dll" target="lib\MonoAndroid\Plugin.SamplePlugin.dll" />
    <file src="Plugin.SamplePlugin.Abstractions\bin\Debug\netstandard2.0\Plugin.SamplePlugin.Abstractions.dll" target="lib\MonoAndroid\Plugin.SamplePlugin.Abstractions.dll" />
  </files>
</package>
```

このnuspecを使って、一応パッケージ化出来ました！

# 最後に

今回やってみて、nugetパッケージ化するまで結構はまったので、
情報共有の意味も込めて、記事にしました。