killapp/Assets/Scripts/Editor/SHA1Helper.cs
2026-04-16 14:57:19 +08:00

323 lines
11 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System.Diagnostics;
using System.IO;
using UnityEditor;
using UnityEngine;
namespace Kill.Editor
{
/// <summary>
/// SHA-1 指纹获取工具
/// </summary>
public class SHA1Helper : EditorWindow
{
private string sha1Result = "";
private Vector2 scrollPosition;
[MenuItem("Tools/SHA-1 指纹获取工具")]
public static void ShowWindow()
{
GetWindow<SHA1Helper>("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);
}
/// <summary>
/// 获取 Debug SHA-1
/// </summary>
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");
}
/// <summary>
/// 获取 Release SHA-1
/// </summary>
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);
}
/// <summary>
/// 运行 keytool 命令
/// </summary>
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}";
}
}
/// <summary>
/// 读取所有字节
/// </summary>
private byte[] ReadAllBytes(System.IO.Stream stream)
{
using (var ms = new System.IO.MemoryStream())
{
stream.CopyTo(ms);
return ms.ToArray();
}
}
/// <summary>
/// 尝试多种编码解码
/// </summary>
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);
}
/// <summary>
/// 检查是否包含乱码
/// </summary>
private bool ContainsGarbled(string text)
{
// 检查是否包含常见的乱码字符
foreach (char c in text)
{
if (c == '<27>' || c == '?' || (c >= 0x80 && c <= 0x9F))
{
return true;
}
}
return false;
}
/// <summary>
/// 从输出中提取 SHA1
/// </summary>
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();
}
/// <summary>
/// 获取 keytool 路径
/// </summary>
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";
}
}
}