DEV Community

Olivier Moussalli
Olivier Moussalli

Posted on

Cross-Platform .NET Licensing: Protect Apps on Windows, Mac, Linux & Mobile

Your .NET application runs on Windows, Mac, and Linux. How do you protect it with license keys that work everywhere?

This guide shows you how to implement cross-platform licensing for .NET applications with Quick License Manager, covering Windows, macOS, Linux, iOS, and Android.

Recommended solution: Quick License Manager Enterprise - the only complete cross-platform licensing solution for .NET ($999/year).


The Cross-Platform Challenge

Platforms you need to support:

  • ✅ Windows (.NET Framework, .NET 6/7/8/9/10)
  • ✅ macOS (.NET 6/7/8/9/10, Xamarin.Mac)
  • ✅ Linux (.NET 6/7/8/9/10)
  • ✅ iOS (Xamarin, .NET MAUI)
  • ✅ Android (Xamarin, .NET MAUI)

What doesn't work cross-platform:

  • ❌ Windows-specific APIs (Registry, WMI)
  • ❌ Platform-specific UI frameworks
  • ❌ Hardware identifiers (different per OS)
  • ❌ Most licensing solutions (Windows only)

What you need:

  1. Unified licensing API across all platforms
  2. Platform-specific hardware binding
  3. Online and offline activation
  4. Single license server for all platforms

Quick License Manager Enterprise: Cross-Platform Solution

QLM Enterprise supports all major platforms:

Platforms:

  • ✅ Windows: .NET Framework 2.0-4.8, .NET Core, .NET 6/7/8/9/10
  • ✅ macOS: .NET 6/7/8/9/10, Xamarin.Mac
  • ✅ Linux: .NET 6/7/8/9/10
  • ✅ iOS: Xamarin.iOS, .NET MAUI
  • ✅ Android: Xamarin.Android, .NET MAUI
  • ✅ Web: ASP.NET, ASP.NET Core, Blazor

Pricing: $999/year per developer/administrator (cross-platform)

Why QLM Enterprise:

  • Same API across all platforms
  • Single license server
  • Unified customer database
  • Platform-specific libraries included
  • Source code provided for mobile

Pricing: QLM Pricing


Cross-Platform Architecture

Windows Implementation

using QLM.LicenseLib;

public class WindowsLicensing
{
    private LicenseValidator lv;

    public bool ValidateLicense()
    {
        lv = new LicenseValidator("settings.xml");

        bool needsActivation = false;
        string errorMsg = string.Empty;

        // Windows: Use Computer Name binding
        bool isValid = lv.ValidateLicenseAtStartup(
            ELicenseBinding.ComputerName,
            ref needsActivation,
            ref errorMsg
        );

        if (needsActivation)
        {
            ShowActivationUI(); // QLM License Wizard
        }

        return isValid;
    }
}
Enter fullscreen mode Exit fullscreen mode

macOS/Linux Implementation

using QlmLicenseLib; // .NET Core library

public class CrossPlatformLicensing
{
    private QlmLicense license;

    public bool ValidateLicense()
    {
        license = new QlmLicense();
        license.DefineProduct(
            productID: 1,
            majorVersion: 1,
            minorVersion: 0,
            licenseType: "permanent",
            webServiceUrl: "https://yourserver.com/qlmservice.asmx"
        );

        // Read stored license key
        string computerKey = ReadStoredKey();

        if (string.IsNullOrEmpty(computerKey))
        {
            ShowActivationUI();
            return false;
        }

        // Validate license
        string computerID = GetPlatformComputerID();
        bool isValid = license.ValidateLicenseAtStartup(
            computerKey,
            computerID
        );

        return isValid;
    }

    private string GetPlatformComputerID()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            return Environment.MachineName;
        else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return GetMacSerialNumber();
        else // Linux
            return GetLinuxMachineID();
    }
}
Enter fullscreen mode Exit fullscreen mode

Tutorial: Protect .NET Core Console App


Hardware Binding Strategies

Windows Identifiers

// Computer Name (recommended for enterprise)
string id = Environment.MachineName;

// MAC Address
string id = lv.QlmLicenseObject.GetComputerID();

// Motherboard Serial
string id = lv.QlmLicenseObject.GetMotherboardSerial();
Enter fullscreen mode Exit fullscreen mode

macOS Identifiers

// Hardware UUID (recommended)
public string GetMacSerialNumber()
{
    var process = new Process
    {
        StartInfo = new ProcessStartInfo
        {
            FileName = "/usr/sbin/system_profiler",
            Arguments = "SPHardwareDataType",
            RedirectStandardOutput = true,
            UseShellExecute = false
        }
    };

    process.Start();
    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();

    // Parse for "Hardware UUID"
    var match = Regex.Match(output, @"Hardware UUID: (.+)");
    return match.Success ? match.Groups[1].Value.Trim() : "";
}
Enter fullscreen mode Exit fullscreen mode

Linux Identifiers

// Machine ID (recommended)
public string GetLinuxMachineID()
{
    try
    {
        return File.ReadAllText("/etc/machine-id").Trim();
    }
    catch
    {
        // Fallback: hostname
        return Dns.GetHostName();
    }
}
Enter fullscreen mode Exit fullscreen mode

Mobile Identifiers

iOS:

// Use identifierForVendor
string deviceID = UIDevice.CurrentDevice.IdentifierForVendor.AsString();
Enter fullscreen mode Exit fullscreen mode

Android:

// Use Android ID
string deviceID = Android.Provider.Settings.Secure.GetString(
    context.ContentResolver,
    Android.Provider.Settings.Secure.AndroidId
);
Enter fullscreen mode Exit fullscreen mode

Activation UI: Platform-Specific

Windows: QLM License Wizard

// Use pre-built wizard (Windows only)
public void ShowWindowsActivation()
{
    string wizardPath = Path.Combine(
        AppDomain.CurrentDomain.BaseDirectory,
        "QlmLicenseWizard.exe"
    );

    lv.QlmLicenseObject.LaunchProcess(
        wizardPath,
        $"/settings \"{settingsFile}\"",
        waitForExit: true,
        hiddenProcess: false
    );
}
Enter fullscreen mode Exit fullscreen mode

macOS/Linux/Mobile: Custom UI

QLM License Wizard is Windows-only. For other platforms, create your own UI:

public class CustomActivationDialog
{
    private QlmLicense license;

    public bool ActivateLicense(string activationKey, string email)
    {
        string computerID = GetPlatformComputerID();
        string computerName = GetPlatformComputerName();

        string response;
        bool success = license.ActivateLicense(
            webServiceUrl: license.WebServiceUrl,
            activationKey: activationKey,
            computerID: computerID,
            computerName: computerName,
            qlmVersion: license.QlmVersion,
            userData: email,
            response: out response
        );

        if (success)
        {
            // Parse response to get Computer Key
            string computerKey = ParseComputerKey(response);

            // Store Computer Key securely
            StoreKey(computerKey);

            return true;
        }

        ShowError(response);
        return false;
    }
}
Enter fullscreen mode Exit fullscreen mode

Storing License Keys: Platform-Specific

Windows

// Option 1: Registry (recommended)
using Microsoft.Win32;

public void StoreKeyWindows(string computerKey)
{
    using var key = Registry.CurrentUser.CreateSubKey(@"Software\YourCompany\YourApp");
    key.SetValue("LicenseKey", computerKey);
}

// Option 2: AppData folder
string path = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "YourCompany", "license.dat"
);
File.WriteAllText(path, computerKey);
Enter fullscreen mode Exit fullscreen mode

macOS

// Use Application Support directory
string path = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "YourCompany", "license.dat"
);
File.WriteAllText(path, computerKey);
Enter fullscreen mode Exit fullscreen mode

Linux

// Use ~/.config directory
string path = Path.Combine(
    Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
    "yourapp", "license.dat"
);
File.WriteAllText(path, computerKey);
Enter fullscreen mode Exit fullscreen mode

iOS

// Use Keychain
using Foundation;

public void StoreKeyiOS(string computerKey)
{
    var record = new SecRecord(SecKind.GenericPassword)
    {
        Account = "LicenseKey",
        Service = "YourApp",
        ValueData = NSData.FromString(computerKey, NSStringEncoding.UTF8)
    };

    SecKeyChain.Add(record);
}
Enter fullscreen mode Exit fullscreen mode

Android

// Use SharedPreferences (encrypted)
using Android.Content;

public void StoreKeyAndroid(string computerKey)
{
    var prefs = context.GetSharedPreferences("license", FileCreationMode.Private);
    var editor = prefs.Edit();
    editor.PutString("key", computerKey);
    editor.Apply();
}
Enter fullscreen mode Exit fullscreen mode

Complete Cross-Platform Example

Shared Code (.NET Standard)

// YourApp.Core (shared library)
public interface IPlatformService
{
    string GetComputerID();
    void StoreKey(string key);
    string ReadKey();
}

public class LicenseManager
{
    private readonly IPlatformService platform;
    private QlmLicense license;

    public LicenseManager(IPlatformService platformService)
    {
        platform = platformService;
        license = new QlmLicense();
    }

    public bool ValidateLicense()
    {
        string computerKey = platform.ReadKey();

        if (string.IsNullOrEmpty(computerKey))
            return false;

        string computerID = platform.GetComputerID();

        return license.ValidateLicenseAtStartup(computerKey, computerID);
    }

    public bool ActivateLicense(string activationKey)
    {
        string computerID = platform.GetComputerID();
        string response;

        bool success = license.ActivateLicense(
            "https://yourserver.com/qlmservice.asmx",
            activationKey,
            computerID,
            Environment.MachineName,
            license.QlmVersion,
            "",
            out response
        );

        if (success)
        {
            string computerKey = ParseComputerKey(response);
            platform.StoreKey(computerKey);
        }

        return success;
    }
}
Enter fullscreen mode Exit fullscreen mode

Windows Implementation

// YourApp.Windows
public class WindowsPlatformService : IPlatformService
{
    public string GetComputerID() => Environment.MachineName;

    public void StoreKey(string key)
    {
        using var regKey = Registry.CurrentUser.CreateSubKey(@"Software\YourApp");
        regKey.SetValue("License", key);
    }

    public string ReadKey()
    {
        using var regKey = Registry.CurrentUser.OpenSubKey(@"Software\YourApp");
        return regKey?.GetValue("License") as string;
    }
}
Enter fullscreen mode Exit fullscreen mode

macOS/Linux Implementation

// YourApp.Mac / YourApp.Linux
public class UnixPlatformService : IPlatformService
{
    public string GetComputerID()
    {
        if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            return GetMacHardwareUUID();
        else
            return File.ReadAllText("/etc/machine-id").Trim();
    }

    public void StoreKey(string key)
    {
        string path = GetLicensePath();
        Directory.CreateDirectory(Path.GetDirectoryName(path));
        File.WriteAllText(path, key);
    }

    public string ReadKey()
    {
        string path = GetLicensePath();
        return File.Exists(path) ? File.ReadAllText(path) : null;
    }

    private string GetLicensePath()
    {
        return Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "yourapp", "license.dat"
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Online Validation Across Platforms

public class CrossPlatformOnlineValidation
{
    public async Task<bool> ValidateOnlineAsync()
    {
        try
        {
            using var client = new HttpClient();

            var request = new
            {
                activationKey = GetStoredActivationKey(),
                computerKey = GetStoredComputerKey(),
                computerID = platform.GetComputerID()
            };

            var response = await client.PostAsJsonAsync(
                "https://yourserver.com/qlmservice.asmx/ValidateLicenseOnServer",
                request
            );

            if (response.IsSuccessStatusCode)
            {
                var result = await response.Content.ReadAsStringAsync();
                return result.Contains("\"result\":\"true\"");
            }

            return false;
        }
        catch
        {
            // Offline - allow grace period
            return true;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Offline Activation: Cross-Platform

Challenge: QLM License Wizard is Windows-only. Other platforms need custom workflow.

Solution: Use QLM Self-Help portal + QR codes

public class OfflineActivation
{
    public string GenerateActivationURL(string activationKey)
    {
        string computerID = platform.GetComputerID();
        string baseUrl = "https://yoursite.com/qlmselfhelp/QlmWebActivation.aspx";

        return $"{baseUrl}?is_avkey={activationKey}&is_pcid={computerID}";
    }

    public void ShowOfflineInstructions()
    {
        string url = GenerateActivationURL(activationKey);

        // Generate QR code
        var qrGenerator = new QRCodeGenerator();
        var qrCode = qrGenerator.CreateQrCode(url, QRCodeGenerator.ECCLevel.M);

        // Show to user with instructions
        ShowDialog(
            "Scan this QR code with your phone to activate offline",
            qrCode
        );
    }
}
Enter fullscreen mode Exit fullscreen mode

Testing Cross-Platform

[TestFixture]
public class CrossPlatformLicensingTests
{
    [Test]
    [Platform("Win")]
    public void TestWindows()
    {
        var platform = new WindowsPlatformService();
        var mgr = new LicenseManager(platform);

        Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
    }

    [Test]
    [Platform("Linux")]
    public void TestLinux()
    {
        var platform = new UnixPlatformService();
        var mgr = new LicenseManager(platform);

        Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
    }

    [Test]
    [Platform("MacOsX")]
    public void TestMac()
    {
        var platform = new UnixPlatformService();
        var mgr = new LicenseManager(platform);

        Assert.IsTrue(mgr.ActivateLicense("TEST-KEY"));
    }
}
Enter fullscreen mode Exit fullscreen mode

Related Reading

For more advanced licensing topics, check out these articles:

On HashNode:


Why Quick License Manager Enterprise

QLM Enterprise is the only complete cross-platform licensing solution for .NET:

All platforms: Windows, Mac, Linux, iOS, Android
Unified API: Same code across platforms
Single license server: Manage all platforms
Source code included: Mobile libraries (iOS, Android)
REST API: For non-.NET platforms
Proven: 20+ years, thousands of customers

Pricing: $999/year per developer/administrator

Alternative: Build your own (6-12 months development) or QLM Professional ($699/year, Windows only)


Getting Started

1. Download trial:
QLM Downloads

2. Read tutorials:

3. Contact sales:
support@soraco.co for cross-platform licensing advice


Resources


Building cross-platform .NET apps? Share your licensing challenges in the comments! 👇

Top comments (0)