Skip to content

Commit

Permalink
[One .NET] add $(AndroidGenerateResourceDesigner) property (#6224)
Browse files Browse the repository at this point in the history
Fixes: #6198

When migrating Xamarin.Android binding projects to .NET 6, one
difference is that `Resource.designer.cs` will be generated by .NET 6
class libraries.

This can result in build failures, e.g.:

	error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'

There is not currently a way to turn this off; if you try:

	dotnet build -p:AndroidUseIntermediateDesignerFile=false

Then `Resources\Resource.designer.cs` will be generated instead.
There is no way to prevent this behavior, because
`$(AndroidResgenFile)` defaults to this value.

To solve cases where you *don't* want `Resource.designer.cs` at all:

 1. Remove the `$(AndroidResgenFile)` default value.

 2. Add a new `$(AndroidGenerateResourceDesigner)` MSBuild property,
    that seems like it will be a better name for .NET 6.
    `$(AndroidGenerateResourceDesigner)` defaults to True.

 3. `$(AndroidUseIntermediateDesignerFile)` is based on
    `$(AndroidGenerateResourceDesigner)`.

This way, if a Xamarin.Android binding project is migrated to .NET 6,
the binding project can set `$(AndroidGenerateResourceDesigner)`=False
to prevent `Resource.designer.cs` from being generated, which may
prevent build failures.

I added a test and docs for the new property.
  • Loading branch information
jonathanpeppers committed Aug 25, 2021
1 parent 5f408eb commit 02c3347
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 4 deletions.
33 changes: 32 additions & 1 deletion Documentation/guides/OneDotNetBindingProjects.md
Expand Up @@ -217,5 +217,36 @@ As the default for .NET 6 is `disable`, the same applies for Xamarin Android pro

Use `enable` as shown above to enable NRT support.


[11-0-release-notes]: https://docs.microsoft.com/en-us/xamarin/android/release-notes/11/11.0

### `Resource.designer.cs`

In Xamarin.Android, Java binding projects did not support generating a `Resource.designer.cs` file.
Since binding projects are just class libraries in .NET 6, this file will be generated. This could
be a breaking change when migrating existing projects.

One example of a failure from this change, is if your binding generates a class named `Resource`
in the root namespace:

```
error CS0101: The namespace 'MyBinding' already contains a definition for 'Resource'
```

Or in the case of AndroidX, we have project files with `-` in the name such as
`androidx.window/window-extensions.csproj`. This results in the root namespace `window-extensions`
and invalid C# in `Resource.designer.cs`:

```
error CS0116: A namespace cannot directly contain members such as fields, methods or statements
error CS1514: { expected
error CS1022: Type or namespace definition, or end-of-file expected
```

To disable `Resource.designer.cs` generation, set `$(AndroidGenerateResourceDesigner)` to `false`
in your `.csproj`:

```xml
<PropertyGroup>
<AndroidGenerateResourceDesigner>false</AndroidGenerateResourceDesigner>
</PropertyGroup>
```
6 changes: 6 additions & 0 deletions Documentation/guides/building-apps/build-properties.md
Expand Up @@ -569,6 +569,12 @@ Enables generation of [layout code-behind](https://github.com/xamarin/xamarin-an
if set to `true` or disables it completely if set to `false`. The
default value is `false`.

## AndroidGenerateResourceDesigner

Defaults to `true`. When set to `false`, disables the generation of `Resource.designer.cs`.

Added in .NET 6 RC 1. Not supported in Xamarin.Android.

## AndroidHttpClientHandlerType

Controls the default
Expand Down
Expand Up @@ -7,11 +7,11 @@
<MonoAndroidResourcePrefix Condition=" '$(MonoAndroidResourcePrefix)' == '' ">Resources</MonoAndroidResourcePrefix>
<MonoAndroidAssetsPrefix Condition=" '$(MonoAndroidAssetsPrefix)' == '' ">Assets</MonoAndroidAssetsPrefix>
<AndroidResgenClass Condition=" '$(AndroidResgenClass)' == '' ">Resource</AndroidResgenClass>
<AndroidResgenFile Condition=" '$(AndroidResgenFile)' == '' ">$(MonoAndroidResourcePrefix)\$(_AndroidResourceDesigner)</AndroidResgenFile>
<AndroidEnableSGenConcurrent Condition=" '$(AndroidEnableSGenConcurrent)' == '' ">true</AndroidEnableSGenConcurrent>
<AndroidHttpClientHandlerType Condition=" '$(AndroidHttpClientHandlerType)' == '' and '$(UsingAndroidNETSdk)' == 'true' ">Xamarin.Android.Net.AndroidMessageHandler</AndroidHttpClientHandlerType>
<AndroidHttpClientHandlerType Condition=" '$(AndroidHttpClientHandlerType)' == '' and '$(UsingAndroidNETSdk)' != 'true' ">Xamarin.Android.Net.AndroidClientHandler</AndroidHttpClientHandlerType>
<AndroidUseIntermediateDesignerFile Condition=" '$(AndroidUseIntermediateDesignerFile)' == '' ">true</AndroidUseIntermediateDesignerFile>
<AndroidGenerateResourceDesigner Condition=" '$(AndroidGenerateResourceDesigner)' == '' ">true</AndroidGenerateResourceDesigner>
<AndroidUseIntermediateDesignerFile Condition=" '$(AndroidUseIntermediateDesignerFile)' == '' ">$(AndroidGenerateResourceDesigner)</AndroidUseIntermediateDesignerFile>
<GenerateDependencyFile Condition=" '$(GenerateDependencyFile)' == '' ">false</GenerateDependencyFile>
<CopyLocalLockFileAssemblies Condition=" '$(CopyLocalLockFileAssemblies)' == '' ">false</CopyLocalLockFileAssemblies>
<ComputeNETCoreBuildOutputFiles Condition=" '$(ComputeNETCoreBuildOutputFiles)' == '' ">false</ComputeNETCoreBuildOutputFiles>
Expand Down
Expand Up @@ -286,6 +286,37 @@ public void DotNetLibraryAarChanges ()
}
}

[Test]
public void GenerateResourceDesigner_false()
{
var proj = new XASdkProject (outputType: "Library") {
Sources = {
new AndroidItem.AndroidResource (() => "Resources\\drawable\\foo.png") {
BinaryContent = () => XamarinAndroidCommonProject.icon_binary_mdpi,
},
}
};
// Turn off Resource.designer.cs and remove usage of it
proj.SetProperty ("AndroidGenerateResourceDesigner", "false");
proj.MainActivity = proj.DefaultMainActivity
.Replace ("Resource.Layout.Main", "0")
.Replace ("Resource.Id.myButton", "0");

var dotnet = CreateDotNetBuilder (proj);
Assert.IsTrue (dotnet.Build (), "build should succeed");

var intermediate = Path.Combine (FullProjectDirectory, proj.IntermediateOutputPath);
var resource_designer_cs = Path.Combine (intermediate, "Resource.designer.cs");
FileAssert.DoesNotExist (resource_designer_cs);

var assemblyPath = Path.Combine (FullProjectDirectory, proj.OutputPath, $"{proj.ProjectName}.dll");
FileAssert.Exists (assemblyPath);
using var assembly = AssemblyDefinition.ReadAssembly (assemblyPath);
var typeName = $"{proj.ProjectName}.Resource";
var type = assembly.MainModule.GetType (typeName);
Assert.IsNull (type, $"{assemblyPath} should *not* contain {typeName}");
}

[Test]
[Category ("SmokeTests")]
public void DotNetBuildBinding ()
Expand Down
Expand Up @@ -7,6 +7,7 @@
<_ApkDebugKeyStore>debug.keystore</_ApkDebugKeyStore>
<EnableDefaultItems>false</EnableDefaultItems>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<AndroidResgenFile>Resources\Resource.designer.cs</AndroidResgenFile>
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
<AppendTargetFrameworkToIntermediateOutputPath>false</AppendTargetFrameworkToIntermediateOutputPath>
Expand Down
Expand Up @@ -33,7 +33,6 @@

<ItemGroup>
<Compile Remove="..\Resources\Resource.designer.cs" />
<Compile Include="Resources\Resource.designer.cs" />
<Compile Include="System\AppContextTests.cs" />
<!-- Mono.Data.Sqlite is not supported in .NET 6 -->
<Compile Remove="..\Mono.Data.Sqlite\SqliteTests.cs" />
Expand Down

0 comments on commit 02c3347

Please sign in to comment.