270 lines
12 KiB
C#
270 lines
12 KiB
C#
// Microsoft
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Xml;
|
|
|
|
// Unity
|
|
using UnityEditor.Android;
|
|
|
|
// GUPS - AntiCheat
|
|
using GUPS.AntiCheat.Settings;
|
|
|
|
namespace GUPS.AntiCheat.Editor.Build
|
|
{
|
|
/// <summary>
|
|
/// Handles post-processing of the Gradle Android project after it is generated by Unity.
|
|
/// Implements the <see cref="IPostGenerateGradleAndroidProject"/> interface.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This class modifies the AndroidManifest.xml file of the generated Gradle project by adding
|
|
/// specific `<package>` elements under the `<queries>` section to ensure compatibility with Android's
|
|
/// runtime permissions model.
|
|
/// </remarks>
|
|
internal class PostProcessAndroidBuild : IPostGenerateGradleAndroidProject
|
|
{
|
|
/// <summary>
|
|
/// Gets the callback order of this postprocessor.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The callback order is set to a high value (<see cref="Int32.MaxValue"/> - 1) to ensure
|
|
/// that this postprocessor is executed near the very end of the post-processing pipeline.
|
|
/// This allows it to modify the AndroidManifest.xml as the final step without overwriting
|
|
/// changes made by other postprocessors.
|
|
/// </remarks>
|
|
public int callbackOrder => Int32.MaxValue - 1;
|
|
|
|
/// <summary>
|
|
/// Retrieves the path to the `AndroidManifest.xml` file within the generated Gradle project.
|
|
/// </summary>
|
|
/// <param name="_BasePath">The base path of the Gradle project.</param>
|
|
/// <returns>The full file path to the `AndroidManifest.xml` file.</returns>
|
|
/// <remarks>
|
|
/// The method constructs the path by combining the base path with the relative path to the manifest file,
|
|
/// which is typically located in `src/main/AndroidManifest.xml`.
|
|
/// </remarks>
|
|
private String GetManifestPath(String _BasePath)
|
|
{
|
|
return Path.Combine(_BasePath, "src", "main", "AndroidManifest.xml");
|
|
}
|
|
|
|
/// <summary>
|
|
/// Processes the generated Gradle Android project after it is created by Unity.
|
|
/// </summary>
|
|
/// <param name="_BasePath">The base path of the generated Gradle project.</param>
|
|
/// <remarks>
|
|
/// This method performs the following steps:
|
|
/// <list type="number">
|
|
/// <item>Locates the `AndroidManifest.xml` file in the Gradle project.</item>
|
|
/// <item>Loads the manifest using the <see cref="AndroidManifest"/> class.</item>
|
|
/// <item>Adds `<package>` elements under the `<queries>` section for applications specified in the global settings.</item>
|
|
/// <item>Saves the updated manifest back to the file system.</item>
|
|
/// </list>
|
|
/// </remarks>
|
|
public void OnPostGenerateGradleAndroidProject(String _BasePath)
|
|
{
|
|
#if UNITY_ANDROID
|
|
|
|
// Get the path to the AndroidManifest.xml file.
|
|
String var_ManifestPath = this.GetManifestPath(_BasePath);
|
|
|
|
// Load the AndroidManifest.xml file.
|
|
AndroidManifest var_Manifest = new AndroidManifest(var_ManifestPath);
|
|
|
|
// Add the packages into the AndroidManifest.xml file.
|
|
List<String> var_AppPackages = this.GetAppPackagesToFind();
|
|
|
|
for (int i = 0; i < var_AppPackages.Count; i++)
|
|
{
|
|
var_Manifest.AddQueryPackage(var_AppPackages[i]);
|
|
}
|
|
|
|
// Save the changes to the AndroidManifest.xml file.
|
|
var_Manifest.Save();
|
|
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieves the list of application package names to add to the `<queries>` section of the manifest.
|
|
/// </summary>
|
|
/// <returns>A list of application package names, or an empty list if no global settings are available.</returns>
|
|
/// <remarks>
|
|
/// The list of applications is determined by accessing the global settings instance and retrieving
|
|
/// the `Android_BlacklistedApplications` property. If the global settings are unavailable, an empty
|
|
/// list is returned.
|
|
/// </remarks>
|
|
private List<String> GetAppPackagesToFind()
|
|
{
|
|
return GlobalSettings.Instance?.Android_BlacklistedApplications ?? new List<String>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an Android XML document that handles Android-specific XML namespace and file operations.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This class extends XmlDocument to provide specialized functionality for working with Android XML files,
|
|
/// including proper namespace management and file handling.
|
|
/// </remarks>
|
|
internal class AndroidXmlDocument : XmlDocument
|
|
{
|
|
/// <summary>
|
|
/// The file path of the Android XML document.
|
|
/// </summary>
|
|
private String filePath;
|
|
|
|
/// <summary>
|
|
/// The namespace manager for handling XML namespaces in the document.
|
|
/// </summary>
|
|
protected XmlNamespaceManager namespaceManager;
|
|
|
|
/// <summary>
|
|
/// The standard Android XML namespace URI.
|
|
/// </summary>
|
|
public readonly String AndroidXmlNamespace = "http://schemas.android.com/apk/res/android";
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the AndroidXmlDocument class.
|
|
/// </summary>
|
|
/// <param name="_Path">The file path of the Android XML document to load.</param>
|
|
/// <remarks>
|
|
/// Loads the XML document from the specified path and initializes the namespace manager
|
|
/// with the Android XML namespace.
|
|
/// </remarks>
|
|
public AndroidXmlDocument(String _Path)
|
|
{
|
|
this.filePath = _Path;
|
|
using (var var_Reader = new XmlTextReader(this.filePath))
|
|
{
|
|
var_Reader.Read();
|
|
this.Load(var_Reader);
|
|
}
|
|
this.namespaceManager = new XmlNamespaceManager(this.NameTable);
|
|
this.namespaceManager.AddNamespace("android", this.AndroidXmlNamespace);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the XML document to its original file path.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Uses the file path specified during initialization to save the document.
|
|
/// </remarks>
|
|
public void Save()
|
|
{
|
|
this.SaveAt(this.filePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Saves the XML document to a specified file path.
|
|
/// </summary>
|
|
/// <param name="_Path">The file path where the XML document should be saved.</param>
|
|
/// <remarks>
|
|
/// Saves the document with proper formatting and UTF-8 encoding without BOM (Byte Order Mark).
|
|
/// </remarks>
|
|
public void SaveAt(String _Path)
|
|
{
|
|
using (var var_Writer = new XmlTextWriter(_Path, new UTF8Encoding(false)))
|
|
{
|
|
var_Writer.Formatting = Formatting.Indented;
|
|
this.Save(var_Writer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an AndroidManifest.xml document and provides methods for common operations
|
|
/// such as adding permissions or query packages.
|
|
/// Inherits from <see cref="AndroidXmlDocument"/>.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This class simplifies the management of AndroidManifest.xml files by providing methods
|
|
/// to manipulate key elements, such as `<uses-permission>` and `<queries>`.
|
|
/// </remarks>
|
|
internal class AndroidManifest : AndroidXmlDocument
|
|
{
|
|
/// <summary>
|
|
/// The root `<manifest>` element of the AndroidManifest.xml document.
|
|
/// </summary>
|
|
private readonly XmlElement ManifestElement;
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="AndroidManifest"/> class.
|
|
/// </summary>
|
|
/// <param name="_Path">The file path of the AndroidManifest.xml document to load.</param>
|
|
/// <remarks>
|
|
/// The constructor loads the AndroidManifest.xml file and initializes the root `<manifest>` element for further manipulation.
|
|
/// </remarks>
|
|
public AndroidManifest(String _Path) : base(_Path)
|
|
{
|
|
// Select the root <manifest> element.
|
|
this.ManifestElement = this.SelectSingleNode("/manifest") as XmlElement;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates an Android-specific XML attribute with the specified key and value.
|
|
/// </summary>
|
|
/// <param name="key">The key of the Android attribute (e.g., "name").</param>
|
|
/// <param name="value">The value of the attribute.</param>
|
|
/// <returns>A new <see cref="XmlAttribute"/> instance representing the Android attribute.</returns>
|
|
/// <remarks>
|
|
/// This method simplifies the creation of namespaced attributes for the Android XML namespace.
|
|
/// </remarks>
|
|
private XmlAttribute CreateAndroidAttribute(String key, String value)
|
|
{
|
|
// Create an attribute in the Android namespace.
|
|
XmlAttribute attr = CreateAttribute("android", key, this.AndroidXmlNamespace);
|
|
attr.Value = value;
|
|
return attr;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a `<uses-permission>` element to the AndroidManifest.xml document.
|
|
/// </summary>
|
|
/// <param name="_Permission">The name of the permission to add (e.g., "android.permission.INTERNET").</param>
|
|
/// <remarks>
|
|
/// This method appends a `<uses-permission>` element with the specified permission to the root `<manifest>` element.
|
|
/// </remarks>
|
|
public void AddUsesPermission(String _Permission)
|
|
{
|
|
// Create a <uses-permission> element.
|
|
XmlElement child = this.CreateElement("uses-permission");
|
|
this.ManifestElement.AppendChild(child);
|
|
|
|
// Create and append the "android:name" attribute.
|
|
XmlAttribute newAttribute = this.CreateAndroidAttribute("name", _Permission);
|
|
child.Attributes.Append(newAttribute);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds a `<package>` element under the `<queries>` section in the AndroidManifest.xml document.
|
|
/// </summary>
|
|
/// <param name="_Name">The name of the package to add (e.g., "com.example.app").</param>
|
|
/// <remarks>
|
|
/// This method ensures that a `<queries>` element exists in the manifest and appends a `<package>` element
|
|
/// with the specified package name to it.
|
|
/// </remarks>
|
|
public void AddQueryPackage(String _Name)
|
|
{
|
|
// Retrieve or create the <queries> element.
|
|
XmlElement queryPackageElement = this.ManifestElement.SelectSingleNode("queries") as XmlElement;
|
|
|
|
if (queryPackageElement == null)
|
|
{
|
|
// If <queries> does not exist, create it.
|
|
queryPackageElement = this.CreateElement("queries");
|
|
this.ManifestElement.AppendChild(queryPackageElement);
|
|
}
|
|
|
|
// Create the <package> element.
|
|
XmlElement packageElement = this.CreateElement("package");
|
|
queryPackageElement.AppendChild(packageElement);
|
|
|
|
// Create and append the "android:name" attribute.
|
|
XmlAttribute newAttribute = this.CreateAndroidAttribute("name", _Name);
|
|
packageElement.Attributes.Append(newAttribute);
|
|
}
|
|
}
|
|
}
|
|
}
|