PXR_BuildProcessor.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*******************************************************************************
  2. Copyright © 2015-2022 PICO Technology Co., Ltd.All rights reserved.
  3. NOTICE:All information contained herein is, and remains the property of
  4. PICO Technology Co., Ltd. The intellectual and technical concepts
  5. contained herein are proprietary to PICO Technology Co., Ltd. and may be
  6. covered by patents, patents in process, and are protected by trade secret or
  7. copyright law. Dissemination of this information or reproduction of this
  8. material is strictly forbidden unless prior written permission is obtained from
  9. PICO Technology Co., Ltd.
  10. *******************************************************************************/
  11. using System;
  12. using System.Collections.Generic;
  13. using System.Xml;
  14. using UnityEngine;
  15. using UnityEngine.Rendering;
  16. using UnityEditor.Android;
  17. using UnityEditor.Build;
  18. using UnityEditor.Build.Reporting;
  19. using UnityEditor;
  20. using UnityEditor.XR.Management;
  21. using UnityEngine.XR.Management;
  22. namespace Unity.XR.PXR.Editor
  23. {
  24. public class PXR_BuildProcessor : XRBuildHelper<PXR_Settings>
  25. {
  26. public override string BuildSettingsKey { get { return "Unity.XR.PXR.Settings"; } }
  27. public static bool IsLoaderExists()
  28. {
  29. XRGeneralSettings generalSettings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(BuildTargetGroup.Android);
  30. if (generalSettings == null) return false;
  31. var assignedSettings = generalSettings.AssignedSettings;
  32. if (assignedSettings == null) return false;
  33. #if UNITY_2021_1_OR_NEWER
  34. foreach (XRLoader loader in assignedSettings.activeLoaders)
  35. {
  36. if (loader is PXR_Loader) return true;
  37. }
  38. #else
  39. foreach (XRLoader loader in assignedSettings.loaders)
  40. {
  41. if (loader is PXR_Loader) return true;
  42. }
  43. #endif
  44. return false;
  45. }
  46. private PXR_Settings PxrSettings
  47. {
  48. get
  49. {
  50. return SettingsForBuildTargetGroup(BuildTargetGroup.Android) as PXR_Settings;
  51. }
  52. }
  53. private void SetRequiredPluginInBuild()
  54. {
  55. PluginImporter[] plugins = PluginImporter.GetAllImporters();
  56. foreach (PluginImporter plugin in plugins)
  57. {
  58. if (plugin.assetPath.Contains("PxrPlatform.aar") || plugin.assetPath.Contains("pxr_api-release.aar"))
  59. {
  60. plugin.SetIncludeInBuildDelegate((path) =>
  61. {
  62. return IsLoaderExists();
  63. });
  64. }
  65. }
  66. }
  67. public override void OnPreprocessBuild(BuildReport report)
  68. {
  69. SetRequiredPluginInBuild();
  70. if (report.summary.platformGroup != BuildTargetGroup.Android)
  71. return;
  72. if (!IsLoaderExists())
  73. return;
  74. GraphicsDeviceType firstGfxType =
  75. PlayerSettings.GetGraphicsAPIs(EditorUserBuildSettings.activeBuildTarget)[0];
  76. if (firstGfxType != GraphicsDeviceType.OpenGLES3 && firstGfxType != GraphicsDeviceType.Vulkan && firstGfxType != GraphicsDeviceType.OpenGLES2)
  77. throw new BuildFailedException($"PICO Plugin on mobile platforms nonsupport the {firstGfxType}");
  78. if (PxrSettings.stereoRenderingModeAndroid == PXR_Settings.StereoRenderingModeAndroid.Multiview && firstGfxType == GraphicsDeviceType.OpenGLES2)
  79. PlayerSettings.SetGraphicsAPIs(BuildTarget.Android, new GraphicsDeviceType[] { GraphicsDeviceType.OpenGLES3 });
  80. if (PlayerSettings.Android.minSdkVersion < AndroidSdkVersions.AndroidApiLevel26)
  81. throw new BuildFailedException("Android Minimum API must be set to 26 or higher for PICO Plugin.");
  82. base.OnPreprocessBuild(report);
  83. }
  84. }
  85. #if UNITY_2021_3_OR_NEWER
  86. internal class PXR_BuildHooks : IPreprocessBuildWithReport, IPostprocessBuildWithReport
  87. {
  88. public int callbackOrder { get; }
  89. private static readonly Dictionary<string, string> AndroidBootConfigVars = new Dictionary<string, string>()
  90. {
  91. };
  92. public void OnPreprocessBuild(BuildReport report)
  93. {
  94. if (report.summary.platformGroup == BuildTargetGroup.Android)
  95. {
  96. var bootConfig = new BootConfig(report);
  97. bootConfig.ReadBootConfig();
  98. foreach (var entry in AndroidBootConfigVars)
  99. {
  100. bootConfig.SetValueForKey(entry.Key, entry.Value);
  101. }
  102. bootConfig.WriteBootConfig();
  103. }
  104. }
  105. public void OnPostprocessBuild(BuildReport report)
  106. {
  107. if (report.summary.platformGroup == BuildTargetGroup.Android)
  108. {
  109. BootConfig bootConfig = new BootConfig(report);
  110. bootConfig.ReadBootConfig();
  111. foreach (KeyValuePair<string, string> entry in AndroidBootConfigVars)
  112. {
  113. bootConfig.ClearEntryForKeyAndValue(entry.Key, entry.Value);
  114. }
  115. bootConfig.WriteBootConfig();
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// Small utility class for reading, updating and writing boot config.
  121. /// </summary>
  122. internal class BootConfig
  123. {
  124. private const string XrBootSettingsKey = "xr-boot-settings";
  125. private readonly Dictionary<string, string> bootConfigSettings;
  126. private readonly string buildTargetName;
  127. public BootConfig(BuildReport report)
  128. {
  129. bootConfigSettings = new Dictionary<string, string>();
  130. buildTargetName = BuildPipeline.GetBuildTargetName(report.summary.platform);
  131. }
  132. public void ReadBootConfig()
  133. {
  134. bootConfigSettings.Clear();
  135. string xrBootSettings = EditorUserBuildSettings.GetPlatformSettings(buildTargetName, XrBootSettingsKey);
  136. if (!string.IsNullOrEmpty(xrBootSettings))
  137. {
  138. var bootSettings = xrBootSettings.Split(';');
  139. foreach (var bootSetting in bootSettings)
  140. {
  141. var setting = bootSetting.Split(':');
  142. if (setting.Length == 2 && !string.IsNullOrEmpty(setting[0]) && !string.IsNullOrEmpty(setting[1]))
  143. {
  144. bootConfigSettings.Add(setting[0], setting[1]);
  145. }
  146. }
  147. }
  148. }
  149. public void SetValueForKey(string key, string value) => bootConfigSettings[key] = value;
  150. public bool TryGetValue(string key, out string value) => bootConfigSettings.TryGetValue(key, out value);
  151. public void ClearEntryForKeyAndValue(string key, string value)
  152. {
  153. if (bootConfigSettings.TryGetValue(key, out string dictValue) && dictValue == value)
  154. {
  155. bootConfigSettings.Remove(key);
  156. }
  157. }
  158. public void WriteBootConfig()
  159. {
  160. bool firstEntry = true;
  161. var sb = new System.Text.StringBuilder();
  162. foreach (var kvp in bootConfigSettings)
  163. {
  164. if (!firstEntry)
  165. {
  166. sb.Append(";");
  167. }
  168. sb.Append($"{kvp.Key}:{kvp.Value}");
  169. firstEntry = false;
  170. }
  171. EditorUserBuildSettings.SetPlatformSettings(buildTargetName, XrBootSettingsKey, sb.ToString());
  172. }
  173. }
  174. #endif
  175. #if UNITY_ANDROID
  176. internal class PXR_Manifest : IPostGenerateGradleAndroidProject
  177. {
  178. public void OnPostGenerateGradleAndroidProject(string path)
  179. {
  180. if (!PXR_BuildProcessor.IsLoaderExists())
  181. return;
  182. string originManifestPath = path + "/src/main/AndroidManifest.xml";
  183. XmlDocument doc = new XmlDocument();
  184. doc.Load(originManifestPath);
  185. string manifestTagPath = "/manifest";
  186. string applicationTagPath = manifestTagPath + "/application";
  187. string metaDataTagPath = applicationTagPath + "/meta-data";
  188. string usesPermissionTagName = "uses-permission";
  189. var settings = PXR_XmlTools.GetSettings();
  190. doc.InsertAttributeInTargetTag(applicationTagPath,null, new Dictionary<string, string>() {{"requestLegacyExternalStorage", "true"}});
  191. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.app.type"}},new Dictionary<string, string>{{"value","vr"}});
  192. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.sdk.version"}},new Dictionary<string, string>{{"value","XR Platform_2.4.3"}});
  193. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","enable_cpt"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().useContentProtect ? "1" : "0"}});
  194. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","handtracking"}},new Dictionary<string, string> {{"value",PXR_ProjectSetting.GetProjectConfig().handTracking ? "1" : "0" }});
  195. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","rendering_mode"}},new Dictionary<string, string>{{"value",((int)settings.stereoRenderingModeAndroid).ToString()}});
  196. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","display_rate"}},new Dictionary<string, string>{{"value",((int)settings.systemDisplayFrequency).ToString()}});
  197. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","color_Space"}},new Dictionary<string, string>{{"value",QualitySettings.activeColorSpace == ColorSpace.Linear ? "1" : "0"}});
  198. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","MRCsupport"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().openMRC ? "1" : "0" }});
  199. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.LateLatching"}}, new Dictionary<string, string> {{"value",PXR_ProjectSetting.GetProjectConfig().latelatching ? "1" : "0" } });
  200. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.LateLatchingDebug"}}, new Dictionary<string, string> {{"value", PXR_ProjectSetting.GetProjectConfig().latelatching && PXR_ProjectSetting.GetProjectConfig().latelatchingDebug ? "1" : "0" } });
  201. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","pvr.app.splash"} },new Dictionary<string, string>{{"value",settings.GetSystemSplashScreen(path)}});
  202. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","PICO.swift.feature"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().bodyTracking ? "1" : "0" }});
  203. doc.InsertAttributeInTargetTag(metaDataTagPath,new Dictionary<string, string>{{"name","adaptive_resolution"}},new Dictionary<string, string>{{"value",PXR_ProjectSetting.GetProjectConfig().adaptiveResolution ? "1" : "0" }});
  204. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "mr_map_require" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
  205. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_mr" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
  206. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_vst" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().videoSeeThrough ? "1" : "0" } });
  207. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "enable_anchor" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
  208. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "mr_map_mgr_auto_start" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().spatialAnchor ? "1" : "0" } });
  209. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.SuperResolution" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().superResolution ? "1" : "0" } });
  210. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.NormalSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().normalSharpening ? "1" : "0" } });
  211. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.QualitySharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().qualitySharpening ? "1" : "0" } });
  212. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.FixedFoveatedSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().fixedFoveatedSharpening ? "1" : "0" } });
  213. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "pvr.SelfAdaptiveSharpening" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().selfAdaptiveSharpening ? "1" : "0" } });
  214. doc.CreateElementInTag(manifestTagPath,usesPermissionTagName,new Dictionary<string, string>{{"name","android.permission.WRITE_SETTINGS"}});
  215. if (PXR_ProjectSetting.GetProjectConfig().eyeTracking || PXR_ProjectSetting.GetProjectConfig().enableETFR)
  216. {
  217. doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "com.picovr.permission.EYE_TRACKING" } });
  218. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.eye_tracking" } }, new Dictionary<string, string> { { "value", "1" } });
  219. doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "eyetracking_calibration" } }, new Dictionary<string, string> { { "value", PXR_ProjectSetting.GetProjectConfig().eyetrackingCalibration ? "true" : "false" } });
  220. }
  221. if (PXR_ProjectSetting.GetProjectConfig().faceTracking) { doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "com.picovr.permission.FACE_TRACKING" } }); }
  222. if (PXR_ProjectSetting.GetProjectConfig().lipsyncTracking) { doc.CreateElementInTag(manifestTagPath, usesPermissionTagName, new Dictionary<string, string> { { "name", "android.permission.RECORD_AUDIO" } }); }
  223. if (PXR_ProjectSetting.GetProjectConfig().faceTracking) { doc.InsertAttributeInTargetTag(metaDataTagPath, new Dictionary<string, string> { { "name", "picovr.software.face_tracking" } }, new Dictionary<string, string> { { "value", "false/true" } }); }
  224. doc.Save(originManifestPath);
  225. }
  226. public int callbackOrder { get { return 10000; } }
  227. }
  228. #endif
  229. public static class PXR_XmlTools
  230. {
  231. static readonly string androidURI = "http://schemas.android.com/apk/res/android";
  232. public static void InsertAttributeInTargetTag(this XmlDocument doc, string tagPath, Dictionary<string, string> filterDic, Dictionary<string, string> attributeDic)
  233. {
  234. XmlElement targetElement = null;
  235. if (filterDic == null)
  236. targetElement = doc.SelectSingleNode(tagPath) as XmlElement;
  237. else
  238. {
  239. XmlNodeList nodeList = doc.SelectNodes(tagPath);
  240. if (nodeList != null)
  241. {
  242. foreach (XmlNode node in nodeList)
  243. {
  244. if (FilterCheck(node as XmlElement, filterDic))
  245. {
  246. targetElement = node as XmlElement;
  247. break;
  248. }
  249. }
  250. }
  251. }
  252. if (targetElement == null)
  253. {
  254. string parentPath = tagPath.Substring(0, tagPath.LastIndexOf("/"));
  255. string tagName = tagPath.Substring(tagPath.LastIndexOf("/") + 1);
  256. foreach (var item in attributeDic)
  257. filterDic.Add(item.Key, item.Value);
  258. doc.CreateElementInTag(parentPath, tagName, filterDic);
  259. }
  260. else UpdateOrCreateAttribute(targetElement, attributeDic);
  261. }
  262. public static void CreateElementInTag(this XmlDocument doc, string parentPath, string tagName,
  263. Dictionary<string, string> attributeDic)
  264. {
  265. XmlNode parentNode = doc.SelectSingleNode(parentPath);
  266. if (parentNode == null)
  267. {
  268. return;
  269. }
  270. foreach (XmlNode childNode in parentNode.ChildNodes)
  271. {
  272. if (childNode.NodeType == XmlNodeType.Element)
  273. {
  274. if (FilterCheck((XmlElement)childNode, attributeDic))
  275. return;
  276. }
  277. }
  278. XmlElement newElement = doc.CreateElement(tagName);
  279. UpdateOrCreateAttribute(newElement, attributeDic);
  280. parentNode.AppendChild(newElement);
  281. }
  282. private static bool FilterCheck(XmlElement element, Dictionary<string, string> filterDic)
  283. {
  284. foreach (var filterCase in filterDic)
  285. {
  286. string caseValue = element.GetAttribute(filterCase.Key, androidURI);
  287. if (String.IsNullOrEmpty(caseValue) || caseValue != filterCase.Value)
  288. return false;
  289. }
  290. return true;
  291. }
  292. private static void UpdateOrCreateAttribute(XmlElement element, Dictionary<string, string> attributeDic)
  293. {
  294. foreach (var attributeItem in attributeDic)
  295. {
  296. element.SetAttribute(attributeItem.Key, androidURI, attributeItem.Value);
  297. }
  298. }
  299. public static PXR_Settings GetSettings()
  300. {
  301. PXR_Settings settings = null;
  302. #if UNITY_EDITOR
  303. UnityEditor.EditorBuildSettings.TryGetConfigObject<PXR_Settings>("Unity.XR.PXR.Settings", out settings);
  304. #endif
  305. #if UNITY_ANDROID && !UNITY_EDITOR
  306. settings = PXR_Settings.settings;
  307. #endif
  308. return settings;
  309. }
  310. }
  311. }
粤ICP备19079148号