killapp/Assets/Scripts/Editor/SHA1Helper.cs

323 lines
11 KiB
C#
Raw Normal View History

2026-04-16 14:57:19 +08:00
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";
}
}
}