Xamarin
.NETCore

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

More than 1 year has passed since last update.


はじめに・・

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


  • IF部分はPCLじゃなくて、.NET Standard2.0対応してほしい

  • プラットフォーム依存な部分はDIじゃなくて、Plugins for Xamarinみたいな機構を使って欲しい

  • nugetパッケージ化してほしい

ほぅ、、、全然わからんぞ・・。

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


Plugins for Xamarin?

そもそも「Plugins for Xamarinってなんぞ?」と思ったので、

google先生に聞きました。

この記事とか本家のページが参考になります。

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

※ライブラリというかプロジェクトのテンプレートかな。

Plugins for Xamarinのリポジトリはこちら

利用するためにプロジェクトテンプレートをVisual Studio(※1)に取り込む必要があります。

こちらから、テンプレートをダウンロード出来ます。

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を変えることが出来ます。

※上手く説明出来ないので、、こことかここらへんを参考にしてみてください。


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

さて、ここまででベースとなるプロジェクトは出来ました。

でも、Plugins for Xamarinの抽象化部分(サンプルで言う所の1と2)はPCLで出来ているため、まだ要件をみたせていません。

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


.NET Standard?

ここが参考になりました。


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パッケージの作成

先程あげたこのページを見ると、Plugins for Xamarinのテンプレートを入れた段階で「Plugins for Xamarin NuSpec」があるらしいのですが、、私は見つからず。。

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


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

色々とgoogle先生に聞いて、作ってみました。

こことかここ

簡単な構成のプロジェクトであれば、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パッケージ化するまで結構はまったので、

情報共有の意味も込めて、記事にしました。