using System.Diagnostics; using System.IO; using UnityEditor; using UnityEngine; namespace Kill.Editor { /// /// SHA-1 指纹获取工具 /// public class SHA1Helper : EditorWindow { private string sha1Result = ""; private Vector2 scrollPosition; [MenuItem("Tools/SHA-1 指纹获取工具")] public static void ShowWindow() { GetWindow("SHA-1 指纹获取"); } private void OnGUI() { GUILayout.Label("SHA-1 指纹获取工具", EditorStyles.boldLabel); GUILayout.Space(10); // 调试密钥库 GUILayout.Label("调试版本 (Debug)", EditorStyles.boldLabel); if (GUILayout.Button("获取 Debug SHA-1", GUILayout.Height(30))) { GetDebugSHA1(); } GUILayout.Space(10); // 发布密钥库 GUILayout.Label("发布版本 (Release)", EditorStyles.boldLabel); EditorGUILayout.HelpBox( "请在 Player Settings > Publishing Settings 中配置密钥库路径和密码", MessageType.Info); if (GUILayout.Button("获取 Release SHA-1", GUILayout.Height(30))) { GetReleaseSHA1(); } GUILayout.Space(20); // 结果显示 GUILayout.Label("结果:", EditorStyles.boldLabel); scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Height(150)); EditorGUILayout.TextArea(sha1Result, GUILayout.ExpandHeight(true)); GUILayout.EndScrollView(); if (!string.IsNullOrEmpty(sha1Result)) { if (GUILayout.Button("复制到剪贴板")) { GUIUtility.systemCopyBuffer = sha1Result; UnityEngine.Debug.Log("已复制到剪贴板"); } } GUILayout.Space(10); // 使用说明 EditorGUILayout.HelpBox( "使用说明:\n" + "1. 点击对应按钮获取 SHA-1\n" + "2. 复制结果\n" + "3. 在 Firebase 控制台 → 项目设置 → 应用 → SHA-1 中添加", MessageType.Info); } /// /// 获取 Debug SHA-1 /// private void GetDebugSHA1() { string keytoolPath = GetKeytoolPath(); if (string.IsNullOrEmpty(keytoolPath)) { sha1Result = "错误: 找不到 keytool\n请确保已安装 JDK 并配置环境变量"; return; } string keystorePath = Path.Combine( System.Environment.GetFolderPath(System.Environment.SpecialFolder.UserProfile), ".android", "debug.keystore"); if (!File.Exists(keystorePath)) { sha1Result = $"错误: 找不到 Debug 密钥库\n路径: {keystorePath}\n\n请先构建一次 Android 项目自动生成"; return; } RunKeytool(keytoolPath, keystorePath, "androiddebugkey", "android"); } /// /// 获取 Release SHA-1 /// private void GetReleaseSHA1() { string keytoolPath = GetKeytoolPath(); if (string.IsNullOrEmpty(keytoolPath)) { sha1Result = "错误: 找不到 keytool\n请确保已安装 JDK 并配置环境变量"; return; } // 从 Player Settings 获取密钥库配置 string keystorePath = PlayerSettings.Android.keystoreName; string keystorePass = PlayerSettings.Android.keystorePass; string keyaliasName = PlayerSettings.Android.keyaliasName; string keyaliasPass = PlayerSettings.Android.keyaliasPass; if (string.IsNullOrEmpty(keystorePath)) { sha1Result = "错误: 未配置发布密钥库\n\n请在 Player Settings > Publishing Settings 中配置"; return; } if (!File.Exists(keystorePath)) { sha1Result = $"错误: 找不到密钥库文件\n路径: {keystorePath}"; return; } RunKeytool(keytoolPath, keystorePath, keyaliasName, keyaliasPass); } /// /// 运行 keytool 命令 /// private void RunKeytool(string keytoolPath, string keystorePath, string alias, string password) { ProcessStartInfo psi = new ProcessStartInfo { FileName = keytoolPath, Arguments = $"-list -v -alias {alias} -keystore \"{keystorePath}\" -storepass {password}", RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true }; try { using (Process process = Process.Start(psi)) { // 读取字节流并尝试多种编码 byte[] outputBytes = ReadAllBytes(process.StandardOutput.BaseStream); byte[] errorBytes = ReadAllBytes(process.StandardError.BaseStream); process.WaitForExit(); // 尝试多种编码解码 string output = TryDecode(outputBytes); string error = TryDecode(errorBytes); if (process.ExitCode == 0) { sha1Result = ExtractSHA1(output); } else { sha1Result = $"错误:\n{error}"; } } } catch (System.Exception ex) { sha1Result = $"执行失败: {ex.Message}"; } } /// /// 读取所有字节 /// private byte[] ReadAllBytes(System.IO.Stream stream) { using (var ms = new System.IO.MemoryStream()) { stream.CopyTo(ms); return ms.ToArray(); } } /// /// 尝试多种编码解码 /// private string TryDecode(byte[] bytes) { // 尝试的编码列表 System.Text.Encoding[] encodings = new System.Text.Encoding[] { System.Text.Encoding.UTF8, System.Text.Encoding.GetEncoding(936), // GBK System.Text.Encoding.GetEncoding(54936), // GB18030 System.Text.Encoding.Default }; foreach (var encoding in encodings) { try { string result = encoding.GetString(bytes); // 检查是否包含乱码特征 if (!ContainsGarbled(result)) { return result; } } catch { } } // 默认使用 UTF-8 return System.Text.Encoding.UTF8.GetString(bytes); } /// /// 检查是否包含乱码 /// private bool ContainsGarbled(string text) { // 检查是否包含常见的乱码字符 foreach (char c in text) { if (c == '�' || c == '?' || (c >= 0x80 && c <= 0x9F)) { return true; } } return false; } /// /// 从输出中提取 SHA1 /// private string ExtractSHA1(string output) { System.Text.StringBuilder result = new System.Text.StringBuilder(); // 提取证书指纹 string[] lines = output.Split('\n'); bool inCertificateFingerprints = false; foreach (string line in lines) { if (line.Contains("Certificate fingerprints")) { inCertificateFingerprints = true; result.AppendLine("证书指纹:"); continue; } if (inCertificateFingerprints) { if (string.IsNullOrWhiteSpace(line)) { inCertificateFingerprints = false; continue; } result.AppendLine(line.Trim()); // 提取 SHA1 值(用于 Firebase) if (line.Contains("SHA1")) { string sha1 = line.Split(':')[1].Trim(); result.AppendLine($"\n>>> Firebase 需要的 SHA-1: {sha1} <<<"); } } } if (result.Length == 0) { result.AppendLine("原始输出:"); result.AppendLine(output); } return result.ToString(); } /// /// 获取 keytool 路径 /// private string GetKeytoolPath() { // 尝试从 Unity 的 JDK 路径获取 string jdkPath = EditorApplication.applicationPath; // macOS if (Application.platform == RuntimePlatform.OSXEditor) { string keytool = Path.Combine(jdkPath, "Contents", "PlaybackEngines", "AndroidPlayer", "OpenJDK", "bin", "keytool"); if (File.Exists(keytool)) return keytool; } // Windows else if (Application.platform == RuntimePlatform.WindowsEditor) { // 尝试 Unity 自带的 JDK string unityJdk = Path.Combine(Path.GetDirectoryName(jdkPath), "Data", "PlaybackEngines", "AndroidPlayer", "OpenJDK", "bin", "keytool.exe"); if (File.Exists(unityJdk)) return unityJdk; // 尝试环境变量 string envKeytool = System.Environment.GetEnvironmentVariable("JAVA_HOME"); if (!string.IsNullOrEmpty(envKeytool)) { string keytool = Path.Combine(envKeytool, "bin", "keytool.exe"); if (File.Exists(keytool)) return keytool; } } // 尝试系统 PATH return "keytool"; } } }