在【Xamarin+Prism開發(fā)詳解系列】里面經(jīng)常使用到【Prism unity app】的模板創(chuàng)建Prism.Forms項目:

備注:由于Unity社區(qū)已經(jīng)不怎么活躍,下一個版本將會有Autofac,DryIOC,Ninject的項目模板。

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

自動彈出選擇框:

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

對于我這類還沒有動手寫過模板的人來說,確實挺新奇的。于是就決定自己也寫個類似的試試,目的就是通過向導創(chuàng)建跨平臺Plugin項目,類似Plugin for xamarin,不過是針對Prism,對應平臺可以自由選擇創(chuàng)建。試了之后才發(fā)現(xiàn)也有不少注意的地方,特寫下此文做備忘。

項目地址:https://github.com/NewBLife/Prism.Forms.Plugin

插件下載地址:TemplatesForPrism.vsix

1、安裝插件開發(fā)用的Extensibility模板與工具

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

2、新建VSIX Project插件項目

source.extension.vsixmanifest 這個文件相當重要,里面可以指定安裝目標,模板,向導等。

最后我實現(xiàn)的例子:

安裝目標:VS2013以上(2017估計不行)

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

資產(chǎn):Project模板,Item模板,Wizard向導

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

3、從【C# Item Template】與【C# Project Template】模板創(chuàng)建項目。

4、從【類庫】模板創(chuàng)建Wizard項目。(Wizard向導只能是類庫)

以上步驟之后的項目結構:

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

介紹:

  • Prism.Forms.Plugin.Nuspec:Plugin打包文件模板

  • Prism.Forms.Plugin:Plugin項目模板

  • Prism.Forms.Plugin.Wizard:Plugin創(chuàng)建向導

  • TemplatesForPrism:VSIX插件項目

 

 

 

 

5、添加引用

  • Prism.Forms.Plugin.Nuspec:Microsoft.VisaulStudio.CoreUtility

  • Prism.Forms.Plugin:Microsoft.VisaulStudio.CoreUtility

  • Prism.Forms.Plugin.WizardMicrosoft.VisaulStudio.TemplateWizardinterface,envdte

  • TemplatesForPrism:Prism.Forms.Plugin.Nuspec,Prism.Forms.Plugin,Prism.Forms.Plugin.Wizard

6、添加生成向導

6.1、NewProjectWizard項目選擇向導創(chuàng)建新建一個WinForm選擇框,返回選擇的結果。

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

繼承IWiazrd向導接口實現(xiàn):

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

using EnvDTE;using Microsoft.VisualStudio.TemplateWizard;using System;using System.Collections.Generic;using System.IO;namespace Prism.Forms.Plugin.Wizard
{    public class NewProjectWizard : IWizard
    {        private DTE _dte = null;        private string _solutionDir = null;        private string _templateDir = null;        private string _projectName = null;

        PluginNewProjectDialogResult _dialogResult;        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }        public void ProjectFinishedGenerating(Project project)
        {if

(_dialogResult.CreateAndroid) CreateProject(Target.Droid.ToString()); if (_dialogResult.CreateiOS) CreateProject(Target.iOS.ToString()); if

 (_dialogResult.CreateUwp)
                CreateProject(Target.UWP.ToString());

        }

void CreateProject(string platform) { string name = $"{_projectName}.{platform}"string projectPath =System.IO.Path.Combine(_solutionDir, Path.Combine(_projectName, name)); string templateName = $"Prism.Forms.Plugin.{platform}"string templatePath = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(_templateDir), $"{templateName}.zip\\{templateName}.vstemplate"

);

            _dte.Solution.AddFromTemplate(templatePath, projectPath, name);

        }

        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
        }        public void RunFinished()
        {
        }        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {            try
            {
                _dte = automationObject as DTE;

                _projectName = replacementsDictionary["$safeprojectname$"];

                _solutionDir = System.IO.Path.GetDirectoryName(replacementsDictionary["$destinationdirectory$"]);

                _templateDir = System.IO.Path.GetDirectoryName(customParams[0] as string);                PluginNewProjectDialog dialog

new PluginNewProjectDialog(); dialog.ShowDialog(); _dialogResult =

 dialog.Result;


                if (_dialogResult.Cancelled)                    throw new WizardBackoutException();

            }            catch (Exception)
            {                if (Directory.Exists(_solutionDir))

                    Directory.Delete(_solutionDir, true);                throw;
            }
        }        public bool ShouldAddProjectItem(string filePath)
        {            return true;
        }
    }
}

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

模板選擇后執(zhí)行RunStarted==》彈出Winform選擇框==》執(zhí)行ProjectFinishedGenerating創(chuàng)建子項目

 

6.2、項目名稱safeprojectgroupname向導創(chuàng)建

在NewProjectWizard向導的CreateProject方法里面我們設置了每個子項目的名稱為"{_projectName}.{platform}",所以到達子項目的時候$safeprojectname$里面已經(jīng)帶了iOS,Droid,UWP等名稱,所以有必要進行處理。

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

using EnvDTE;using Microsoft.VisualStudio.TemplateWizard;using System.Collections.Generic;using System.Threading;namespace Prism.Forms.Plugin.Wizard
{    public class SafeProjectGroupName : IWizard
    {        public const string ParameterName = "$safeprojectgroupname$";        static ThreadLocal<string> projectGroupName = new ThreadLocal<string>();        bool isRootWizard;        public void BeforeOpeningFile(ProjectItem projectItem)
        {
        }        public void ProjectFinishedGenerating(Project project)
        {
        }        public void ProjectItemFinishedGenerating(ProjectItem projectItem)
        {
        }        public void RunFinished()
        {            // If we were the ones to set the value, we must clear it.
            if (isRootWizard)
                projectGroupName.Value = null;
        }        public void RunStarted(object automationObject, Dictionary<string, string> replacementsDictionary, WizardRunKind runKind, object[] customParams)
        {            if (projectGroupName.Value == null)
            {                var name = replacementsDictionary["$safeprojectname$"];                if (name.EndsWith(Target.Abstractions.ToString()))
                {
                    projectGroupName.Value = name.Replace($".{Target.Abstractions.ToString()}", string.Empty);
                }                else if (name.EndsWith(Target.Droid.ToString()))
                {
                    projectGroupName.Value = name.Replace($".{Target.Droid.ToString()}", string.Empty);
                }                else if (name.EndsWith(Target.iOS.ToString()))
                {
                    projectGroupName.Value = name.Replace($".{Target.iOS.ToString()}", string.Empty);
                }                else if (name.EndsWith(Target.UWP.ToString()))
                {
                    projectGroupName.Value = name.Replace($".{Target.UWP.ToString()}", string.Empty);
                }                // If there wasn't a value already, it means we're the root wizard itself.
                isRootWizard = true;
            }

            replacementsDictionary[ParameterName] = projectGroupName.Value;
        }        public bool ShouldAddProjectItem(string filePath)
        {            return true;
        }
    }
}

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

Debug測試方法:

  • 給類庫添加署名,否則無法注冊

  • 管理員權限啟動VS2015 開發(fā)人員命令提示工具

  • 導航到wizard生成目錄

  • 執(zhí)行gacutil -if Prism.Forms.Plugin.Wizard.dll 命令注冊類庫

  • 執(zhí)行gacutil –l  列出類庫的Token信息(Prism.Forms.Plugin.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b2335488e79a16da, processorArchitecture=MSIL)

  • 模板文件的WizarExtension節(jié)點添加以上Token信息與入口類名稱

  • 安裝模板,設置斷點

  • 啟動另一個Visual Studio程序

  • 調試-》附加到進程-》附加新啟動的Visual Studio進程

  • 新Visual Studio窗口選擇建立的模板,將進入斷點

7、添加模板文件并設置

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓Prism.Forms.Plugin.Nuspec模板設置

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010">
  <TemplateData>
    <Name>Plugin nuspec for Prism.Forms</Name>
    <Description>Create a nuspec file for Prism.Forms.Plugin solution</Description>
    <Icon>Prism.Forms.Plugin.Nuspec.ico</Icon>
    <TemplateID>325a0391-d11c-4432-8658-b70405881e87</TemplateID>

<ProjectType>General</ProjectType>

    <RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
    <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp>
    <DefaultName>PrismFormsPlugin.nuspec</DefaultName>
  </TemplateData>
  <TemplateContent>
    <ProjectItem TargetFileName="$fileinputname$.nuspec" ReplaceParameters="true">Prism.Forms.Plugin.nuspec</ProjectItem>
  </TemplateContent>
</VSTemplate>

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

注意點:

  • Item模板的ProjectType默認為CSharp,有時候沒法找到,最好設置為General。

  • 模板參照文件的生成操作都設置為無。

  • 記得設置分類Category,這樣好找。

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

效果如下:(在添加新項里面)

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓Prism.Forms.Plugin模板設置

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

每個文件夾下面為相應的模板文件

  • Prism.Forms.Plugin.Abstractions:接口定義

  • Prism.Forms.Plugin.Droid:Android平臺特性的接口實現(xiàn)

  • Prism.Forms.Plugin.iOS:iOS平臺特性的接口實現(xiàn)

  • Prism.Forms.Plugin.UWP:UWP平臺特性的接口實現(xiàn)

最外面的入口模板文件Prism.Forms.Plugin.vstemplate設置:

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

<?xml version="1.0" encoding="utf-8"?>
<VSTemplate Version="3.0.0"

Type="ProjectGroup"

 xmlns="http://schemas.microsoft.com/developer/vstemplate/2005" xmlns:sdk="http://schemas.microsoft.com/developer/vstemplate-sdkextension/2010">
  <TemplateData>
    <Name>Plugin for Prism.Forms</Name>
    <Description>Creates all files necessary to create a plugin for Prism.Forms</Description>
    <Icon>Prism.Forms.Plugin.ico</Icon>
    <ProjectType>CSharp</ProjectType>
    <RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
    <SortOrder>30</SortOrder>
    <TemplateID>16bac5e1-199d-4e08-9ed3-2ef287221be1</TemplateID>
    <DefaultName>PrismFormsPlugin</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <PromptForSaveOnCreation>true</PromptForSaveOnCreation>
    <NumberOfParentCategoriesToRollUp>1</NumberOfParentCategoriesToRollUp>
  </TemplateData>
  <TemplateContent>

<ProjectCollection> <ProjectTemplateLink ProjectName="$safeprojectname$.Abstractions">

        Prism.Forms.Plugin.Abstractions\Prism.Forms.Plugin.Abstractions.vstemplate

</ProjectTemplateLink> </ProjectCollection>

  </TemplateContent>

  <WizardExtension>     <Assembly>Prism.Forms.Plugin.Wizard, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b2335488e79a16da</Assembly>     <FullClassName>Prism.Forms.Plugin.Wizard.NewProjectWizard</FullClassName>   </WizardExtension>

</VSTemplate>

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

注意點:

  • 入口模板文件的Type必須為ProjectGroup,否則只創(chuàng)建一個工程項目

  • 模板內(nèi)容必須使用ProjectTemplateLink添加每個子項目的模板文件設置

  • 由于使用向導可選擇方式創(chuàng)建子項目,所有這里只添加了接口的模板文件

  • WizarExtension節(jié)點為向導程序設置,調用Prism.Forms.Plugin.Wizard.NewProjectWizard

子項目模板Prism.Forms.Plugin.Abstractions.vstemplate設置:

iOS培訓,Swift培訓,蘋果開發(fā)培訓,移動開發(fā)培訓

<VSTemplate Version="3.0.0" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005"
http://www.cnblogs.com/lixiaobin/p/VSIX.html