22 private enum AppInstallStatus
30 private const float TimeOut = 10.0f;
31 private const float MaxWaitTime = 20.0f;
36 private static readonly
string API_GetMachineNameQuery =
@"{0}/api/os/machinename";
37 private static readonly
string API_ProcessQuery =
@"{0}/api/resourcemanager/processes";
38 private static readonly
string API_PackagesQuery =
@"{0}/api/appx/packagemanager/packages";
39 private static readonly
string API_InstallQuery =
@"{0}/api/app/packagemanager/package";
40 private static readonly
string API_InstallStatusQuery =
@"{0}/api/app/packagemanager/state";
41 private static readonly
string API_AppQuery =
@"{0}/api/taskmanager/app";
42 private static readonly
string API_FileQuery =
@"{0}/api/filesystem/apps/file?knownfolderid=LocalAppData&filename=UnityPlayer.log&packagefullname={1}&path=%5C%5CTempState";
43 private static readonly
string API_IpConfigQuery =
@"{0}/api/networking/ipconfig";
53 private static string GetBasicAuthHeader(
ConnectInfo connectionInfo,
bool isGetRequest =
false)
56 auth = Convert.ToBase64String(Encoding.GetEncoding(
"ISO-8859-1").GetBytes(auth));
57 return string.Format(
"Basic {0}", auth);
67 private static string WebRequestGet(
string query,
string auth,
bool showProgressDialog =
true)
71 using (var webRequest = UnityWebRequest.Get(query))
73 webRequest.SetRequestHeader(
"Authorization", auth);
74 #if UNITY_2017_1_OR_NEWER 75 webRequest.timeout = (int)TimeOut;
78 #if UNITY_2017_2_OR_NEWER 79 webRequest.SendWebRequest();
84 while (!webRequest.isDone)
86 if (webRequest.downloadProgress > -1 && showProgressDialog)
88 EditorUtility.DisplayProgressBar(
"Connecting to Device Portal",
89 "Progress...", webRequest.downloadProgress);
93 if (showProgressDialog)
95 EditorUtility.ClearProgressBar();
99 #
if UNITY_2017_1_OR_NEWER
100 webRequest.isNetworkError || webRequest.isHttpError &&
102 webRequest.isError &&
104 webRequest.responseCode != 401)
106 string response =
string.Empty;
107 var responseHeaders = webRequest.GetResponseHeaders();
108 if (responseHeaders != null)
110 response = responseHeaders.Aggregate(
string.Empty, (current, header) =>
string.Format(
"{0}{1}: {2}\n", current, header.Key, header.Value));
113 Debug.LogErrorFormat(
"Network Error: {0}\n{1}", webRequest.error, response);
117 switch (webRequest.responseCode)
121 return webRequest.downloadHandler.text;
123 Debug.LogError(
"Unauthorized: Access is denied due to invalid credentials.");
126 Debug.LogError(webRequest.responseCode);
133 Debug.LogException(e);
147 private static string WebRequestPost(
string query, WWWForm postData,
string auth,
bool showDialog =
true)
151 using (var webRequest = UnityWebRequest.Post(query, postData))
153 webRequest.SetRequestHeader(
"Authorization", auth);
154 #if UNITY_2017_1_OR_NEWER 155 webRequest.timeout = (int)TimeOut;
159 string contentType = webRequest.GetRequestHeader(
"Content-Type");
160 if (contentType != null)
162 contentType = contentType.Replace(
"\"",
"");
163 webRequest.SetRequestHeader(
"Content-Type", contentType);
166 #if UNITY_2017_2_OR_NEWER 167 webRequest.SendWebRequest();
172 while (!webRequest.isDone)
174 if (webRequest.uploadProgress > -1 && showDialog)
176 EditorUtility.DisplayProgressBar(
"Connecting to Device Portal",
177 "Uploading...", webRequest.uploadProgress);
179 else if (webRequest.downloadProgress > -1 && showDialog)
181 EditorUtility.DisplayProgressBar(
"Connecting to Device Portal",
182 "Progress...", webRequest.downloadProgress);
186 EditorUtility.ClearProgressBar();
189 #
if UNITY_2017_1_OR_NEWER
190 webRequest.isNetworkError || webRequest.isHttpError &&
192 webRequest.isError &&
194 webRequest.responseCode != 401)
196 string response =
string.Empty;
197 var responseHeaders = webRequest.GetResponseHeaders();
198 if (responseHeaders != null)
200 response = responseHeaders.Aggregate(
string.Empty, (current, header) =>
string.Format(
"{0}{1}: {2}\n", current, header.Key, header.Value));
203 Debug.LogErrorFormat(
"Network Error: {0}\n{1}", webRequest.error, response);
207 switch (webRequest.responseCode)
211 return webRequest.downloadHandler.text;
213 Debug.LogError(
"Unauthorized: Access is denied due to invalid credentials.");
216 Debug.LogError(webRequest.responseCode);
223 Debug.LogException(e);
236 private static bool WebRequestDelete(
string query,
string auth,
bool showDialog =
true)
240 using (var webRequest = UnityWebRequest.Delete(query))
242 webRequest.SetRequestHeader(
"Authorization", auth);
243 #if UNITY_2017_1_OR_NEWER 244 webRequest.timeout = (int)TimeOut;
247 #if UNITY_2017_2_OR_NEWER 248 webRequest.SendWebRequest();
253 while (!webRequest.isDone)
255 if (showDialog && webRequest.downloadProgress > -1)
257 EditorUtility.DisplayProgressBar(
"Connecting to Device Portal",
258 "Progress...", webRequest.downloadProgress);
262 EditorUtility.ClearProgressBar();
265 #
if UNITY_2017_1_OR_NEWER
266 webRequest.isNetworkError || webRequest.isHttpError &&
268 webRequest.isError &&
270 webRequest.responseCode != 401)
272 string response =
string.Empty;
273 var responseHeaders = webRequest.GetResponseHeaders();
274 if (responseHeaders != null)
276 response = responseHeaders.Aggregate(
string.Empty, (current, header) =>
string.Format(
"{0}{1}: {2}\n", current, header.Key, header.Value));
279 Debug.LogErrorFormat(
"Network Error: {0}\n{1}", webRequest.error, response);
283 switch (webRequest.responseCode)
288 Debug.LogError(
"Unauthorized: Access is denied due to invalid credentials.");
291 Debug.LogError(webRequest.responseCode);
298 Debug.LogException(e);
311 Process.Start(FinalizeUrl(targetDevice.
IP));
322 string query =
string.Format(API_GetMachineNameQuery, FinalizeUrl(targetDevice.
IP));
323 string response = WebRequestGet(query, GetBasicAuthHeader(targetDevice,
true),
false);
325 if (!
string.IsNullOrEmpty(response))
327 machineName = JsonUtility.FromJson<
MachineName>(response);
333 [Obsolete(
"Use IsAppInstalled(string packageFamilyName, ConnectInfo targetDevice)")]
347 return QueryAppDetails(packageFamilyName, targetDevice) != null;
350 [Obsolete(
"IsAppRunning(string appName, ConnectInfo targetDevice)")]
364 string response = WebRequestGet(
string.Format(API_ProcessQuery, FinalizeUrl(targetDevice.
IP)), GetBasicAuthHeader(targetDevice,
true),
false);
366 if (!
string.IsNullOrEmpty(response))
368 var processList = JsonUtility.FromJson<
ProcessList>(response);
369 for (
int i = 0; i < processList.Processes.Length; ++i)
373 if (processName.Contains(appName))
391 string response = WebRequestGet(
string.Format(API_PackagesQuery, FinalizeUrl(targetDevice.
IP)), GetBasicAuthHeader(targetDevice,
true),
false);
393 if (!
string.IsNullOrEmpty(response))
395 var appList = JsonUtility.FromJson<
AppList>(response);
396 for (
int i = 0; i < appList.InstalledPackages.Length; ++i)
399 if (thisAppName.Equals(packageFamilyName, StringComparison.OrdinalIgnoreCase))
401 return appList.InstalledPackages[i];
418 bool success =
false;
423 string fileName = Path.GetFileName(appFullPath);
424 string certFullPath = Path.ChangeExtension(appFullPath,
".cer");
425 string certName = Path.GetFileName(certFullPath);
426 string depPath = Path.GetDirectoryName(appFullPath) +
@"\Dependencies\x86\";
429 var form =
new WWWForm();
432 Debug.Assert(appFullPath != null);
433 using (var stream =
new FileStream(appFullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
435 using (var reader =
new BinaryReader(stream))
437 form.AddBinaryData(fileName, reader.ReadBytes((
int)reader.BaseStream.Length), fileName);
442 Debug.Assert(certFullPath != null);
443 using (var stream =
new FileStream(certFullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
445 using (var reader =
new BinaryReader(stream))
447 form.AddBinaryData(certName, reader.ReadBytes((
int)reader.BaseStream.Length), certName);
452 FileInfo[] depFiles =
new DirectoryInfo(depPath).GetFiles();
453 foreach (FileInfo dep
in depFiles)
455 using (var stream =
new FileStream(dep.FullName, FileMode.Open, FileAccess.Read, FileShare.Read))
457 using (var reader =
new BinaryReader(stream))
459 string depFilename = Path.GetFileName(dep.FullName);
460 form.AddBinaryData(depFilename, reader.ReadBytes((
int)reader.BaseStream.Length), depFilename);
466 string query =
string.Format(API_InstallQuery, FinalizeUrl(targetDevice.
IP));
467 query +=
"?package=" + WWW.EscapeURL(fileName);
469 var response = WebRequestPost(query, form, GetBasicAuthHeader(targetDevice));
471 if (
string.IsNullOrEmpty(response))
473 Debug.LogErrorFormat(
"Failed to install {0} on {1}.\n", fileName, targetDevice.
MachineName);
478 DateTime waitStartTime = DateTime.Now;
479 while (waitForDone && (DateTime.Now - waitStartTime).TotalSeconds < MaxWaitTime)
481 EditorUtility.DisplayProgressBar(
"Connecting to Device Portal",
"Installing...", (
float)((DateTime.Now - waitStartTime).TotalSeconds / MaxWaitTime));
482 AppInstallStatus status = GetInstallStatus(targetDevice);
484 if (status == AppInstallStatus.InstallSuccess)
486 Debug.LogFormat(
"Successfully installed {0} on {1}.", fileName, targetDevice.
MachineName);
491 if (status == AppInstallStatus.InstallFail)
493 Debug.LogErrorFormat(
"Failed to install {0} on {1}.\n", fileName, targetDevice.
MachineName);
501 EditorUtility.ClearProgressBar();
505 Debug.LogException(e);
512 private static AppInstallStatus GetInstallStatus(
ConnectInfo targetDevice)
514 string response = WebRequestGet(
string.Format(API_InstallStatusQuery, FinalizeUrl(targetDevice.
IP)), GetBasicAuthHeader(targetDevice,
true),
false);
516 if (!
string.IsNullOrEmpty(response))
522 return AppInstallStatus.Installing;
527 return AppInstallStatus.InstallSuccess;
530 Debug.LogError(status.Reason +
"(" + status.CodeText +
")");
534 return AppInstallStatus.Installing;
537 return AppInstallStatus.InstallFail;
540 [Obsolete(
"Use UninstallApp(string packageFamilyName, ConnectInfo targetDevice)")]
541 public static bool UninstallApp(
string packageFamilyName,
string targetIp)
555 AppDetails appDetails = QueryAppDetails(packageFamilyName, targetDevice);
556 if (appDetails == null)
558 Debug.Log(
string.Format(
"Application '{0}' not found", packageFamilyName));
562 string query =
string.Format(
"{0}?package={1}",
563 string.Format(API_InstallQuery, FinalizeUrl(targetDevice.
IP)),
566 bool success = WebRequestDelete(query, GetBasicAuthHeader(targetDevice), showDialog);
567 MachineName targetMachine = GetMachineName(targetDevice);
571 Debug.LogFormat(
"Successfully uninstalled {0} on {1}.", packageFamilyName, targetMachine.
ComputerName);
575 Debug.LogErrorFormat(
"Failed to uninstall {0} on {1}", packageFamilyName, targetMachine.
ComputerName);
591 AppDetails appDetails = QueryAppDetails(packageFamilyName, targetDevice);
593 if (appDetails == null)
595 Debug.LogWarning(
"Application not found");
599 string query =
string.Format(API_AppQuery, FinalizeUrl(targetDevice.
IP)) +
600 string.Format(
"?appid={0}&package={1}",
603 WebRequestPost(query, null, GetBasicAuthHeader(targetDevice),
false);
605 return IsAppRunning(PlayerSettings.productName, targetDevice);
608 [Obsolete(
"KillApp(string packageFamilyName, ConnectInfo targetDevice)")]
609 public static bool KillApp(
string packageFamilyName,
string targetIp)
621 public static bool KillApp(
string packageFamilyName,
ConnectInfo targetDevice,
bool showDialog =
true)
623 AppDetails appDetails = QueryAppDetails(packageFamilyName, targetDevice);
624 if (appDetails == null)
626 Debug.LogError(
"Application not found");
630 string query =
string.Format(
"{0}?package={1}",
631 string.Format(API_AppQuery, FinalizeUrl(targetDevice.
IP)),
634 bool success = WebRequestDelete(query, GetBasicAuthHeader(targetDevice), showDialog);
635 MachineName targetMachine = GetMachineName(targetDevice);
639 Debug.LogFormat(
"Successfully stopped {0} on {1}.", packageFamilyName, targetMachine.
ComputerName);
645 [Obsolete(
"DeviceLogFile_View(string packageFamilyName, ConnectInfo targetDevice)")]
659 EditorUtility.DisplayProgressBar(
"Download Log",
"Downloading Log File for " + packageFamilyName, 0.25f);
661 AppDetails appDetails = QueryAppDetails(packageFamilyName, targetDevice);
662 if (appDetails == null)
664 Debug.LogWarningFormat(
"{0} not installed on target device", packageFamilyName);
665 EditorUtility.ClearProgressBar();
669 string logFile =
string.Format(
"{0}/{1}_{2}{3}{4}{5}{6}{7}_deviceLog.txt",
670 Application.temporaryCachePath,
677 DateTime.Now.Second);
679 string response = WebRequestGet(
string.Format(API_FileQuery, FinalizeUrl(targetDevice.
IP), appDetails.
PackageFullName), GetBasicAuthHeader(targetDevice,
true));
680 bool success = !
string.IsNullOrEmpty(response);
684 File.WriteAllText(logFile, response);
685 Process.Start(logFile);
688 EditorUtility.ClearProgressBar();
700 string response = WebRequestGet(
string.Format(API_IpConfigQuery, FinalizeUrl(targetDevice.
IP)), GetBasicAuthHeader(targetDevice,
true),
false);
701 if (!
string.IsNullOrEmpty(response))
703 return JsonUtility.FromJson<
NetworkInfo>(response);
715 private static string FinalizeUrl(
string targetUrl)
719 if (targetUrl.Contains(
"Local Machine"))
721 targetUrl =
"127.0.0.1:10080";
724 return string.Format(
@"http{0}://{1}", ssl, targetUrl);
727 private static string EncodeTo64(
string toEncode)
729 byte[] toEncodeAsBytes = Encoding.ASCII.GetBytes(toEncode);
730 string returnValue = Convert.ToBase64String(toEncodeAsBytes);
734 private static string DecodeFrom64(
string encodedData)
736 byte[] encodedDataAsBytes = Convert.FromBase64String(encodedData);
737 string returnValue = Encoding.ASCII.GetString(encodedDataAsBytes);