VSIXプロジェクトテンプレートを作る
以前にASP.NET Core(Generic Host)のDIの仕組みをXamarin.Formsで利用する手順を書きました.
しかし,毎回この手順を行うのは苦痛なので,プロジェクトのテンプレートを作成したいと思います.
Xamarin.Formsは通常,複数プロジェクト(共有プロジェクト,Android,iOS,UWPなど)からなります.
複数プロジェクトのテンプレートを作成するには以下の公式ドキュメントの「既存のソリューションから複数プロジェクトのテンプレートを作成する」に従います.
雛形となるソリューションを作成する
作成したものがこちらになります.これが「既存のソリューション」に当たります
各プラットフォームのプロジェクトをテンプレートとしてエクスポートする
各プラットフォームのプロジェクトそれぞれについて「Project -> Export Template...」します.
Export Template Wizard
が開くので,作成するテンプレートの種類にはProject template
を選択し,エクスポート対象のプロジェクトを下のドロップダウンリストから選択してNext
ボタンを押します.
次の画面ではテンプレート名などの情報を入力します.
テンプレート名,説明,アイコン,出力先などを指定できますが,ここでは基本デフォルトのままで,一つだけAutomatically import the template into Visual Studio
のチェックを外してFinish
ボタンを押します.
これがついていると,プロジェクトをエクスポートすると同時にVisual Studioにテンプレートとして追加されてしまうためです.
今回はまだVisual Studioに追加されてほしくないので,チェックを外しておきます.
これを各プラットフォームの分だけ行います.今回は共有プロジェクト
,Android
,iOS
の3つです.
出力先はデフォルトでは%USERPROFILE%\Documents\Visual Studio {バージョン:2019とか2017}\My Exported Templates
です.
テンプレートファイルを解凍する
zip形式で出力された各テンプレートファイルですが,これをそれぞれ解凍します.
解凍されてできたフォルダごと,適当なフォルダに移動させます.私はデスクトップに「XFAspNetCoreDITemplate」という名前のフォルダを作って,そこに3つのフォルダを移動させました.
.vstemplate
ファイルを作成する
各テンプレートのフォルダを置いたフォルダに.vstemplate
という拡張子のファイルを作成します.
空のテキストファイルを作成して名前を変更して作ればOkです.
ここではXFAspNetCoreDITemplate.vstemplate
という名前にしました.中身はまだ空です.
vstemplateファイルの中身を書く
vstemplateファイルにはXMLで以下のように書きます.
<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" Type="ProjectGroup"> <TemplateData> <Name>Xamarin.Forms with ASP.NET Core DI (.NET Standard 2.1)</Name> <Description>Xamarin.Forms with ASP.NET Core DI template.</Description> <ProjectType>CSharp</ProjectType> <Icon></Icon> <DefaultName>XFAppAspDI</DefaultName> <ProvideDefaultName>true</ProvideDefaultName> </TemplateData> <TemplateContent PreferedSolusionConfigration="Debug|Any CPU"> <ProjectCollection> <ProjectTemplateLink ProjectName="$safeprojectname$" CopyParameters="true"> XFAspNetCoreDITemplate\MyTemplate.vstemplate </ProjectTemplateLink> <ProjectTemplateLink ProjectName="$safeprojectname$.Android" CopyParameters="true"> XFAspNetCoreDITemplate.Android\MyTemplate.vstemplate </ProjectTemplateLink> <ProjectTemplateLink ProjectName="$safeprojectname$.iOS" CopyParameters="true"> XFAspNetCoreDITemplate.iOS\MyTemplate.vstemplate </ProjectTemplateLink> </ProjectCollection> </TemplateContent> </VSTemplate>
vstemplateファイル内で各プロジェクトの名前なども指定するのですが,実際に使うときはプロジェクトの名前はユーザーが作成時に入力するソリューション名が使用されるようにしなければなりません.
それをどうするかというと,田淵さんのサンプルにあるように$safeprojectname$
という変数(テンプレートパラメータ)を使います.
テンプレートパラメータに関する公式ドキュメントはこちら.
これで,アプリ作成時に指定したソリューション名に合わせて{ソリューション名}.Android
,{ソリューション名}.iOS
のように各プラットフォームのプロジェクト名がつけられます.
が,プロジェクトの中ではソリューション名が変わらないままです.
例えば,Android,iOSの各プロジェクトから共有コードのプロジェクトを参照しているのですが,その参照先のプロジェクト名が変更されないため,以下のように参照エラーになります.これではいけません.
各プロジェクトの中でソリューション名に指定された文字列を使うためにはここでも先程と同じようにテンプレートパラメータ
を使用します.
どのようなテンプレートパラメータを使用するかというと$ext_safeprojectname
というパラメータです.
Android,iOSの各プロジェクトの.csproj
ファイルの中で,プロジェクトの参照情報の記述があるので,それを以下のように変更します.
<ItemGroup> <ProjectReference Include="..\XFAspNetCoreDITemplate\XFAspNetCoreDITemplate.csproj"> <Project>{7DD7EBB5-8DCB-428D-A7B2-FE93EE1EFC89}</Project> <Name>XFAspNetCoreDITemplate</Name> </ProjectReference> </ItemGroup>
↓
<ItemGroup> <ProjectReference Include="..\$ext_safeprojectname$\$ext_safeprojectname$.csproj"> <Project>{7DD7EBB5-8DCB-428D-A7B2-FE93EE1EFC89}</Project> <Name>$ext_safeprojectname$</Name> </ProjectReference> </ItemGroup>
あともう一点,変更箇所がありました.基本的にはAndroidもiOSも同じです.
<PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{$guid1$}</ProjectGuid> <ProjectTypeGuids>{EFBA0AD7-5A72-4C68-AF49-83D382785DCF};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <TemplateGuid>{c9e5eea5-ca05-42a1-839b-61506e0a37df}</TemplateGuid> <OutputType>Library</OutputType> <RootNamespace>$ext_safeprojectname$</RootNamespace> <AssemblyName>$ext_safeprojectname$.Android</AssemblyName>
ピックアップすると以下の箇所です.
<ProjectGuid>{$guid1$}</ProjectGuid>
<RootNamespace>$ext_safeprojectname$</RootNamespace>
<AssemblyName>$ext_safeprojectname$.Android</AssemblyName>
以上のように修正して保存します.
フォルダとvstemplateファイルをzip形式に圧縮する
以下のようにフォルダとファイルを選択してzipにします.
テンプレートフォルダに配置
以下のフォルダに先程作成したzipファイルを配置します.
%USERPROFILE%\Documents\Visual Studio 2019\Templates\ProjectTemplates
これで準備完了です.
Visual Studioを閉じてから再び起動します.
試してみる.
プロジェクトの新規作成でテンプレートを検索すると,以下のように先程作成したテンプレートが見つかります.
デフォルトのプロジェクト名も指定したとおりになっています.
ソースコード
テンプレートのもとにしたプロジェクト
テンプレート(zip前)
これをzipで固めると,プロジェクトテンプレートになります.
テンプレートの公開
作成したテンプレートを他の端末や,多くの人に使ってもらいたい場合,テンプレートを拡張機能として公開すると便利でしょう.
その場合は以下の手順を行います.
VSIXファイルを作成する
VSIXプロジェクトを作成するのですが,VSIXプロジェクトを作成するにはVisual Studio SDK
をインストールしておく必要があるので,インストールします.
Visual Studio SDKのインストール
インストールはVisual Studio Installer
からVisual Studio extension development
というワークロードを選択することでインストールされます.
約3GBあるので,インストールの完了を気長に待ちます.
VSIXプロジェクトの作成
Visual Studio SDKのインストールが完了したら,Visual Studioを起動してC#
のEmpty VSIX Project
を新規作成します.
プロジェクト名はこのようにしました.
テンプレートファイル(zip)をプロジェクトに追加する
ソリューションエクスプローラでVSIXプロジェクトを右クリックしてコンテキストメニューからAdd -> Existing Item
を選択します.
ファイル選択ダイアログが開くのでファイルの種類をAll Files
にして,先程出力したテンプレートファイル(zip)を選択します.
ソリューションエクスプローラ上で,追加したテンプレートファイルを右クリックしてコンテキストメニューからProperty
を選択し,Copy to Output Directory
の項目にCopy always
を指定します.
source.extension.vsixmanifestを編集する
VSIXプロジェクトの中にsource.extension.vsixmanifest
というファイルがあるので,ダブルクリックしてデザイナを開きます.
デザイナではMetadata
のページで以下のように入力します.
次にAssets
のページでNew
ボタンを押します.
以下のウィンドウが表示されるので以下のように各項目を指定します.
Type
にはMicrosoft.VisualStudio.ProjectTemplate
を指定.Source
はFile on filesystem
を指定.Path
にテンプレートファイル(zip)を指定します.
OK
ボタンを押します.
すると,ソリューションには以下のようにフォルダが作成され,その中にテンプレートファイルがインポートされます.
VSIXプロジェクトをビルドする
ビルドすると,VSIXプロジェクト内のbin\Debug(またはRelease)
フォルダ内に以下のような.vsix
ファイルが生成されます.
拡張機能としてテンプレートをインストールする
この中のvsixファイルをダブルクリックするとインストールが始まります.
インストールが完了したらVisual Studioを起動します.
プロジェクト新規作成でテンプレートを検索すると,以下のようにインストールしたテンプレートが見つかります.
20200715追記
Releaseビルドしたvsixファイルをインストールしようとすると,以下のようにサインがない,と言われてインストールできないことがあります.