You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux下用C#计算与Unity一致的deviceUniqueIdentifier

在Linux平台用C#实现与Unity一致的deviceUniqueIdentifier

Unity的SystemInfo.deviceUniqueIdentifier在Linux平台是通过收集多组硬件信息、拼接后做MD5哈希,最终转成小写十六进制字符串生成的。以下是与Unity逻辑对齐的C#实现方案:

核心实现步骤

  1. 读取Linux系统下的关键硬件标识(顺序必须与Unity一致):
    • 主板序列号(/sys/class/dmi/id/board_serial)
    • BIOS序列号(/sys/class/dmi/id/bios_serial)
    • 根分区UUID
    • CPU核心标识组合(从/proc/cpuinfo提取关键字段)
  2. 将上述信息按固定顺序拼接为字符串
  3. 对拼接后的字符串做MD5哈希,转换为小写十六进制字符串即得到目标标识

完整代码实现

using System;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Security.Cryptography;
using System.Text;

public class UnityDeviceIdentifier
{
    // 读取指定路径的文件内容,处理异常返回空字符串
    private static string ReadFileContent(string path)
    {
        try
        {
            return File.ReadAllText(path).Trim();
        }
        catch
        {
            return string.Empty;
        }
    }

    // 获取根分区的UUID
    private static string GetRootPartitionUuid()
    {
        try
        {
            var mounts = File.ReadAllLines("/proc/mounts");
            foreach (var line in mounts)
            {
                var parts = line.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                if (parts.Length >= 2 && parts[1] == "/")
                {
                    var devicePath = parts[0];
                    // 直接从by-uuid路径提取UUID
                    if (devicePath.StartsWith("/dev/disk/by-uuid/"))
                    {
                        return Path.GetFileName(devicePath);
                    }
                    // 从块设备uevent文件读取UUID
                    var blockName = Path.GetFileName(devicePath);
                    var ueventPath = $"/sys/block/{blockName}/uevent";
                    var ueventContent = ReadFileContent(ueventPath);
                    var uuidLine = ueventContent.Split('\n').FirstOrDefault(l => l.StartsWith("UUID="));
                    if (!string.IsNullOrEmpty(uuidLine))
                    {
                        return uuidLine.Substring(5).Trim();
                    }
                    break;
                }
            }
        }
        catch
        {
            // 忽略异常,返回空
        }
        return string.Empty;
    }

    // 收集所有需要的硬件信息,严格遵循Unity的拼接顺序
    private static string CollectHardwareInfo()
    {
        var boardSerial = ReadFileContent("/sys/class/dmi/id/board_serial");
        var biosSerial = ReadFileContent("/sys/class/dmi/id/bios_serial");
        var rootUuid = GetRootPartitionUuid();
        
        // 从/proc/cpuinfo提取关键CPU字段
        var cpuInfo = ReadFileContent("/proc/cpuinfo");
        var cpuKeyParts = cpuInfo.Split('\n')
            .Where(line => line.StartsWith("vendor_id") 
                         || line.StartsWith("cpu family") 
                         || line.StartsWith("model") 
                         || line.StartsWith("model name") 
                         || line.StartsWith("physical id") 
                         || line.StartsWith("core id"))
            .Select(line => line.Split(':')[1].Trim())
            .ToList();
        var cpuKey = string.Join("|", cpuKeyParts);

        return string.Join("|", boardSerial, biosSerial, rootUuid, cpuKey);
    }

    // 生成与Unity一致的deviceUniqueIdentifier
    public static string GetUnityDeviceUniqueIdentifier()
    {
        var hardwareString = CollectHardwareInfo();
        
        // 当核心硬件信息无法获取时, fallback 到可用的网卡MAC地址
        if (string.IsNullOrEmpty(hardwareString))
        {
            var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
            var macAddress = networkInterfaces
                .FirstOrDefault(n => n.OperationalStatus == OperationalStatus.Up 
                                  && !n.Description.Contains("loopback", StringComparison.OrdinalIgnoreCase))?
                .GetPhysicalAddress().ToString();
            hardwareString = macAddress ?? string.Empty;
        }

        using (var md5 = MD5.Create())
        {
            var bytes = Encoding.UTF8.GetBytes(hardwareString);
            var hashBytes = md5.ComputeHash(bytes);
            return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
        }
    }
}

注意事项

  • 权限要求:读取/sys/class/dmi/id下的文件需要root权限,普通用户执行时这些字段会返回空,此时会自动 fallback 到网卡MAC地址。
  • 顺序一致性:硬件信息的拼接顺序必须和Unity保持一致,否则哈希结果会完全不同。
  • 兼容性:部分嵌入式Linux系统可能缺少部分文件(比如dmi相关文件),代码已做异常处理,会自动降级到可用信息。

内容的提问来源于stack exchange,提问作者crackanddie

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:00:35