Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 

237 righe
9.9 KiB

  1. using System.Xml;
  2. using System.Text;
  3. using System;
  4. using UnityEngine;
  5. internal class UniWebViewAndroidXmlDocument : XmlDocument {
  6. private readonly string path;
  7. protected readonly XmlNamespaceManager nameSpaceManager;
  8. protected const string AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
  9. protected UniWebViewAndroidXmlDocument(string path) {
  10. this.path = path;
  11. using (var reader = new XmlTextReader(path)) {
  12. reader.Read();
  13. Load(reader);
  14. }
  15. nameSpaceManager = new XmlNamespaceManager(NameTable);
  16. nameSpaceManager.AddNamespace("android", AndroidXmlNamespace);
  17. }
  18. public void Save() {
  19. SaveAs(path);
  20. }
  21. private void SaveAs(string path)
  22. {
  23. using var writer = new XmlTextWriter(path, new UTF8Encoding(false));
  24. writer.Formatting = Formatting.Indented;
  25. Save(writer);
  26. }
  27. }
  28. internal class UniWebViewAndroidManifest : UniWebViewAndroidXmlDocument {
  29. private readonly XmlElement manifestElement;
  30. private readonly XmlElement applicationElement;
  31. public UniWebViewAndroidManifest(string path) : base(path) {
  32. manifestElement = SelectSingleNode("/manifest") as XmlElement;
  33. applicationElement = SelectSingleNode("/manifest/application") as XmlElement;
  34. }
  35. private XmlAttribute CreateAndroidAttribute(string key, string value) {
  36. XmlAttribute attr = CreateAttribute("android", key, AndroidXmlNamespace);
  37. attr.Value = value;
  38. return attr;
  39. }
  40. internal XmlNode GetActivityWithLaunchIntent() {
  41. return
  42. SelectSingleNode(
  43. "/manifest/application/activity[intent-filter/action/@android:name='android.intent.action.MAIN' and "
  44. + "intent-filter/category/@android:name='android.intent.category.LAUNCHER']",
  45. nameSpaceManager);
  46. }
  47. internal bool SetUsesCleartextTraffic() {
  48. var changed = false;
  49. if (applicationElement.GetAttribute("usesCleartextTraffic", AndroidXmlNamespace) != "true") {
  50. applicationElement.SetAttribute("usesCleartextTraffic", AndroidXmlNamespace, "true");
  51. changed = true;
  52. }
  53. return changed;
  54. }
  55. internal bool SetHardwareAccelerated() {
  56. var changed = false;
  57. var activity = GetActivityWithLaunchIntent() as XmlElement;
  58. if (activity == null)
  59. {
  60. Debug.LogError(
  61. "There is no launch intent activity in the AndroidManifest.xml." +
  62. " Please check your AndroidManifest.xml file and make sure it has a main activity with intent filter");
  63. return false;
  64. }
  65. if (activity.GetAttribute("hardwareAccelerated", AndroidXmlNamespace) != "true") {
  66. activity.SetAttribute("hardwareAccelerated", AndroidXmlNamespace, "true");
  67. changed = true;
  68. }
  69. return changed;
  70. }
  71. internal bool AddCameraPermission() {
  72. var changed = false;
  73. var cameraPermission = "/manifest/uses-permission[@android:name='android.permission.CAMERA']";
  74. var cameraPermissionNode = SelectNodes(cameraPermission, nameSpaceManager);
  75. if (cameraPermissionNode == null || cameraPermissionNode.Count == 0) {
  76. var elem = CreateElement("uses-permission");
  77. elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.CAMERA"));
  78. manifestElement.AppendChild(elem);
  79. changed = true;
  80. }
  81. var hardwareCamera = "/manifest/uses-feature[@android:name='android.hardware.camera']";
  82. var hardwareCameraNode = SelectNodes(hardwareCamera, nameSpaceManager);
  83. if (hardwareCameraNode == null || hardwareCameraNode.Count == 0) {
  84. var elem = CreateElement("uses-feature");
  85. elem.Attributes.Append(CreateAndroidAttribute("name", "android.hardware.camera"));
  86. manifestElement.AppendChild(elem);
  87. changed = true;
  88. }
  89. return changed;
  90. }
  91. internal bool AddMicrophonePermission() {
  92. bool changed = false;
  93. var microphonePermission = "/manifest/uses-permission[@android:name='android.permission.MICROPHONE']";
  94. var microphonePermissionNode = SelectNodes(microphonePermission, nameSpaceManager);
  95. if (microphonePermissionNode == null || microphonePermissionNode.Count == 0) {
  96. var elem = CreateElement("uses-permission");
  97. elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.MICROPHONE"));
  98. manifestElement.AppendChild(elem);
  99. changed = true;
  100. }
  101. var microphoneHardware = "/manifest/uses-feature[@android:name='android.hardware.microphone']";
  102. var microphoneHardwareNode = SelectNodes(microphoneHardware, nameSpaceManager);
  103. if (microphoneHardwareNode == null || microphoneHardwareNode.Count == 0) {
  104. var elem = CreateElement("uses-feature");
  105. elem.Attributes.Append(CreateAndroidAttribute("name", "android.hardware.microphone"));
  106. manifestElement.AppendChild(elem);
  107. changed = true;
  108. }
  109. return changed;
  110. }
  111. internal bool AddReadExternalStoragePermission() {
  112. var changed = false;
  113. var externalPermission = "/manifest/uses-permission[@android:name='android.permission.READ_EXTERNAL_STORAGE']";
  114. var externalNode = SelectNodes(externalPermission, nameSpaceManager);
  115. if (externalNode == null || externalNode.Count == 0) {
  116. var elem = CreateElement("uses-permission");
  117. elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.READ_EXTERNAL_STORAGE"));
  118. manifestElement.AppendChild(elem);
  119. changed = true;
  120. }
  121. return changed;
  122. }
  123. internal bool AddWriteExternalStoragePermission() {
  124. var changed = false;
  125. var externalPermission = "/manifest/uses-permission[@android:name='android.permission.WRITE_EXTERNAL_STORAGE']";
  126. var externalNode = SelectNodes(externalPermission, nameSpaceManager);
  127. if (externalNode == null || externalNode.Count == 0) {
  128. var elem = CreateElement("uses-permission");
  129. elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.WRITE_EXTERNAL_STORAGE"));
  130. manifestElement.AppendChild(elem);
  131. changed = true;
  132. }
  133. return changed;
  134. }
  135. internal bool AddAccessFineLocationPermission() {
  136. var changed = false;
  137. var locationPermission = "/manifest/uses-permission[@android:name='android.permission.ACCESS_FINE_LOCATION']";
  138. var locationNode = SelectNodes(locationPermission, nameSpaceManager);
  139. if (locationNode == null || locationNode.Count == 0) {
  140. var elem = CreateElement("uses-permission");
  141. elem.Attributes.Append(CreateAndroidAttribute("name", "android.permission.ACCESS_FINE_LOCATION"));
  142. manifestElement.AppendChild(elem);
  143. changed = true;
  144. }
  145. return changed;
  146. }
  147. internal bool AddAuthCallbacksIntentFilter(string[] authCallbackUrls) {
  148. var changed = false;
  149. XmlElement authActivityNode;
  150. if (authCallbackUrls.Length > 0) {
  151. var authActivity = "/manifest/application/activity[@android:name='com.onevcat.uniwebview.UniWebViewAuthenticationActivity']";
  152. var list = SelectNodes(authActivity, nameSpaceManager);
  153. if (list == null || list.Count == 0) {
  154. var created = CreateElement("activity");
  155. created.SetAttribute("name", AndroidXmlNamespace, "com.onevcat.uniwebview.UniWebViewAuthenticationActivity");
  156. created.SetAttribute("exported", AndroidXmlNamespace, "true");
  157. created.SetAttribute("launchMode", AndroidXmlNamespace, "singleTask");
  158. created.SetAttribute("configChanges", AndroidXmlNamespace, "orientation|screenSize|keyboardHidden");
  159. authActivityNode = created;
  160. } else {
  161. authActivityNode = list[0] as XmlElement;
  162. }
  163. } else {
  164. return false;
  165. }
  166. foreach (var url in authCallbackUrls) {
  167. var intentFilter = CreateIntentFilter(url);
  168. if (intentFilter != null) {
  169. authActivityNode?.AppendChild(intentFilter);
  170. changed = true;
  171. }
  172. }
  173. if (authActivityNode != null) {
  174. applicationElement.AppendChild(authActivityNode);
  175. }
  176. return changed;
  177. }
  178. private XmlElement CreateIntentFilter(string url) {
  179. var uri = new Uri(url);
  180. var scheme = uri.Scheme;
  181. if (string.IsNullOrEmpty(scheme)) {
  182. Debug.LogError("<UniWebView> Auth callback url contains an empty scheme. Please check the url: " + url);
  183. return null;
  184. }
  185. var filter = CreateElement("intent-filter");
  186. var action = CreateElement("action");
  187. action.SetAttribute("name", AndroidXmlNamespace, "android.intent.action.VIEW");
  188. filter.AppendChild(action);
  189. var defaultCategory = CreateElement("category");
  190. defaultCategory.SetAttribute("name", AndroidXmlNamespace, "android.intent.category.DEFAULT");
  191. filter.AppendChild(defaultCategory);
  192. var browseCategory = CreateElement("category");
  193. browseCategory.SetAttribute("name", AndroidXmlNamespace, "android.intent.category.BROWSABLE");
  194. filter.AppendChild(browseCategory);
  195. var data = CreateElement("data");
  196. data.SetAttribute("scheme", AndroidXmlNamespace, scheme);
  197. if (!String.IsNullOrEmpty(uri.Host)) {
  198. data.SetAttribute("host", AndroidXmlNamespace, uri.Host);
  199. }
  200. if (uri.Port != -1) {
  201. data.SetAttribute("port", AndroidXmlNamespace, uri.Port.ToString());
  202. }
  203. if (!string.IsNullOrEmpty(uri.PathAndQuery) && uri.PathAndQuery != "/") {
  204. data.SetAttribute("path", AndroidXmlNamespace, uri.PathAndQuery);
  205. }
  206. filter.AppendChild(data);
  207. return filter;
  208. }
  209. }