PICOModifyAndroidManifest.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Xml;
  5. using UnityEditor.Build.Reporting;
  6. using UnityEditor.XR.OpenXR.Features;
  7. namespace Unity.XR.OpenXR.Features.PICOSupport
  8. {
  9. internal class PICOModifyAndroidManifest : OpenXRFeatureBuildHooks
  10. {
  11. public override int callbackOrder => 1;
  12. public override Type featureType => typeof(PICOFeature);
  13. protected override void OnPreprocessBuildExt(BuildReport report) { }
  14. protected override void OnPostGenerateGradleAndroidProjectExt(string path)
  15. {
  16. var androidManifest = new AndroidManifest(GetManifestPath(path));
  17. androidManifest.AddPICOMetaData(path);
  18. androidManifest.Save();
  19. }
  20. protected override void OnPostprocessBuildExt(BuildReport report) { }
  21. private string _manifestFilePath;
  22. private string GetManifestPath(string basePath)
  23. {
  24. if (!string.IsNullOrEmpty(_manifestFilePath)) return _manifestFilePath;
  25. var pathBuilder = new StringBuilder(basePath);
  26. pathBuilder.Append(Path.DirectorySeparatorChar).Append("src");
  27. pathBuilder.Append(Path.DirectorySeparatorChar).Append("main");
  28. pathBuilder.Append(Path.DirectorySeparatorChar).Append("AndroidManifest.xml");
  29. _manifestFilePath = pathBuilder.ToString();
  30. return _manifestFilePath;
  31. }
  32. private class AndroidXmlDocument : XmlDocument
  33. {
  34. private string m_Path;
  35. protected XmlNamespaceManager nsMgr;
  36. public readonly string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
  37. public AndroidXmlDocument(string path)
  38. {
  39. m_Path = path;
  40. using (var reader = new XmlTextReader(m_Path))
  41. {
  42. reader.Read();
  43. Load(reader);
  44. }
  45. nsMgr = new XmlNamespaceManager(NameTable);
  46. nsMgr.AddNamespace("android", AndroidXmlNamespace);
  47. }
  48. public string Save()
  49. {
  50. return SaveAs(m_Path);
  51. }
  52. public string SaveAs(string path)
  53. {
  54. using (var writer = new XmlTextWriter(path, new UTF8Encoding(false)))
  55. {
  56. writer.Formatting = Formatting.Indented;
  57. Save(writer);
  58. }
  59. return path;
  60. }
  61. }
  62. private class AndroidManifest : AndroidXmlDocument
  63. {
  64. private readonly XmlElement ApplicationElement;
  65. private readonly XmlElement ManifestElement;
  66. public AndroidManifest(string path) : base(path)
  67. {
  68. ManifestElement = SelectSingleNode("/manifest") as XmlElement;
  69. ApplicationElement = SelectSingleNode("/manifest/application") as XmlElement;
  70. }
  71. private XmlAttribute CreateOrUpdateAndroidAttribute(string key, string value)
  72. {
  73. XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
  74. attr.Value = value;
  75. return attr;
  76. }
  77. private void CreateOrUpdateAndroidPermissionData(string name)
  78. {
  79. XmlNodeList nodeList = ManifestElement.SelectNodes("uses-permission");
  80. foreach (XmlNode node in nodeList)
  81. {
  82. if (node != null)
  83. {
  84. // Update existing nodes
  85. if (node.Attributes != null && name.Equals(node.Attributes[0].Value))
  86. {
  87. return;
  88. }
  89. }
  90. }
  91. // Create new node
  92. var md = ManifestElement.AppendChild(CreateElement("uses-permission"));
  93. md.Attributes.Append(CreateOrUpdateAndroidAttribute("name", name.ToString()));
  94. }
  95. private void DeleteAndroidPermissionData(string name)
  96. {
  97. XmlNodeList nodeList = ManifestElement.SelectNodes("uses-permission");
  98. foreach (XmlNode node in nodeList)
  99. {
  100. if (node != null)
  101. {
  102. // Delete existing nodes
  103. if (node.Attributes != null && name.Equals(node.Attributes[0].Value))
  104. {
  105. node.ParentNode?.RemoveChild(node);
  106. return;
  107. }
  108. }
  109. }
  110. }
  111. private void CreateOrUpdateAndroidMetaData(string name, string value)
  112. {
  113. XmlNodeList nodeList = ApplicationElement.SelectNodes("meta-data");
  114. foreach (XmlNode node in nodeList)
  115. {
  116. if (node != null)
  117. {
  118. // Update existing nodes
  119. if (node.Attributes != null && name.Equals(node.Attributes[0].Value))
  120. {
  121. node.Attributes[0].Value = name;
  122. node.Attributes[1].Value = value;
  123. return;
  124. }
  125. }
  126. }
  127. // Create new node
  128. var md = ApplicationElement.AppendChild(CreateElement("meta-data"));
  129. md.Attributes.Append(CreateOrUpdateAndroidAttribute("name", name.ToString()));
  130. md.Attributes.Append(CreateOrUpdateAndroidAttribute("value", value.ToString()));
  131. }
  132. private void DeleteAndroidMetaData(string name)
  133. {
  134. XmlNodeList nodeList = ApplicationElement.SelectNodes("meta-data");
  135. foreach (XmlNode node in nodeList)
  136. {
  137. if (node != null)
  138. {
  139. // Delete existing nodes
  140. if (node.Attributes != null && name.Equals(node.Attributes[0].Value))
  141. {
  142. node.ParentNode?.RemoveChild(node);
  143. return;
  144. }
  145. }
  146. }
  147. }
  148. internal void AddPICOMetaData(string path)
  149. {
  150. CreateOrUpdateAndroidMetaData("pvr.app.type", "vr");
  151. CreateOrUpdateAndroidMetaData("pvr.sdk.version", PICOFeature.SDKVersion);
  152. CreateOrUpdateAndroidMetaData("pxr.sdk.version_code", "5800");
  153. if (PICOProjectSetting.GetProjectConfig().isEyeTracking)
  154. {
  155. CreateOrUpdateAndroidPermissionData("com.picovr.permission.EYE_TRACKING");
  156. CreateOrUpdateAndroidMetaData("picovr.software.eye_tracking", "1");
  157. CreateOrUpdateAndroidMetaData("eyetracking_calibration", PICOProjectSetting.GetProjectConfig().isEyeTrackingCalibration ? "true" : "false");
  158. }
  159. else
  160. {
  161. DeleteAndroidPermissionData("com.picovr.permission.EYE_TRACKING");
  162. DeleteAndroidMetaData("picovr.software.eye_tracking");
  163. DeleteAndroidMetaData("eyetracking_calibration");
  164. }
  165. CreateOrUpdateAndroidMetaData("handtracking", PICOProjectSetting.GetProjectConfig().isHandTracking ? "1" : "0");
  166. CreateOrUpdateAndroidMetaData("pvr.app.splash", PICOProjectSetting.GetProjectConfig().GetSystemSplashScreen(path));
  167. }
  168. }
  169. }
  170. }