Skip to content

Renaming Namespaces

Jonathan Pobst edited this page Sep 13, 2023 · 2 revisions

This feature was added in Xamarin.Android 12.3 (Visual Studio 2022 17.2).

Renaming Java packages to better fit C# namespace conventions is a common enough scenario that there is a shortcut to perform this in addition to the standard <metadata> mechanism.

Using traditional metadata to rename many packages can be tedious:

<attr path="/api/package[@name='com.xamarin.accessibility']" name="managedName">Xamarin.Accessibility</attr>
<attr path="/api/package[@name='com.xamarin.content']" name="managedName">Xamarin.Content</attr>
<attr path="/api/package[@name='com.xamarin.core']" name="managedName">Xamarin.Core</attr>
...

With <AndroidNamespaceReplacement>, the same MSBuild transform placed in the project file can be applied to all matching packages:

<ItemGroup>
  <AndroidNamespaceReplacement Include='com.xamarin' Replacement='Xamarin' />
</ItemGroup>

Specification

These replacements will only be run for <package> elements that do not specify a metadata @managedName attribute. If @managedName is used, you are opting to provide the exact desired name, it will not be processed further.

Unlike unused metadata, these replacement will not raise a warning if they are unused.

Case Sensitivity

Replacements take place after the automatic Pascal case transform, but the compare is case-insensitive.

Thus, both of the following are equivalent:

<AndroidNamespaceReplacement Include='Androidx' Replacement='AndroidX' />
<AndroidNamespaceReplacement Include='androidx' Replacement='AndroidX' />

Word Bounds

Replacements take place only on full words (namespace parts).

Thus,

<AndroidNamespaceReplacement Include='Com' Replacement='' />

Matches matches Com.Google.Library, but not Common.Google.Library or Google.Imaging.Dicom.

Multiple full words can be used:

<AndroidNamespaceReplacement Include='Com.Google' Replacement='Google' />
<AndroidNamespaceReplacement Include='Com.Androidx' Replacement='Xamarin.AndroidX' />

Word Position

The word part match can be constrained to the beginning or end of a namespace by appending a . or prepending a ., respectively.

<AndroidNamespaceReplacement Include='Androidx.' Replacement='Xamarin.AndroidX' />

matches Androidx.Core, but not Square.OkHttp.Androidx.

Similarly,

<AndroidNamespaceReplacement Include='.Compose' Replacement='ComposeUI' />

matches Google.AndroidX.Compose, but not Google.Compose.Writer.

Both prepending and appending a . makes it an exact match.

<AndroidNamespaceReplacement Include='.Androidx.' Replacement='Xamarin.AndroidX' />

matches Androidx, but not Google.Androidx.Core.

Replacement Order

Replacements run in the order specified by the <ItemGroup>, however adding to this group at different times may result in an unintended order.

Replacements are run sequentially, and multiple replacements may affect a single namespace.

<AndroidNamespaceReplacement Include='Androidx' Replacement='Xamarin.AndroidX' />
<AndroidNamespaceReplacement Include='View' Replacement='Views' />

changes Androidx.View to Xamarin.AndroidX.Views.

Relation to Metadata

Technically these are implemented as a special case of <metadata>, and can be placed directly in a metadata.xml file in their metadata form if desired.

That is, the MSBuild item:

<ItemGroup>
  <AndroidNamespaceReplacement Include='com.xamarin' Replacement='Xamarin' />
</ItemGroup>

could instead be placed in metadata.xml as:

<metadata>
  <ns-replace source='com.xamarin' replacement='Xamarin' />
</metadata>