ATPostProcessBuildAndroid.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. #if UNITY_ANDROID && UNITY_2018_2_OR_NEWER
  2. using AnyThink.Scripts.IntegrationManager.Editor;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Xml.Linq;
  8. using UnityEditor;
  9. using UnityEditor.Android;
  10. namespace AnyThink.Scripts.Editor
  11. {
  12. public class ATPostProcessBuildAndroid: IPostGenerateGradleAndroidProject
  13. {
  14. #if UNITY_2019_3_OR_NEWER
  15. private static string PropertyAndroidX = "android.useAndroidX";
  16. private static string PropertyJetifier = "android.enableJetifier";
  17. private static string EnableProperty = "=true";
  18. #endif
  19. private static string PropertyDexingArtifactTransform = "android.enableDexingArtifactTransform";
  20. private static string DisableProperty = "=false";
  21. private static string KeyMetaDataGoogleApplicationId = "com.google.android.gms.ads.APPLICATION_ID";
  22. private static string KeyMetaDataGoogleAdManagerApp = "com.google.android.gms.ads.AD_MANAGER_APP";
  23. private static readonly XNamespace AndroidNamespace = "http://schemas.android.com/apk/res/android";
  24. private static readonly XNamespace ToolsNamespace = "http://schemas.android.com/tools";
  25. public void OnPostGenerateGradleAndroidProject(string path)
  26. {
  27. ATLog.log("OnPostGenerateGradleAndroidProject() >>> path: " + path);
  28. #if UNITY_2019_3_OR_NEWER
  29. var gradlePropertiesPath = Path.Combine(path, "../gradle.properties");
  30. #else
  31. var gradlePropertiesPath = Path.Combine(path, "gradle.properties");
  32. #endif
  33. if (!ATConfig.isDefaultAndroidX()) {
  34. processGradleProperties(gradlePropertiesPath);
  35. }
  36. processAndroidManifest(path);
  37. processNetworkConfigXml(path);
  38. ATProcessBuildGradleAndroid.processBuildGradle(path);
  39. }
  40. public int callbackOrder
  41. {
  42. get { return int.MaxValue; }
  43. }
  44. private static void processGradleProperties(string gradlePropertiesPath)
  45. {
  46. ATLog.log("OnPostGenerateGradleAndroidProject() >>> gradlePropertiesPath: " + gradlePropertiesPath + " File.Exists(gradlePropertiesPath): " + File.Exists(gradlePropertiesPath));
  47. bool isChina = ATConfig.isSelectedChina();
  48. var gradlePropertiesUpdated = new List<string>();
  49. // If the gradle properties file already exists, make sure to add any previous properties.
  50. if (File.Exists(gradlePropertiesPath))
  51. {
  52. var lines = File.ReadAllLines(gradlePropertiesPath);
  53. #if UNITY_2019_3_OR_NEWER
  54. // Add all properties except AndroidX, Jetifier, and DexingArtifactTransform since they may already exist. We will re-add them below.
  55. gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyAndroidX) && !line.Contains(PropertyJetifier) && !line.Contains(PropertyDexingArtifactTransform)));
  56. #else
  57. // Add all properties except DexingArtifactTransform since it may already exist. We will re-add it below.
  58. gradlePropertiesUpdated.AddRange(lines.Where(line => !line.Contains(PropertyDexingArtifactTransform)));
  59. #endif
  60. }
  61. #if UNITY_2019_3_OR_NEWER
  62. //如果是国内,则根据选择来决定是否用AndroidX
  63. if (isChina)
  64. {
  65. if (!ATConfig.enableAndroidX()) {
  66. EnableProperty = "=false";
  67. } else {
  68. EnableProperty = "=true";
  69. }
  70. } else {
  71. EnableProperty = "=true";
  72. }
  73. ATLog.log("[AnyThink] AndroidX EnableProperty" + EnableProperty);
  74. // Enable AndroidX and Jetifier properties
  75. gradlePropertiesUpdated.Add(PropertyAndroidX + EnableProperty);
  76. gradlePropertiesUpdated.Add(PropertyJetifier + EnableProperty);
  77. #endif
  78. // Disable dexing using artifact transform (it causes issues for ExoPlayer with Gradle plugin 3.5.0+)
  79. gradlePropertiesUpdated.Add(PropertyDexingArtifactTransform + DisableProperty);
  80. try
  81. {
  82. File.WriteAllText(gradlePropertiesPath, string.Join("\n", gradlePropertiesUpdated.ToArray()) + "\n");
  83. }
  84. catch (Exception exception)
  85. {
  86. ATLog.logError("Failed to enable AndroidX and Jetifier. gradle.properties file write failed.");
  87. Console.WriteLine(exception);
  88. }
  89. }
  90. private static void processAndroidManifest(string path)
  91. {
  92. #if UNITY_2019_3_OR_NEWER
  93. var manifestPath = Path.Combine(path, "src/main/AndroidManifest.xml");
  94. #else
  95. var manifestPath = Path.Combine(path, "unityLibrary/src/main/AndroidManifest.xml");
  96. #endif
  97. // var manifestPath = Path.Combine(path, "src/main/AndroidManifest.xml");
  98. XDocument manifest;
  99. try
  100. {
  101. manifest = XDocument.Load(manifestPath);
  102. }
  103. #pragma warning disable 0168
  104. catch (IOException exception)
  105. #pragma warning restore 0168
  106. {
  107. ATLog.log("[AnyThink] AndroidManifest.xml is missing.");
  108. return;
  109. }
  110. // Get the `manifest` element.
  111. var elementManifest = manifest.Element("manifest");
  112. if (elementManifest == null)
  113. {
  114. ATLog.log("[AnyThink] AndroidManifest.xml is invalid.");
  115. return;
  116. }
  117. var elementApplication = elementManifest.Element("application");
  118. if (elementApplication == null)
  119. {
  120. ATLog.log("[AnyThink] AndroidManifest.xml is invalid.");
  121. return;
  122. }
  123. var metaDataElements = elementApplication.Descendants().Where(element => element.Name.LocalName.Equals("meta-data"));
  124. addGoogleApplicationIdIfNeeded(elementApplication, metaDataElements);
  125. // Save the updated manifest file.
  126. manifest.Save(manifestPath);
  127. }
  128. private static void addGoogleApplicationIdIfNeeded(XElement elementApplication, IEnumerable<XElement> metaDataElements)
  129. {
  130. var googleApplicationIdMetaData = GetElementByName(metaDataElements, KeyMetaDataGoogleApplicationId);
  131. if (!ATConfig.isNetworkInstalledByName("Admob", ATConfig.OS_ANDROID))
  132. {
  133. ATLog.log("addGoogleApplicationIdIfNeeded() >>> Admob not install.");
  134. if (googleApplicationIdMetaData != null) googleApplicationIdMetaData.Remove();
  135. return;
  136. }
  137. var appId = ATConfig.getAdmobAppIdByOs(ATConfig.OS_ANDROID);
  138. // Log error if the App ID is not set.
  139. if (string.IsNullOrEmpty(appId) || !appId.StartsWith("ca-app-pub-"))
  140. {
  141. ATLog.logError("AdMob App ID is not set. Please enter a valid app ID within the AnyThink Integration Manager window.");
  142. return;
  143. }
  144. // Check if the Google App ID meta data already exists. Update if it already exists.
  145. if (googleApplicationIdMetaData != null)
  146. {
  147. googleApplicationIdMetaData.SetAttributeValue(AndroidNamespace + "value", appId);
  148. }
  149. // Meta data doesn't exist, add it.
  150. else
  151. {
  152. elementApplication.Add(CreateMetaDataElement(KeyMetaDataGoogleApplicationId, appId));
  153. }
  154. }
  155. /// <summary>
  156. /// Looks through all the given meta-data elements to check if the required one exists. Returns <c>null</c> if it doesn't exist.
  157. /// </summary>
  158. private static XElement GetElementByName(IEnumerable<XElement> elements, string name)
  159. {
  160. foreach (var element in elements)
  161. {
  162. var attributes = element.Attributes();
  163. if (attributes.Any(attribute => attribute.Name.Namespace.Equals(AndroidNamespace)
  164. && attribute.Name.LocalName.Equals("name")
  165. && attribute.Value.Equals(name)))
  166. {
  167. return element;
  168. }
  169. }
  170. return null;
  171. }
  172. /// <summary>
  173. /// Creates and returns a <c>meta-data</c> element with the given name and value.
  174. /// </summary>
  175. private static XElement CreateMetaDataElement(string name, object value)
  176. {
  177. var metaData = new XElement("meta-data");
  178. metaData.Add(new XAttribute(AndroidNamespace + "name", name));
  179. metaData.Add(new XAttribute(AndroidNamespace + "value", value));
  180. return metaData;
  181. }
  182. private static void processNetworkConfigXml(string path)
  183. {
  184. bool isChina = ATConfig.isSelectedChina();
  185. // bool isChina = true;
  186. //在application标签加上:android:networkSecurityConfig="@xml/anythink_network_security_config"
  187. addNetworkSecurityConfigInApplication(path, isChina);
  188. #if UNITY_2019_3_OR_NEWER
  189. var resXmlPath = Path.Combine(path, "src/main/res/xml");
  190. #else
  191. var resXmlPath = Path.Combine(path, "unityLibrary/src/main/res/xml");
  192. #endif
  193. var rexXmlDir = Path.Combine(resXmlPath, "anythink_network_security_config.xml");
  194. if (File.Exists(rexXmlDir))
  195. {
  196. if (!isChina) //海外不用配置这个xml
  197. {
  198. FileUtil.DeleteFileOrDirectory(rexXmlDir);
  199. }
  200. return;
  201. }
  202. if (!Directory.Exists(resXmlPath))
  203. {
  204. Directory.CreateDirectory(resXmlPath);
  205. }
  206. saveFile("Assets/AnyThinkPlugin/Script/Editor/anythink_network_security_config.xml", resXmlPath);
  207. }
  208. public static void saveFile(string filePathName , string toFilesPath)
  209. {
  210. FileInfo file = new FileInfo(filePathName);
  211. string newFileName= file.Name;
  212. file.CopyTo(toFilesPath + "/" + newFileName, true);
  213. }
  214. private static void addNetworkSecurityConfigInApplication(string path, bool isChina)
  215. {
  216. #if UNITY_2019_3_OR_NEWER
  217. var manifestPath = Path.Combine(path, "src/main/AndroidManifest.xml");
  218. #else
  219. var manifestPath = Path.Combine(path, "unityLibrary/src/main/AndroidManifest.xml");
  220. #endif
  221. // var manifestPath = Path.Combine(path, "src/main/AndroidManifest.xml");
  222. XDocument manifest;
  223. try
  224. {
  225. manifest = XDocument.Load(manifestPath);
  226. }
  227. #pragma warning disable 0168
  228. catch (IOException exception)
  229. #pragma warning restore 0168
  230. {
  231. ATLog.log("[AnyThink] AndroidManifest.xml is missing.");
  232. return;
  233. }
  234. // Get the `manifest` element.
  235. var elementManifest = manifest.Element("manifest");
  236. if (elementManifest == null)
  237. {
  238. ATLog.log("[AnyThink] AndroidManifest.xml is invalid.");
  239. return;
  240. }
  241. var elementApplication = elementManifest.Element("application");
  242. if (elementApplication == null)
  243. {
  244. ATLog.log("[AnyThink] AndroidManifest.xml is invalid.");
  245. return;
  246. }
  247. //handle anythink_network_security_config.xml
  248. XAttribute networkConfigAttribute = elementApplication.Attribute(AndroidNamespace + "networkSecurityConfig");
  249. if (networkConfigAttribute != null) {
  250. networkConfigAttribute.Remove();
  251. }
  252. if (isChina)
  253. {
  254. elementApplication.Add(new XAttribute(AndroidNamespace + "networkSecurityConfig", "@xml/anythink_network_security_config"));
  255. }
  256. //这个设置主要是为了适配9.0以上的机器
  257. //<uses-library android:name="org.apache.http.legacy" android:required="false" />
  258. var usesLibraryElements = elementApplication.Descendants().Where(element => element.Name.LocalName.Equals("uses-library"));
  259. if (usesLibraryElements == null)
  260. {
  261. elementApplication.Add(createHttpLegacyElement());
  262. }
  263. else
  264. {
  265. XElement httpLegacyElement = GetElementByName(usesLibraryElements, "org.apache.http.legacy");
  266. if (httpLegacyElement == null)
  267. {
  268. elementApplication.Add(createHttpLegacyElement());
  269. }
  270. }
  271. manifest.Save(manifestPath);
  272. }
  273. public static XElement createHttpLegacyElement()
  274. {
  275. var httpFeautre = new XElement("uses-library");
  276. httpFeautre.Add(new XAttribute(AndroidNamespace + "name", "org.apache.http.legacy"));
  277. httpFeautre.Add(new XAttribute(AndroidNamespace + "required", "false"));
  278. return httpFeautre;
  279. }
  280. private static XElement CreateMetaDataElement(string name, object value, object toolsNode)
  281. {
  282. var metaData = new XElement("meta-data");
  283. metaData.Add(new XAttribute(AndroidNamespace + "name", name));
  284. metaData.Add(new XAttribute(AndroidNamespace + "value", value));
  285. metaData.Add(new XAttribute(ToolsNamespace + "node", toolsNode));
  286. return metaData;
  287. }
  288. }
  289. }
  290. #endif