Skip to content

Commit 98a2fd1

Browse files
[One .NET] dotnet new project and item templates
Context: https://docs.microsoft.com/dotnet/core/tutorials/cli-templates-create-template-pack Context: https://github.com/dotnet/templating/wiki Context: dotnet/designs#120 This implements basic Android templates that are contained in a `Microsoft.Android.Templates.nupkg` file. We can define a template pack in `WorkloadManifest.json`: "Microsoft.Android.Templates": { "kind": "template", "version": "@TEMPLATE_PACK_VERSION@" } This allows the workload to locate the `*.nupkg` file in: C:\Program Files\dotnet\template-packs /usr/local/share/dotnet/template-packs Our .NET 6 preview installers simply have to place the `*.nupkg` files in the right place for them to be picked up by `dotnet new`. Some example project templates: dotnet new android --output MyAndroidApp --packageName com.mycompany.myandroidapp dotnet new androidlib --output MyAndroidLibrary dotnet new android-bindinglib --output MyJavaBinding And item templates: dotnet new android-activity --name LoginActivity --namespace MyAndroidApp dotnet new android-layout --name MyLayout --output Resources/layout Note that the `android-bindinglib` template is not a special project type. It has additional help files for writing bindings as we have in the current Xamarin.Android templates. I also updated the `XASdkTests` to `dotnet new` each template and `dotnet build` the resulting output.
1 parent 113ffcc commit 98a2fd1

File tree

48 files changed

+510
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+510
-20
lines changed

Documentation/guides/OneDotNet.md

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -189,12 +189,45 @@ It is recommended to migrate to the new linker settings, as
189189
There are currently a few "verbs" we are aiming to get working in
190190
Xamarin.Android:
191191

192+
dotnet new
192193
dotnet build
193194
dotnet publish
194195
dotnet run
195196

196-
Currently in .NET 5 console apps, `dotnet publish` is where all the
197-
work to produce a self-contained "app" happens:
197+
### dotnet new
198+
199+
To support `dotnet new`, we created a few basic project and item
200+
templates for Android that are named following the patterns and naming
201+
of existing .NET templates:
202+
203+
Templates Short Name Language Tags
204+
-------------------------------------------- ------------------- ---------- ----------------------
205+
Android Activity template android-activity [C#] Android
206+
Android Java Library Binding android-bindinglib [C#] Android
207+
Android Layout template android-layout [C#] Android
208+
Android Class library androidlib [C#] Android
209+
Android Application android [C#] Android
210+
Console Application console [C#],F#,VB Common/Console
211+
Class library classlib [C#],F#,VB Common/Library
212+
Razor Page page [C#] Web/ASP.NET
213+
ASP.NET Core Web App webapp [C#] Web/MVC/Razor Pages
214+
215+
To create different types of Android projects:
216+
217+
dotnet new android --output MyAndroidApp --packageName com.mycompany.myandroidapp
218+
dotnet new androidlib --output MyAndroidLibrary
219+
dotnet new android-bindinglib --output MyJavaBinding
220+
221+
Once the projects are created, some basic item templates can also be
222+
used such as:
223+
224+
dotnet new android-activity --name LoginActivity --namespace MyAndroidApp
225+
dotnet new android-layout --name MyLayout --output Resources/layout
226+
227+
### dotnet build & publish
228+
229+
Currently in .NET console apps, `dotnet publish` is where all the work
230+
to produce a self-contained "app" happens:
198231

199232
* The linker via the `<IlLink/>` MSBuild task
200233
* .NET Core's version of AOT, named "ReadyToRun"
@@ -223,12 +256,18 @@ Play, ad-hoc distribution, etc. It could be able to sign the `.apk` or
223256
`.aab` with different keys. As a starting point, this will currently
224257
copy the output to a `publish` directory on disk.
225258

259+
[illink]: https://github.com/mono/linker/blob/master/src/linker/README.md
260+
261+
### dotnet run
262+
226263
`dotnet run` can be used to launch applications on a
227264
device or emulator via the `--project` switch:
228265

229266
dotnet run --project HelloAndroid.csproj
230267

231-
[illink]: https://github.com/mono/linker/blob/master/src/linker/README.md
268+
Alternatively, you could use the `Run` MSBuild target such as:
269+
270+
dotnet build HelloAndroid.csproj -t:Run
232271

233272
### Preview testing
234273

build-tools/Xamarin.Android.Tools.BootstrapTasks/Xamarin.Android.Tools.BootstrapTasks/GenerateWixFile.cs

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,22 @@ public override bool Execute ()
108108
packWriter.WriteStartElement ("Directory");
109109
packWriter.WriteAttributeString ("Id", "packs");
110110
packWriter.WriteAttributeString ("Name", "packs");
111+
packWriter.WriteAttributeString ("FileSource", packs_dir);
111112
foreach (var directory in Directory.EnumerateDirectories (packs_dir, "Microsoft.Android.*")) {
112113
RecurseDirectory (packs_dir, packWriter, componentWriter, directory);
113114
}
115+
packWriter.WriteEndElement (); // </Directory> packs
116+
117+
// template-packs
118+
var templates_dir = Path.Combine (DotNetPath, "template-packs");
119+
packWriter.WriteStartElement ("Directory");
120+
packWriter.WriteAttributeString ("Id", "templatepacks");
121+
packWriter.WriteAttributeString ("Name", "template-packs");
122+
packWriter.WriteAttributeString ("FileSource", templates_dir);
123+
foreach (var file in Directory.EnumerateFiles (templates_dir, "Microsoft.Android.Templates.*.nupkg")) {
124+
AddFile (templates_dir, packWriter, componentWriter, file);
125+
}
126+
packWriter.WriteEndElement (); // </Directory> template-packs
114127

115128
packWriter.WriteEndDocument (); // </Directory>
116129
componentWriter.WriteEndDocument (); // </ComponentGroup>
@@ -145,22 +158,27 @@ static void RecurseDirectory (string top_dir, XmlWriter packWriter, XmlWriter co
145158
var fileName = Path.GetFileName (file);
146159
if (fileName.StartsWith (".") || fileName.StartsWith ("_"))
147160
continue;
148-
var componentId = GetId (top_dir, file);
149-
packWriter.WriteStartElement ("Component");
150-
packWriter.WriteAttributeString ("Id", componentId);
151-
packWriter.WriteStartElement ("File");
152-
packWriter.WriteAttributeString ("Id", componentId);
153-
packWriter.WriteAttributeString ("Name", Path.GetFileName (file));
154-
packWriter.WriteAttributeString ("KeyPath", "yes");
155-
packWriter.WriteEndElement (); // </File>
156-
packWriter.WriteEndElement (); // </Component>
157-
componentWriter.WriteStartElement ("ComponentRef");
158-
componentWriter.WriteAttributeString ("Id", componentId);
159-
componentWriter.WriteEndElement (); // </ComponentRef>
161+
AddFile (top_dir, packWriter, componentWriter, file);
160162
}
161163
packWriter.WriteEndElement (); // </Directory>
162164
}
163165

166+
static void AddFile (string top_dir, XmlWriter packWriter, XmlWriter componentWriter, string file)
167+
{
168+
string componentId = GetId (top_dir, file);
169+
packWriter.WriteStartElement ("Component");
170+
packWriter.WriteAttributeString ("Id", componentId);
171+
packWriter.WriteStartElement ("File");
172+
packWriter.WriteAttributeString ("Id", componentId);
173+
packWriter.WriteAttributeString ("Name", Path.GetFileName (file));
174+
packWriter.WriteAttributeString ("KeyPath", "yes");
175+
packWriter.WriteEndElement (); // </File>
176+
packWriter.WriteEndElement (); // </Component>
177+
componentWriter.WriteStartElement ("ComponentRef");
178+
componentWriter.WriteAttributeString ("Id", componentId);
179+
componentWriter.WriteEndElement (); // </ComponentRef>
180+
}
181+
164182
static string GetId (string top_dir, string path)
165183
{
166184
if (string.IsNullOrEmpty (path))

build-tools/create-dotnet-pkg/create-dotnet-pkg.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<_FilesToCopy Include="$(DotNetPreviewPath)\sdk-manifests\$(DotNetPreviewVersionBand)\Microsoft.NET.Workload.Android\**\*" />
3636
<_FilesToCopy Include="$(DotNetPreviewPath)\packs\Microsoft.Android.Ref\**\*" />
3737
<_FilesToCopy Include="$(DotNetPreviewPath)\packs\Microsoft.Android.Sdk.osx-x64\**\*" />
38+
<_FilesToCopy Include="$(DotNetPreviewPath)\template-packs\Microsoft.Android.Templates.*.nupkg" />
3839
</ItemGroup>
3940
<MakeDir Directories="$(PkgOutputPath);$(PayloadDir);$(PkgResourcesPath);$(LicenseDestination)"/>
4041
<ReplaceFileContents

build-tools/create-packs/Directory.Build.targets

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
<Exec Command="$(DotNetPreviewTool) pack @(_GlobalProperties, ' ') -p:AndroidHostRID=osx-x64 &quot;$(MSBuildThisFileDirectory)Microsoft.Android.Sdk.proj&quot;" Condition=" '$(HostOS)' == 'Darwin' " />
8383
<Exec Command="$(DotNetPreviewTool) pack @(_GlobalProperties, ' ') -p:AndroidHostRID=win-x64 &quot;$(MSBuildThisFileDirectory)Microsoft.Android.Sdk.proj&quot;" Condition=" '$(HostOS)' != 'Linux' " /> <!-- Windows pack should be built both Windows and macOS -->
8484
<Exec Command="$(DotNetPreviewTool) pack @(_GlobalProperties, ' ') &quot;$(MSBuildThisFileDirectory)Microsoft.NET.Workload.Android.proj&quot;" />
85+
<Exec Command="$(DotNetPreviewTool) pack @(_GlobalProperties, ' ') &quot;$(XamarinAndroidSourcePath)src\templates\templates.csproj&quot;" />
8586
</Target>
8687

8788
<Target Name="ExtractWorkloadPacks"
@@ -92,6 +93,7 @@
9293
<_WLPacks Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\nupkgs\Microsoft.Android.Sdk.osx-x64.*.nupkg" Condition=" '$(HostOS)' == 'Darwin' " />
9394
<_WLPacks Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\nupkgs\Microsoft.Android.Sdk.win-x64.*.nupkg" Condition=" '$(HostOS)' == 'Windows' " />
9495
<_WLPacks Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\nupkgs\Microsoft.Android.Ref.*.nupkg" />
96+
<_WLTemplates Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\nupkgs\Microsoft.Android.Templates.*.nupkg" />
9597
<!-- Runtime packs are not yet supported by workloads -->
9698
<!-- <_WLPacks Include="$(XamarinAndroidSourcePath)bin\Build$(Configuration)\nupkgs\Microsoft.Android.Runtime.*.nupkg" /> -->
9799
</ItemGroup>
@@ -106,6 +108,8 @@
106108
SourceFiles="@(_WLPacks)"
107109
DestinationFolder="$(DotNetPreviewPath)packs\$([System.String]::Copy('%(_WLPacks.Filename)').Replace('.$(_WLPackVersion)', ''))\$(_WLPackVersion)"
108110
/>
111+
<MakeDir Directories="$(DotNetPreviewPath)template-packs" />
112+
<Copy SourceFiles="@(_WLTemplates)" DestinationFolder="$(DotNetPreviewPath)template-packs" />
109113
<ItemGroup>
110114
<_UnixExecutables Include="$(DotNetPreviewPath)packs\Microsoft.Android.Sdk.*\*\tools\$(HostOS)\**\*.*" />
111115
<_FilesToTouch Include="$(DotNetPreviewPath)sdk-manifests\$(DotNetPreviewVersionBand)\Microsoft.NET.Workload.Android\**" />
@@ -129,6 +133,7 @@
129133
<_PackFilesToDelete Include="$(DotNetPreviewPath)sdk-manifests\$(DotNetPreviewVersionBand)\Microsoft.Android.Workload\**\*.*" />
130134
<_PackFilesToDelete Include="$(DotNetPreviewPath)sdk-manifests\$(DotNetPreviewVersionBand)\Microsoft.NET.Workload.Android\**\*.*" />
131135
<_PackFilesToDelete Include="$(DotNetPreviewPath)packs\Microsoft.Android*\**\*.*" />
136+
<_PackFilesToDelete Include="$(DotNetPreviewPath)template-packs\Microsoft.Android.Templates.*.nupkg" />
132137
</ItemGroup>
133138
<RemoveDir Directories="%(_PackFilesToDelete.RootDir)%(_PackFilesToDelete.Directory)" />
134139
<Delete Files="$(_WorkloadResolverFlagFile)" />

build-tools/create-packs/Microsoft.NET.Workload.Android.proj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ workload manifest pack containing information about the various Microsoft.Androi
3636
<ReplaceFileContents
3737
SourceFile="$(XamarinAndroidSourcePath)src\Xamarin.Android.Build.Tasks\Microsoft.NET.Workload.Android\WorkloadManifest.in.json"
3838
DestinationFile="$(WorkloadManifestJsonPath)"
39-
Replacements="@SDK_PACK_VERSION@=$(AndroidPackVersionLong);@REF_PACK_VERSION@=$(AndroidPackVersionLong)">
39+
Replacements="@SDK_PACK_VERSION@=$(AndroidPackVersionLong);@REF_PACK_VERSION@=$(AndroidPackVersionLong);@TEMPLATE_PACK_VERSION@=$(AndroidPackVersionLong);">
4040
</ReplaceFileContents>
4141

4242
<ItemGroup>

src/Xamarin.Android.Build.Tasks/Microsoft.NET.Workload.Android/WorkloadManifest.in.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"description": "Android SDK",
66
"packs": [
77
"Microsoft.Android.Sdk",
8-
"Microsoft.Android.Ref"
8+
"Microsoft.Android.Ref",
9+
"Microsoft.Android.Templates"
910
]
1011
}
1112
},
@@ -21,6 +22,10 @@
2122
"Microsoft.Android.Ref": {
2223
"kind": "framework",
2324
"version": "@REF_PACK_VERSION@"
25+
},
26+
"Microsoft.Android.Templates": {
27+
"kind": "template",
28+
"version": "@TEMPLATE_PACK_VERSION@"
2429
}
2530
}
2631
}

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/XASdkTests.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,16 @@ public void DotNetBuildLibrary (bool isRelease, bool duplicateAar)
177177
StringAssert.Contains ("public const int MyLayout", resource_designer_text);
178178
}
179179

180+
[Test]
181+
public void DotNetNew ([Values ("android", "androidlib", "android-bindinglib")] string template)
182+
{
183+
var dotnet = CreateDotNetBuilder ();
184+
Assert.IsTrue (dotnet.New (template), $"`dotnet new {template}` should succeed");
185+
Assert.IsTrue (dotnet.New ("android-activity"), "`dotnet new android-activity` should succeed");
186+
Assert.IsTrue (dotnet.New ("android-layout", Path.Combine (dotnet.ProjectDirectory, "Resources", "layout")), "`dotnet new android-layout` should succeed");
187+
Assert.IsTrue (dotnet.Build (), "`dotnet build` should succeed");
188+
}
189+
180190
[Test]
181191
public void DotNetPack ([Values ("net6.0-android", "net6.0-android30")] string targetFramework)
182192
{
@@ -461,6 +471,16 @@ void CreateEmptyFile (params string [] paths)
461471
}
462472
}
463473

474+
DotNetCLI CreateDotNetBuilder (string relativeProjectDir = null)
475+
{
476+
if (string.IsNullOrEmpty (relativeProjectDir)) {
477+
relativeProjectDir = Path.Combine ("temp", TestName);
478+
}
479+
TestOutputDirectories [TestContext.CurrentContext.Test.ID] =
480+
FullProjectDirectory = Path.Combine (Root, relativeProjectDir);
481+
return new DotNetCLI (Path.Combine (FullProjectDirectory, $"{TestName}.csproj"));
482+
}
483+
464484
DotNetCLI CreateDotNetBuilder (XASdkProject project, string relativeProjectDir = null)
465485
{
466486
if (string.IsNullOrEmpty (relativeProjectDir)) {

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.ProjectTools/Common/DotNetCLI.cs

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,18 @@ public class DotNetCLI
2121
readonly XASdkProject project;
2222
readonly string projectOrSolution;
2323

24-
public DotNetCLI (XASdkProject project, string projectOrSolution)
24+
public DotNetCLI (string projectOrSolution)
2525
{
26-
this.project = project;
2726
this.projectOrSolution = projectOrSolution;
2827
ProjectDirectory = Path.GetDirectoryName (projectOrSolution);
2928
}
3029

30+
public DotNetCLI (XASdkProject project, string projectOrSolution)
31+
: this (projectOrSolution)
32+
{
33+
this.project = project;
34+
}
35+
3136
/// <summary>
3237
/// Runs the `dotnet` tool with the specified arguments.
3338
/// </summary>
@@ -73,6 +78,16 @@ protected bool Execute (params string [] args)
7378
return succeeded;
7479
}
7580

81+
public bool New (string template, string output = null)
82+
{
83+
var arguments = new List<string> {
84+
"new",
85+
template,
86+
"--output", $"\"{output ?? ProjectDirectory}\"",
87+
};
88+
return Execute (arguments.ToArray ());
89+
}
90+
7691
public bool Build (string target = null, string [] parameters = null)
7792
{
7893
var arguments = GetDefaultCommandLineArgs ("build", target, parameters);
@@ -123,14 +138,16 @@ List<string> GetDefaultCommandLineArgs (string verb, string target = null, strin
123138
var arguments = new List<string> {
124139
verb,
125140
$"\"{projectOrSolution}\"",
126-
$"/p:Configuration={project.Configuration}",
127141
"/noconsolelogger",
128142
$"/flp1:LogFile=\"{BuildLogFile}\";Encoding=UTF-8;Verbosity={Verbosity}",
129143
$"/bl:\"{Path.Combine (testDir, "msbuild.binlog")}\""
130144
};
131145
if (!string.IsNullOrEmpty (target)) {
132146
arguments.Add ($"/t:{target}");
133147
}
148+
if (project != null) {
149+
arguments.Add ($"/p:Configuration={project.Configuration}");
150+
}
134151
if (Directory.Exists (AndroidSdkPath)) {
135152
arguments.Add ($"/p:AndroidSdkDirectory=\"{AndroidSdkPath}\"");
136153
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project>
2+
<Import Project="..\..\build-tools\scripts\XAVersionInfo.targets" />
3+
<PropertyGroup>
4+
<BeforePack>
5+
_GetDefaultPackageVersion;
6+
$(BeforePack);
7+
</BeforePack>
8+
</PropertyGroup>
9+
<Target Name="_GetDefaultPackageVersion"
10+
DependsOnTargets="GetXAVersionInfo" >
11+
<PropertyGroup>
12+
<PackageVersion>$(AndroidPackVersionLong)+sha.$(XAVersionHash)</PackageVersion>
13+
</PropertyGroup>
14+
</Target>
15+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"$schema": "http://json.schemastore.org/template",
3+
"author": "Microsoft",
4+
"classifications": [ "Android" ],
5+
"name": "Android Activity template",
6+
"description": "An Android Activity class",
7+
"tags": {
8+
"language": "C#",
9+
"type": "item"
10+
},
11+
"identity": "Microsoft.Android.AndroidActivity",
12+
"shortName": "android-activity",
13+
"sourceName": "Activity1",
14+
"primaryOutputs": [
15+
{ "path": "Activity1.cs" }
16+
],
17+
"defaultName": "Activity1",
18+
"symbols": {
19+
"namespace": {
20+
"description": "namespace for the generated code",
21+
"replaces": "AndroidApp1",
22+
"type": "parameter"
23+
}
24+
}
25+
}

0 commit comments

Comments
 (0)