getsentry / getsentry/sentry-dotnet

Support platform specific version formats

Open
#4,325 0 comments 0 reactions 0 assignees View on GitHub
.NET Feature
Dominant language
C#
Stars
770
Forks
248
Avg merge
3d 4h
Merged PRs (30d)
49

Description

### Description

Originally came up in https://github.com/getsentry/sentry-dotnet/issues/3801

When we [set a release](https://docs.sentry.io/platforms/dotnet/configuration/releases/#setting-a-release) we currently use the same format, regardless of the platform being targeted. However it appears different platforms have different conventions for version formats.

According to my LLM (so all of this probably needs to be fact checked):

## 📦 .NET MAUI Versioning Summary by Platform

| Platform | Format / Convention | MSBuild Properties / Notes |
|-------------|------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|
| **.NET Assembly** | `a.b.c.d` | `AssemblyVersion`, `AssemblyFileVersion`, `AssemblyInformationalVersion` |
| **Android** | `versionName`: `a.b.c (dddddd)`
`versionCode`: Integer | `1.2.3`
`456`
Common to append build metadata in parentheses |
| **iOS / macOS** | `CFBundleShortVersionString`: `a.b.c`
`CFBundleVersion`: `dddddd` | `1.2.3`
`456`
`CFBundleShortVersionString` **must** be in `a.b.c` format (Apple requirement) |
| **Windows** | `PackageVersion`: `a.b.c.d` | `1.2.3.4` |

### 🔍 Notes

- **Android:**
- `versionName` is shown to users, often includes build metadata (e.g., `1.2.3 (456)`).
- `versionCode` is used internally to determine update precedence and must increase with each build.

- **iOS/macOS:**
- `CFBundleShortVersionString` is the public version shown to users and must follow `a.b.c`.
- `CFBundleVersion` is the internal build number and can be any string, but Apple prefers it to be incrementing.

- **Windows:**
- `PackageVersion` must be a full four-part version (`a.b.c.d`).
- This format is consistent with traditional .NET assembly versioning.

- **.NET Assemblies:**
- Use standard four-part versioning: `AssemblyVersion`, `AssemblyFileVersion`, `AssemblyInformationalVersion`.

## 🔍 How to Access Version Information in .NET MAUI (Build-Time & Runtime)

| Platform | Build-Time Access | Runtime Access |
|----------------|-------------------------------------------------------|--------------------------------------------------------------------------------------------------|
| **.NET Assembly** | - `AssemblyVersion`, `AssemblyFileVersion`, etc.
- Read from `csproj`, `Directory.Build.props`, or `AssemblyInfo.cs` | - `typeof(App).Assembly.GetName().Version`
- `Assembly.GetExecutingAssembly()` with reflection |
| **Android** | - `` and `` in `csproj`
- `AndroidManifest.xml` generated from MSBuild props | - `Context.PackageManager.GetPackageInfo()` in Java/Android code
- MAUI: `Platform.CurrentActivity.PackageManager...`
- Or use [Plugin.VersionTracking](https://github.com/jamesmontemagno/VersionTrackingPlugin) |
| **iOS / macOS** | - `` and `` in `csproj`
- Placed into `Info.plist` by MSBuild | - `NSBundle.MainBundle.ObjectForInfoDictionary("CFBundleShortVersionString")`
- Or use `VersionTracking` plugin |
| **Windows** | - `` in `csproj` → used in `AppxManifest.xml` | - `Package.Current.Id.Version` from `Windows.ApplicationModel` namespace |

## 🏃 Runtime Version Access Examples in .NET MAUI

### 🔧 .NET Assembly (All Platforms)

Access the version embedded in the .NET assembly metadata.

```csharp
// Gets the version from the assembly identity (e.g., 1.2.3.4)
var version = typeof(App).Assembly.GetName().Version;

// Gets the file version (AssemblyFileVersion)
var fileVersion = Assembly
.GetExecutingAssembly()
.GetCustomAttribute()?.Version;
```

### 🤖 Android

Use Android APIs via `Platform.CurrentActivity` (from `Microsoft.Maui.ApplicationModel`) to retrieve version info.

```csharp
using Android.Content.PM;
using Microsoft.Maui.ApplicationModel;

var context = Platform.CurrentActivity;
var packageInfo = context.PackageManager.GetPackageInfo(context.PackageName, 0);

string versionName = packageInfo.VersionName; // e.g., "1.2.3"
int versionCode = (int)packageInfo.LongVersionCode; // e.g., 456
```

> 💡 Note: `LongVersionCode` is used for API level 28+ and is backward-compatible when cast to int.

### 🍏 iOS / macOS

Use `NSBundle` to read values from the native `Info.plist`.

```csharp
using Foundation;

// User-visible version (e.g., "1.2.3")
var shortVersion = NSBundle.MainBundle
.ObjectForInfoDictionary("CFBundleShortVersionString")?.ToString();

// Internal build number (e.g., "456")
var buildVersion = NSBundle.MainBundle
.ObjectForInfoDictionary("CFBundleVersion")?.ToString();
```

> 📘 CFBundleShortVersionString is the public version shown in the App Store.

> 📘 CFBundleVersion is the internal build number submitted to Apple.

### 🪟 Windows (UWP / WinAppSDK)

Use `Windows.ApplicationModel.Package` to retrieve the app version from the package metadata.

```csharp
using Windows.ApplicationModel;

var version = Package.Current.Id.Version;

string fullVersion = $"{version.Major}.{version.Minor}.{version.Build}.{version.Revision}";
// Example output: "1.2.3.4"
```
> ℹ️ This retrieves the version defined in your MSBuild property,
which maps to the Identity.Version field in the app package manifest (AppxManifest.xml).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.