BuildDeployWindow.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // Licensed under the MIT License. See LICENSE in the project root for license information.
  3. using Newtonsoft.Json;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Threading;
  9. using UnityEditor;
  10. using UnityEditor.Build.Reporting;
  11. using UnityEngine;
  12. using XRTool.UI;
  13. namespace XRTool.Util
  14. {
  15. public enum BuildTargets
  16. {
  17. NoHand = 0,
  18. Hand = 1,
  19. Both = 2,
  20. None = 3
  21. }
  22. /// <summary>
  23. /// 打包窗口
  24. /// </summary>
  25. public class BuildDeployWindow : EditorWindow
  26. {
  27. private Vector2 scrollPos;
  28. private static BuildConfig buildConf;
  29. /// <inheritdoc />
  30. public IEnumerable<string> Scenes { get; set; }
  31. public string outputPath;
  32. public bool isAutoUpdateVersion = true;
  33. private bool isOpenOutPath = true;
  34. private string realPath;
  35. private string serverPath;
  36. public BuildOptions buildOptions = BuildOptions.None;
  37. private string[] suffix = new string[] { ".exe", ".apk", "Project", };
  38. public string appName;
  39. private int buildIndex = 2;
  40. public const string initVersion = "1.0.0";
  41. private string allSymbol;
  42. private bool isAutoInstall = true;
  43. private string androidSDPath = "sdcard/Android/data/";
  44. private BuildTargets buildTargets;
  45. private string appProName = "MRStudio";
  46. private string appPackName = "com.shadowcreate.MRStudio";
  47. private int serverIndex;
  48. private string[] servers;
  49. [MenuItem("XRTool/Build Window", false, 0)]
  50. public static void OpenWindow()
  51. {
  52. // Dock it next to the Scene View.
  53. var window = GetWindow<BuildDeployWindow>(typeof(SceneView));
  54. window.titleContent = new GUIContent("Build Window");
  55. window.Show();
  56. }
  57. private void OnEnable()
  58. {
  59. PlayerSettings.companyName = "shadowcreator";
  60. buildIndex = 2;
  61. if (buildConf == null)
  62. {
  63. if (BuildConfigMgr.Instance.IsInit)
  64. {
  65. buildConf = BuildConfig.Instance;
  66. }
  67. else
  68. {
  69. UnityLog.Instance.LogError("配置初始化失败!");
  70. }
  71. //buildConf = AssetDatabase.LoadAssetAtPath<BuildConfig>("Assets/GameData/BuildConf/BuildConfig.asset");
  72. }
  73. titleContent = new GUIContent("Build Window");
  74. minSize = new Vector2(512, 256);
  75. CheckVersion();
  76. if (buildConf == null)
  77. {
  78. UnityLog.Instance.LogError("buildConf is null");
  79. }
  80. if (DataConfMgr<ServerConfig>.Instance.TableHelper == null)
  81. {
  82. DataConfMgr<ServerConfig>.Instance.OpenData(Application.streamingAssetsPath);
  83. }
  84. DataConfMgr<ServerConfig>.Instance.TableHelper.readConfComplete += OnReadConfComplete;
  85. DataConfMgr<ServerConfig>.Instance.OpenTable("serverName");
  86. //UnityLog.Instance.Log(buildConf);
  87. }
  88. /// <summary>
  89. /// 完成读取
  90. /// </summary>
  91. private void OnReadConfComplete()
  92. {
  93. if (DataConfMgr<ServerConfig>.Instance.TableHelper.DataList != null && DataConfMgr<ServerConfig>.Instance.TableHelper.DataList.Count > 0)
  94. {
  95. servers = new string[DataConfMgr<ServerConfig>.Instance.TableHelper.DataList.Count];
  96. for (int i = 0; i < DataConfMgr<ServerConfig>.Instance.TableHelper.DataList.Count; i++)
  97. {
  98. servers[i] = DataConfMgr<ServerConfig>.Instance.TableHelper.DataList[i].serverName;
  99. }
  100. }
  101. }
  102. private void CheckVersion()
  103. {
  104. string version = PlayerSettings.bundleVersion;
  105. string[] curversion = version.Split('.');
  106. if (curversion.Length < 3)
  107. {
  108. PlayerSettings.bundleVersion = initVersion;
  109. Debug.Log("版本号初始化:" + initVersion);
  110. }
  111. }
  112. /// <summary>
  113. /// 更新版本号,在打包时调用此函数
  114. /// </summary>
  115. public string UpdateGameVersion()
  116. {
  117. string version = PlayerSettings.bundleVersion;
  118. string[] curversion = version.Split('.');
  119. if (curversion.Length < 3)
  120. {
  121. Debug.LogError("请规范版本号:" + initVersion);
  122. return PlayerSettings.bundleVersion;
  123. }
  124. ///测试版本,程序自测版本
  125. if (buildConf.buildType == BuildType.Test)
  126. {
  127. return PlayerSettings.bundleVersion;
  128. }
  129. int startIndex = (int)buildConf.buildVersion;
  130. int ver = int.Parse(curversion[startIndex]) + 1;
  131. curversion[startIndex] = ver.ToString();
  132. if (buildConf.buildVersion != BuildVersion.Build)
  133. {
  134. for (int i = startIndex + 1; i < curversion.Length; i++)
  135. {
  136. curversion[i] = "0";
  137. }
  138. }
  139. string newVersion = curversion[0];
  140. for (int i = 1; i < curversion.Length; i++)
  141. {
  142. newVersion += "." + curversion[i];
  143. }
  144. return newVersion;
  145. }
  146. private void ChangeHand()
  147. {
  148. if (buildTargets == BuildTargets.Hand)
  149. {
  150. PlayerSettings.productName = appProName + "WithHand";
  151. BuildConfig.Instance.useHand = true;
  152. }
  153. else if (buildTargets == BuildTargets.NoHand)
  154. {
  155. PlayerSettings.productName = appProName + "NoHand";
  156. BuildConfig.Instance.useHand = false;
  157. }
  158. else
  159. {
  160. PlayerSettings.productName = appProName;
  161. BuildConfig.Instance.useHand = false;
  162. }
  163. PlayerSettings.applicationIdentifier = "com." + PlayerSettings.companyName + "." + PlayerSettings.productName;
  164. appPackName = PlayerSettings.applicationIdentifier;
  165. }
  166. /// <summary>
  167. /// 属性展示和同步
  168. /// </summary>
  169. private void OnGUI()
  170. {
  171. //buildConf = EditorGUI.ObjectField(new Rect(0, 5, 600, 20), "BuildSetting", buildConf, typeof(BuildConfig), true) as BuildConfig;
  172. if (!buildConf)
  173. {
  174. return;
  175. }
  176. scrollPos = GUI.BeginScrollView(new Rect(0, 30, position.width, position.height),
  177. scrollPos, new Rect(0, 0, 1920, 2160));
  178. if (servers != null)
  179. {
  180. int tmpI = serverIndex;
  181. serverIndex = EditorGUILayout.Popup("服务器选择", serverIndex, servers);
  182. if (serverIndex != tmpI)
  183. {
  184. ServerConfig sc = DataConfMgr<ServerConfig>.Instance.TableHelper.DataList[serverIndex];
  185. buildConf.loginUrl = sc.loginUrl;
  186. buildConf.lobbyUrl = sc.lobbyUrl;
  187. buildConf.roomUrl = sc.roomUrl;
  188. buildConf.rtcUrl = sc.rtcUrl;
  189. Debug.Log("当前服务器:" + JsonConvert.SerializeObject(sc));
  190. }
  191. }
  192. appProName = EditorGUILayout.TextField("应用名称", appProName);
  193. appPackName = EditorGUILayout.TextField("包名", appPackName);
  194. buildConf.buildVersion = (BuildVersion)EditorGUILayout.EnumPopup("版本类型", buildConf.buildVersion);
  195. buildConf.buildType = (BuildType)EditorGUILayout.EnumPopup("发布模式", buildConf.buildType);
  196. buildConf.assetsType = (AssetsType)EditorGUILayout.EnumPopup("资源访问方式", buildConf.assetsType);
  197. buildConf.buildTarget = (BuildTarget)EditorGUILayout.EnumPopup("运行的平台", buildConf.buildTarget);
  198. buildConf.playType = (PlayType)EditorGUILayout.EnumPopup("运行的模式", buildConf.playType);
  199. //buildConf.buildTargetGroup = (BuildTargetGroup)EditorGUILayout.EnumPopup("发布的平台", buildConf.buildTargetGroup);
  200. buildConf.otherSymbol = EditorGUILayout.TextField("宏", buildConf.otherSymbol);
  201. allSymbol = EditorGUILayout.TextField("全部宏", allSymbol);
  202. if (string.IsNullOrEmpty(allSymbol))
  203. {
  204. allSymbol = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildConf.buildTargetGroup);
  205. }
  206. isAutoUpdateVersion = EditorGUILayout.Toggle("更新版本", isAutoUpdateVersion);
  207. isOpenOutPath = EditorGUILayout.Toggle("打开输出路径", isOpenOutPath);
  208. if (buildConf.buildTarget == BuildTarget.Android)
  209. {
  210. isAutoInstall = EditorGUILayout.Toggle("自动安装", isAutoInstall);
  211. }
  212. EditorGUILayout.LabelField("Version", PlayerSettings.bundleVersion);
  213. EditorGUILayout.LabelField("发布时间", buildConf.buildTime);
  214. outputPath = EditorGUILayout.TextField("输出路径", outputPath);
  215. if (string.IsNullOrEmpty(outputPath))
  216. {
  217. string path = Application.dataPath;
  218. path = path.Substring(0, path.LastIndexOf("/"));
  219. outputPath = path;
  220. }
  221. realPath = EditorGUILayout.TextField("完整路径", realPath);
  222. serverPath = EditorGUILayout.TextField("服务器地址", serverPath);
  223. androidSDPath = EditorGUILayout.TextField("安卓sd卡路径", androidSDPath);
  224. if (string.IsNullOrEmpty(realPath))
  225. {
  226. realPath = Path.Combine(outputPath, buildConf.buildTarget.ToString(), buildConf.playType.ToString(), Application.productName);
  227. }
  228. buildOptions = (BuildOptions)EditorGUILayout.EnumPopup("发布设置", buildOptions);
  229. var bd = buildTargets;
  230. buildTargets = (BuildTargets)EditorGUILayout.EnumPopup("发布操作方式", buildTargets);
  231. if (bd != buildTargets)
  232. {
  233. ChangeHand();
  234. }
  235. if (GUILayout.Button("重置版本号", GUILayout.Width(200)))
  236. {
  237. buildConf.appVersion = initVersion;
  238. PlayerSettings.bundleVersion = buildConf.appVersion;
  239. }
  240. if (GUILayout.Button("强制升级版本", GUILayout.Width(200)))
  241. {
  242. PlayerSettings.bundleVersion = UpdateGameVersion();
  243. }
  244. if (GUILayout.Button("同步设置", GUILayout.Width(200)))
  245. {
  246. SetDef();
  247. }
  248. if (GUILayout.Button("清空编辑器日志", GUILayout.Width(200)))
  249. {
  250. UnityLog.Instance.ClearAllLog();
  251. }
  252. if (GUILayout.Button("打开编辑器缓存路径", GUILayout.Width(200)))
  253. {
  254. OpenDirectory(Application.persistentDataPath);
  255. }
  256. if (buildConf.buildTarget == BuildTarget.Android && GUILayout.Button("安装", GUILayout.Width(200)))
  257. {
  258. if (!string.IsNullOrEmpty(appName) && !string.IsNullOrEmpty(realPath))
  259. {
  260. InstallApp(Path.Combine(realPath, appName));
  261. }
  262. }
  263. if (buildConf.buildTarget == BuildTarget.Android && GUILayout.Button("卸载", GUILayout.Width(200)))
  264. {
  265. if (!string.IsNullOrEmpty(appName) && !string.IsNullOrEmpty(realPath))
  266. {
  267. UnInstallApp();
  268. }
  269. }
  270. if (GUILayout.Button("清空Androd日志", GUILayout.Width(200)))
  271. {
  272. if (Directory.Exists(realPath + "/" + UnityLog.LogPath))
  273. {
  274. Directory.Delete(realPath + "/" + UnityLog.LogPath, true);
  275. }
  276. }
  277. if (GUILayout.Button("拷贝缓存数据", GUILayout.Width(150)))
  278. {
  279. string resPath = "sdcard/ShadowCreate/MRStores/";
  280. string logPath = realPath + "/ShadowCreate/MRStores/";
  281. string[] files = new string[] { "DeviceDownInfo.xml" };
  282. if (!Directory.Exists(logPath))
  283. {
  284. Directory.CreateDirectory(logPath);
  285. }
  286. for (int i = 0; i < files.Length; i++)
  287. {
  288. string tmpPath = logPath + "/" + files[i];
  289. if (File.Exists(tmpPath))
  290. {
  291. File.Delete(tmpPath);
  292. }
  293. Thread newThread = new Thread(new ParameterizedThreadStart(RunCmd));
  294. string adb = "adb pull " + "\"" + resPath + files[i] + "\"" + " " + "\"" + logPath + "\"";
  295. newThread.Start(adb);
  296. }
  297. OpenDirectory(logPath);
  298. }
  299. if (GUILayout.Button("拷贝日志到本地", GUILayout.Width(150)))
  300. {
  301. string resPath = androidSDPath + Application.identifier + "/files/" + UnityLog.LogPath + "/";
  302. string logPath = realPath + "/" + buildConf.buildType.ToString() +
  303. "_" + PlayerSettings.bundleVersion + "/" + Application.version + "/" + UnityLog.LogPath;
  304. string[] files = new string[] { "error.txt", "except.txt", "log.txt" };
  305. if (!Directory.Exists(logPath))
  306. {
  307. Directory.CreateDirectory(logPath);
  308. }
  309. for (int i = 0; i < files.Length; i++)
  310. {
  311. string tmpPath = logPath + "/" + files[i];
  312. if (File.Exists(tmpPath))
  313. {
  314. File.Delete(tmpPath);
  315. }
  316. Thread newThread = new Thread(new ParameterizedThreadStart(RunCmd));
  317. string adb = "adb pull " + "\"" + resPath + files[i] + "\"" + " " + "\"" + logPath + "\"";
  318. newThread.Start(adb);
  319. }
  320. OpenDirectory(logPath);
  321. }
  322. if (GUILayout.Button("推送服务器地址", GUILayout.Width(150)))
  323. {
  324. string targetPath = androidSDPath + Application.identifier + "/files/";
  325. Thread newThread = new Thread(new ParameterizedThreadStart(RunCmd));
  326. string adb = "adb push " + "\""+serverPath + "\"" + " " + "\"" + targetPath + "\"";
  327. newThread.Start(adb);
  328. }
  329. if (GUILayout.Button("发布", GUILayout.Width(150)))
  330. {
  331. if (buildTargets != BuildTargets.Both)
  332. {
  333. DisPlayBuild(buildTargets);
  334. }
  335. else
  336. {
  337. ///先安装手势版本,再安装无手势版本
  338. DisPlayBuild(BuildTargets.Hand);
  339. isAutoUpdateVersion = false;
  340. DisPlayBuild(BuildTargets.NoHand);
  341. }
  342. }
  343. GUI.EndScrollView();
  344. //GUI.EndScrollView();
  345. if (GUI.changed)
  346. {
  347. UpdateSetting();
  348. }
  349. }
  350. public void DisPlayBuild(BuildTargets buildTargets)
  351. {
  352. string lastBuildTime = buildConf.buildTime;
  353. buildConf.buildTime = DateTime.Now.ToString();
  354. EditorUtility.SetDirty(buildConf);
  355. this.buildTargets = buildTargets;
  356. ChangeHand();
  357. ///设置宏编译指令
  358. SetDef();
  359. string lastVersion = PlayerSettings.bundleVersion;
  360. UpdateSetting();
  361. string newVersion = isAutoUpdateVersion ? UpdateGameVersion() : lastVersion;
  362. PlayerSettings.bundleVersion = newVersion;
  363. appName = Application.productName + "_" + buildConf.buildType.ToString() +
  364. "_" + PlayerSettings.bundleVersion + "_" + DateTime.Now.ToString("MMddHHmm") + "_" + servers[serverIndex] + suffix[buildIndex];
  365. bool isSucess = PlayerBuild(Path.Combine(realPath, appName));
  366. if (!isSucess)
  367. {
  368. PlayerSettings.bundleVersion = lastVersion;
  369. buildConf.buildTime = lastBuildTime;
  370. EditorUtility.SetDirty(buildConf);
  371. }
  372. else
  373. {
  374. if (isOpenOutPath)
  375. {
  376. OpenDirectory(realPath);
  377. }
  378. if (buildConf.buildTarget == BuildTarget.Android && isAutoInstall)
  379. {
  380. InstallApp(Path.Combine(realPath, appName));
  381. }
  382. }
  383. Debug.Log("当前版本" + PlayerSettings.bundleVersion);
  384. }
  385. private void InstallApp(string realPath)
  386. {
  387. if (File.Exists(realPath))
  388. {
  389. UnityLog.Instance.Log(realPath);
  390. Thread newThread = new Thread(new ParameterizedThreadStart(RunCmd));
  391. string cmd = "adb install -r -d " +"\""+ realPath+"\"";
  392. newThread.Start(cmd);
  393. }
  394. else
  395. {
  396. UnityLog.Instance.LogError(realPath + " 不存在");
  397. }
  398. }
  399. private void UnInstallApp()
  400. {
  401. Thread newThread = new Thread(new ParameterizedThreadStart(RunCmd));
  402. string cmd = "adb uninstall " + Application.identifier;
  403. newThread.Start(cmd);
  404. }
  405. private void UpdateSetting()
  406. {
  407. if (buildConf.buildTarget == BuildTarget.Android)
  408. {
  409. buildConf.buildTargetGroup = BuildTargetGroup.Android;
  410. if (EditorUserBuildSettings.exportAsGoogleAndroidProject)
  411. {
  412. buildIndex = 2;
  413. }
  414. else
  415. {
  416. buildIndex = 1;
  417. }
  418. }
  419. if (buildConf.buildTarget == BuildTarget.iOS)
  420. {
  421. buildConf.buildTargetGroup = BuildTargetGroup.iOS;
  422. buildIndex = 2;
  423. }
  424. if (buildConf.buildTarget == BuildTarget.StandaloneWindows)
  425. {
  426. buildConf.buildTargetGroup = BuildTargetGroup.Standalone;
  427. buildIndex = 0;
  428. }
  429. //buildConf.buildType.ToString(), buildConf.playType.ToString(),
  430. realPath = Path.Combine(outputPath, Application.productName, buildConf.buildTarget.ToString(), buildConf.playType.ToString());
  431. }
  432. private bool PlayerBuild(string path)
  433. {
  434. if (EditorUserBuildSettings.activeBuildTarget != buildConf.buildTarget)
  435. {
  436. EditorUserBuildSettings.SwitchActiveBuildTarget(buildConf.buildTargetGroup, buildConf.buildTarget);
  437. }
  438. BuildReport buildReport = Build(path);
  439. bool success = buildReport != null && buildReport.summary.result == BuildResult.Succeeded;
  440. return success;
  441. }
  442. private BuildReport Build(string path)
  443. {
  444. Scenes = EditorBuildSettings.scenes.Where(scene => scene.enabled).Select(scene => scene.path);
  445. EditorUtility.DisplayProgressBar("Build Pipeline", "Gathering Build Data...", 0.25f);
  446. BuildReport buildReport = default;
  447. try
  448. {
  449. buildReport = BuildPipeline.BuildPlayer(
  450. Scenes.ToArray(),
  451. path,
  452. EditorUserBuildSettings.activeBuildTarget, buildOptions);
  453. }
  454. catch (Exception e)
  455. {
  456. Debug.LogError($"{e.Message}\n{e.StackTrace}");
  457. }
  458. EditorUtility.ClearProgressBar();
  459. return buildReport;
  460. }
  461. private void SetDef()
  462. {
  463. string lastSym = PlayerSettings.GetScriptingDefineSymbolsForGroup(buildConf.buildTargetGroup);
  464. Debug.Log(lastSym);
  465. ///设置指令用;分割
  466. string symbol = string.Format("buildType_{0};assetsType_{1};buildPlatform_{2};playType_{3}",
  467. buildConf.buildType, buildConf.assetsType, buildConf.buildTarget, buildConf.playType).ToUpper() + ";" + buildConf.otherSymbol;
  468. if (symbol != lastSym)
  469. {
  470. Debug.Log(lastSym + "当前宏编译配置:" + symbol);
  471. PlayerSettings.SetScriptingDefineSymbolsForGroup(buildConf.buildTargetGroup, symbol);
  472. }
  473. allSymbol = symbol;
  474. }
  475. /// <summary>
  476. /// 弹出指定的文件窗口,仅windows和mac使用
  477. /// </summary>
  478. /// <param name="path"></param>
  479. public static void OpenDirectory(string path)
  480. {
  481. if (string.IsNullOrEmpty(path)) return;
  482. if (!Directory.Exists(path))
  483. {
  484. UnityEngine.Debug.LogError("No Directory: " + path);
  485. return;
  486. }
  487. path=path.Replace("/","\\");
  488. UnityLog.Instance.Log("Open Path"+path);
  489. //Application.dataPath 只能在主线程中获取
  490. //int lastIndex = Application.dataPath.LastIndexOf("/");
  491. //string shellPath = Application.dataPath.Substring(0, lastIndex) + "/Shell/";
  492. // 新开线程防止锁死
  493. Thread newThread = new Thread(new ParameterizedThreadStart(CmdOpenDirectory));
  494. newThread.Start(path);
  495. }
  496. private static void CmdOpenDirectory(object obj)
  497. {
  498. System.Diagnostics.Process p = new System.Diagnostics.Process();
  499. #if UNITY_EDITOR_WIN
  500. p.StartInfo.FileName = "cmd.exe";
  501. p.StartInfo.Arguments = "/c explorer " + obj.ToString();
  502. #elif UNITY_EDITOR_OSX
  503. p.StartInfo.FileName = "bash";
  504. string shPath = shellPath + "openDir.sh";
  505. p.StartInfo.Arguments = shPath + " " + obj.ToString();
  506. #endif
  507. //UnityEngine.Debug.Log(p.StartInfo.Arguments);
  508. p.StartInfo.UseShellExecute = false;
  509. p.StartInfo.RedirectStandardInput = true;
  510. p.StartInfo.RedirectStandardOutput = true;
  511. p.StartInfo.RedirectStandardError = true;
  512. p.StartInfo.CreateNoWindow = true;
  513. p.Start();
  514. p.WaitForExit();
  515. p.Close();
  516. }
  517. private static void RunCmd(object command)
  518. {
  519. //例Process
  520. System.Diagnostics.Process p = new System.Diagnostics.Process();
  521. p.StartInfo.FileName = "cmd.exe"; //确定程序名
  522. p.StartInfo.Arguments = "/c " + command.ToString(); //确定程式命令行
  523. p.StartInfo.UseShellExecute = false; //Shell的使用
  524. p.StartInfo.RedirectStandardInput = true; //重定向输入
  525. p.StartInfo.RedirectStandardOutput = true; //重定向输出
  526. p.StartInfo.RedirectStandardError = true; //重定向输出错误
  527. p.StartInfo.CreateNoWindow = false; //设置置不显示示窗口
  528. p.Start();
  529. //return p.StandardOutput.ReadToEnd(); //输出出流取得命令行结果果
  530. }
  531. }
  532. }