Resolving the .NET MAUI “VersionCode 1.0 is invalid. It must be an integer value.” error when updating Visual Studio 2022 Preview

I installed the Visual Studio 2022 Preview 6 this evening. I had been using Preview 4. I installed Preview 5, but didn’t have a chance to play with it. I have a simple demo app that I have working with, a basic stopwatch type of app. That app had been created with Preview 4 and it more or less worked fine (unless you counted Mac Catalyst and Windows). After I installed Preview 6, I tried to run the project on Android. It failed to compile with the following error message:

Severity	Code	Description	Project	File	Line	Suppression State
Error	XA0003	VersionCode 1.0 is invalid. It must be an integer value.
Parameter name: VersionCode	StopwatchMaui	....\StopwatchMaui\obj\Debug\net6.0-android\android\AndroidManifest.xml

As a test, I created a new .NET MAUI app from Preview 6. It compiled and ran just fine.

So who now, what now? When I first saw the error, I didn’t pay too much attention to the full path, just the file name. With .NET MAUI, there is an AndroidManifest.xml in the android platform folder.

And we take a look at the file, it’s pretty standard, pretty boring AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
	<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
	<application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application>
	<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>

No versionCode there. What’s going on? So I went back and actually read the error message and it was complaining about a version of AndroidManifest.xml located in obj\Debug\net6.0-android. That little fellow looks like this:

<?xml version="1.0" encoding="utf-8"?>
<!--
    This code was generated by a tool.
    It was generated from ....\StopwatchMaui\Platforms\Android\AndroidManifest.xml
    Changes to this file may cause incorrect behavior and will be lost if
    the contents are regenerated.
    -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1.0" package="com.companyname.StopwatchMaui" android:versionName="1.0.0">
  <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="31" />
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
  <application android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true" android:name="crc64c1104ba8f6ea44b3.MainApplication" android:label="StopwatchMaui" android:debuggable="true" android:extractNativeLibs="true">
    <activity android:configChanges="orientation|smallestScreenSize|screenLayout|screenSize|uiMode" android:theme="@style/Maui.SplashTheme" android:name="crc64c1104ba8f6ea44b3.MainActivity" android:exported="true">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Battery Broadcast Receiver" android:name="crc64192d9de59b079c6d.BatteryBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Energy Saver Broadcast Receiver" android:name="crc64192d9de59b079c6d.EnergySaverBroadcastReceiver" />
    <receiver android:enabled="true" android:exported="false" android:label="Essentials Connectivity Broadcast Receiver" android:name="crc64192d9de59b079c6d.ConnectivityBroadcastReceiver" />
    <activity android:configChanges="orientation|screenSize" android:name="crc64192d9de59b079c6d.IntermediateActivity" />
    <provider android:authorities="com.companyname.StopwatchMaui.fileProvider" android:exported="false" android:grantUriPermissions="true" android:name="xamarin.essentials.fileProvider">
      <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/xamarin_essentials_fileprovider_file_paths" />
    </provider>
    <activity android:configChanges="orientation|screenSize" android:name="crc64192d9de59b079c6d.WebAuthenticatorIntermediateActivity" />
    <service android:name="crc64396a3fe5f8138e3f.KeepAliveService" />
    <provider android:name="mono.MonoRuntimeProvider" android:exported="false" android:initOrder="1999999999" android:authorities="com.companyname.StopwatchMaui.mono.MonoRuntimeProvider.__mono_init__" />
  </application>
</manifest>

If we look at line 8, we see the culprit

<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:versionCode="1.0" 
    package="com.companyname.StopwatchMaui" 
    android:versionName="1.0.0">

In the new app that was created in Preview 6, the same file had the following line:

<manifest 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:versionCode="1" 
    package="com.companyname.StopwatchMaui" 
    android:versionName="1.0.0">

So why is the first one bad and the second one good? In the wacky world of Android, android:versionCode has to have an integer value. This is documented here. So now we know what is the actual error, the next question is why that error occurred.

We can’t just edit the obj\Debug\net6.0-android\AndroidManifest.xml file and call it a day. The next time you rebuild the app, that file gets generated from Platforms\Android\AndroidManifest.xml. And apparently it pulls in information from somewhere else as well.

So I took a look at the .csproj files for the working and non-working apps. In the .csproj file generated by Preview 4, the version information was defined with the following two lines

<!-- Versions -->
<ApplicationVersion>1.0</ApplicationVersion>
<AndroidVersionCode>1</AndroidVersionCode>

With the new project freshly generated by Release 6, the same two lines were now a single line, with the ApplicationVersion now set with an integer value.

<!-- Versions -->
<ApplicationVersion>1</ApplicationVersion>

When I changed the “Versions” lines .csproj to match the single line used in the new .csproj Preview 6, the app compiled and deployed to Android. My best guess is that AndroidVersionCode was being used in Preview 4 and sometime after that, they made the breaking change to ApplicationVersion and jettisoned the AndroidVersionCode setting. It’s a preview release of Visual Studio and they are still baking .NET MAUI. This kind of stuff happens and the end result is a better product.