for build tool
This commit is contained in:
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using UnityEngine;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
public class PostBuildAdbInstall : IPostprocessBuildWithReport
|
||||
{
|
||||
private const string PrefKey = "PerfectWorld/AutoAdbInstallAfterAndroidBuild";
|
||||
|
||||
public int callbackOrder => 200;
|
||||
|
||||
[MenuItem("Tools/Perfect World/Auto install APK after build (toggle)")]
|
||||
private static void ToggleAutoInstall()
|
||||
{
|
||||
bool v = !EditorPrefs.GetBool(PrefKey, true);
|
||||
EditorPrefs.SetBool(PrefKey, v);
|
||||
Debug.Log("[AdbInstall] Auto install after Android build: " + (v ? "ON" : "OFF"));
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Perfect World/Auto install APK after build (toggle)", true)]
|
||||
private static bool ToggleAutoInstallValidate()
|
||||
{
|
||||
UnityEditor.Menu.SetChecked("Tools/Perfect World/Auto install APK after build (toggle)", EditorPrefs.GetBool(PrefKey, true));
|
||||
return true;
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Perfect World/Install APK to device (choose file)")]
|
||||
private static void InstallApkFromPicker()
|
||||
{
|
||||
string p = EditorUtility.OpenFilePanel("Pick APK", "", "apk");
|
||||
if (string.IsNullOrEmpty(p))
|
||||
return;
|
||||
RunAdbInstall(p);
|
||||
}
|
||||
|
||||
public void OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
if (report.summary.platform != BuildTarget.Android)
|
||||
return;
|
||||
if (report.summary.result != BuildResult.Succeeded)
|
||||
return;
|
||||
if (!EditorPrefs.GetBool(PrefKey, true))
|
||||
return;
|
||||
|
||||
string outputPath = report.summary.outputPath;
|
||||
string apkPath = ResolveApkPath(outputPath);
|
||||
if (string.IsNullOrEmpty(apkPath))
|
||||
{
|
||||
if (!string.IsNullOrEmpty(outputPath) &&
|
||||
outputPath.EndsWith(".aab", StringComparison.OrdinalIgnoreCase) &&
|
||||
File.Exists(outputPath))
|
||||
{
|
||||
Debug.LogWarning(
|
||||
"[AdbInstall] Output is .aab; adb install needs an APK. Disable App Bundle for dev, or use menu to install a built APK.");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("[AdbInstall] No .apk found. Build output: " + outputPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
RunAdbInstall(apkPath);
|
||||
}
|
||||
|
||||
private static string ResolveApkPath(string outputPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(outputPath))
|
||||
return null;
|
||||
|
||||
if (File.Exists(outputPath) && outputPath.EndsWith(".apk", StringComparison.OrdinalIgnoreCase))
|
||||
return outputPath;
|
||||
|
||||
if (File.Exists(outputPath) && outputPath.EndsWith(".aab", StringComparison.OrdinalIgnoreCase))
|
||||
return null;
|
||||
|
||||
if (Directory.Exists(outputPath))
|
||||
{
|
||||
var apks = new List<string>(Directory.GetFiles(outputPath, "*.apk", SearchOption.AllDirectories));
|
||||
if (apks.Count == 0)
|
||||
return null;
|
||||
apks.Sort((a, b) => File.GetLastWriteTimeUtc(b).CompareTo(File.GetLastWriteTimeUtc(a)));
|
||||
return apks[0];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void RunAdbInstall(string apkPath)
|
||||
{
|
||||
string adb = FindAdbExecutable();
|
||||
if (string.IsNullOrEmpty(adb))
|
||||
{
|
||||
Debug.LogError(
|
||||
"[AdbInstall] adb.exe not found. Install Android Build Support (SDK) in Unity Hub, or set ANDROID_HOME, or add platform-tools to PATH. Editor: " + (EditorApplication.applicationPath ?? "(null)"));
|
||||
return;
|
||||
}
|
||||
|
||||
string serial = GetSingleDeviceOrFirst(adb, out string listErr);
|
||||
if (serial == null)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(listErr))
|
||||
Debug.LogWarning("[AdbInstall] " + listErr);
|
||||
return;
|
||||
}
|
||||
|
||||
string argPrefix = string.IsNullOrEmpty(serial) ? "" : ("-s " + serial + " ");
|
||||
string args = argPrefix + "install -r \"" + apkPath + "\"";
|
||||
|
||||
var psi = new ProcessStartInfo(adb, args)
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
using (var p = Process.Start(psi))
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
Debug.LogError("[AdbInstall] Failed to start adb.");
|
||||
return;
|
||||
}
|
||||
string std = p.StandardOutput.ReadToEnd();
|
||||
string err = p.StandardError.ReadToEnd();
|
||||
p.WaitForExit(120000);
|
||||
if (p.ExitCode == 0)
|
||||
Debug.Log("[AdbInstall] Installed: " + apkPath + "\n" + std + err);
|
||||
else
|
||||
Debug.LogError("[AdbInstall] Install failed (exit " + p.ExitCode + "): " + apkPath + "\n" + std + err);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError("[AdbInstall] " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetSingleDeviceOrFirst(string adb, out string error)
|
||||
{
|
||||
error = null;
|
||||
var psi = new ProcessStartInfo(adb, "devices")
|
||||
{
|
||||
UseShellExecute = false,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
CreateNoWindow = true,
|
||||
};
|
||||
string stdout;
|
||||
try
|
||||
{
|
||||
using (var p = Process.Start(psi))
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
error = "Could not run adb devices.";
|
||||
return null;
|
||||
}
|
||||
stdout = p.StandardOutput.ReadToEnd();
|
||||
p.WaitForExit(10000);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
error = ex.Message;
|
||||
return null;
|
||||
}
|
||||
|
||||
var onlines = new List<string>();
|
||||
var lines = stdout.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
for (int i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if (i == 0 && lines[i].IndexOf("List of devices", StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
continue;
|
||||
int tab = lines[i].IndexOf('\t');
|
||||
if (tab < 0)
|
||||
continue;
|
||||
string id = lines[i].Substring(0, tab).Trim();
|
||||
string st = lines[i].Substring(tab + 1).Trim();
|
||||
if (st.Equals("device", StringComparison.OrdinalIgnoreCase))
|
||||
onlines.Add(id);
|
||||
}
|
||||
|
||||
if (onlines.Count == 0)
|
||||
{
|
||||
error = "No Android device in state \"device\" (enable USB debugging, cable, allow PC).";
|
||||
return null;
|
||||
}
|
||||
if (onlines.Count == 1)
|
||||
return "";
|
||||
Debug.LogWarning("[AdbInstall] Multiple devices - installing to: " + onlines[0]);
|
||||
return onlines[0];
|
||||
}
|
||||
|
||||
private static string FindAdbExecutable()
|
||||
{
|
||||
foreach (string root in EnumerateAndroidSdkRoots())
|
||||
{
|
||||
string a = TryAdbInSdk(root);
|
||||
if (!string.IsNullOrEmpty(a))
|
||||
return a;
|
||||
}
|
||||
|
||||
var pathvar = Environment.GetEnvironmentVariable("PATH");
|
||||
if (!string.IsNullOrEmpty(pathvar))
|
||||
{
|
||||
foreach (var part in pathvar.Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
var t = part.Trim();
|
||||
if (t.Length > 1 && t[0] == '"' && t[t.Length - 1] == '"')
|
||||
t = t.Substring(1, t.Length - 2);
|
||||
var candidate = Path.Combine(t, "adb.exe");
|
||||
if (File.Exists(candidate))
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> EnumerateAndroidSdkRoots()
|
||||
{
|
||||
var seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
void Add(string p)
|
||||
{
|
||||
if (string.IsNullOrEmpty(p)) return;
|
||||
p = p.Trim();
|
||||
if (p.Length == 0) return;
|
||||
seen.Add(p);
|
||||
}
|
||||
|
||||
Add(Environment.GetEnvironmentVariable("ANDROID_HOME"));
|
||||
Add(Environment.GetEnvironmentVariable("ANDROID_SDK_ROOT"));
|
||||
string ext = GetUnityAndroidSdkRootPathFromSettings();
|
||||
if (!string.IsNullOrEmpty(ext))
|
||||
Add(ext);
|
||||
if (EditorPrefs.HasKey("AndroidSdkRoot"))
|
||||
Add(EditorPrefs.GetString("AndroidSdkRoot", ""));
|
||||
|
||||
try
|
||||
{
|
||||
string editorExe = EditorApplication.applicationPath;
|
||||
if (!string.IsNullOrEmpty(editorExe))
|
||||
{
|
||||
string editorDir = Path.GetDirectoryName(editorExe);
|
||||
if (!string.IsNullOrEmpty(editorDir))
|
||||
Add(Path.Combine(editorDir, "Data", "PlaybackEngines", "AndroidPlayer", "SDK"));
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
Add(Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
|
||||
"AppData", "Local", "Android", "Sdk"));
|
||||
|
||||
return seen;
|
||||
}
|
||||
|
||||
private static string GetUnityAndroidSdkRootPathFromSettings()
|
||||
{
|
||||
try
|
||||
{
|
||||
var t = Type.GetType("UnityEditor.Android.AndroidExternalToolsSettings, UnityEditor.Android.EModule");
|
||||
if (t == null) return null;
|
||||
var p = t.GetProperty("sdkRootPath", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
|
||||
if (p == null) return null;
|
||||
var s = p.GetValue(null) as string;
|
||||
if (string.IsNullOrEmpty(s)) return null;
|
||||
if (Directory.Exists(s)) return s;
|
||||
}
|
||||
catch { }
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string TryAdbInSdk(string sdkRoot)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sdkRoot) || !Directory.Exists(sdkRoot))
|
||||
return null;
|
||||
var adb = Path.Combine(sdkRoot, "platform-tools", "adb.exe");
|
||||
if (File.Exists(adb))
|
||||
return adb;
|
||||
adb = Path.Combine(sdkRoot, "adb.exe");
|
||||
if (File.Exists(adb))
|
||||
return adb;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 44ebaf0d93aaaaa4e82846358850f836
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4bc52f1ad066409458b0dd00add32cc1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user