Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,8 @@ build/
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta

# Auto-generated scenes by play mode tests
/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity*
/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity*

/unity-application-patcher
*.so
*BurstDebugInformation_DoNotShip
177 changes: 177 additions & 0 deletions Assets/Editor/BuildLibunity.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Net.Http;
using System.Runtime.InteropServices;
using System;
using System.Diagnostics;
using System.Security.Permissions;
using System.IO.Compression;

public class BuildLibunity : MonoBehaviour
{
#pragma warning disable
static readonly string PATCHER_WINDOWS_X64 = "https://security-patches.unity.com/bc0977e0-21a9-4f6e-9414-4f44b242110a/unity-patcher/UnityApplicationPatcher-1.3.3-Win.zip";
static readonly string PATCHER_MAC_X64 = "https://security-patches.unity.com/bc0977e0-21a9-4f6e-9414-4f44b242110a/unity-patcher/UnityApplicationPatcher-1.3.3-macOS-x64.zip";
static readonly string PATCHER_MAC_ARM64 = "https://security-patches.unity.com/bc0977e0-21a9-4f6e-9414-4f44b242110a/unity-patcher/UnityApplicationPatcher-1.3.3-macOS-Arm64.zip";
static readonly string PATCHER_LINUX_X64 = "https://security-patches.unity.com/bc0977e0-21a9-4f6e-9414-4f44b242110a/unity-patcher/UnityApplicationPatcher-1.3.3-Linux.zip";

static void MakeExecutable(string file)
{
try
{
var proc = new Process();
proc.StartInfo.FileName = "chmod";
proc.StartInfo.Arguments = $"+x '{file}'";
proc.StartInfo.UseShellExecute = true;
proc.Start();
proc.WaitForExit();
}
catch(Exception e)
{
UnityEngine.Debug.LogError($"Failed to make '{file}' executable " + e.ToString());
EditorUtility.ClearProgressBar();
return;
}
}

public static void ExtractWithExecutableBits(string zipPath, string destinationDir, Action<int, int> onExtract)
{
using (ZipArchive archive = ZipFile.OpenRead(zipPath))
{
int fileCount = archive.Entries.Count;
int extracted = 0;
onExtract(0, fileCount);
foreach (ZipArchiveEntry entry in archive.Entries)
{
string destinationPath = Path.GetFullPath(Path.Combine(destinationDir, entry.FullName));

if (entry.FullName.EndsWith("/"))
{
Directory.CreateDirectory(destinationPath);
continue;
}

Directory.CreateDirectory(Path.GetDirectoryName(destinationPath)!);

entry.ExtractToFile(destinationPath, overwrite: true);

int externalAttributes = entry.ExternalAttributes;
int unixMode = externalAttributes >> 16;

if (unixMode != 0)
{
// Check if any executable bit is set (User, Group, or Others)
bool isExecutable = (unixMode & 0b001_001_001) != 0;

if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) || RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
MakeExecutable(destinationPath);
}
}

extracted += 1;
onExtract(extracted, fileCount);
}
}
}

static string? GetPatcherURL()
{
if(RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) return PATCHER_WINDOWS_X64;
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) return PATCHER_LINUX_X64;
if(RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
if(RuntimeInformation.ProcessArchitecture == Architecture.Arm64) return PATCHER_MAC_ARM64;
if(RuntimeInformation.ProcessArchitecture == Architecture.X64) return PATCHER_MAC_X64;
}
return null;
}

[MenuItem("Jobs/Build libunity.so")]
static async void Build()
{
var apkOutputFile = Path.Join(Application.dataPath, "..", "game.apk");
var options = new BuildPlayerOptions
{
locationPathName = apkOutputFile,
target = BuildTarget.Android,
options = BuildOptions.None,
};
var build = BuildPipeline.BuildPlayer(options);
if(build.summary.result != UnityEditor.Build.Reporting.BuildResult.Succeeded)
{
return;
}

var patcherDirectory = Path.Join(Application.dataPath, "..", "unity-application-patcher");
var executableName = "UnityApplicationPatcherCLI" + (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".exe" : "");
var patcherExecutable = Path.Join(patcherDirectory, executableName);
if(!File.Exists(patcherExecutable))
{
EditorUtility.DisplayProgressBar("Build libunity.so", "Downloading patcher tool", 0);
var client = new HttpClient();
var url = GetPatcherURL();
if(url == null)
{
EditorUtility.ClearProgressBar();
UnityEngine.Debug.LogError("Unsupported platform!");
return;
}
var response = await client.GetAsync(url);
if(response.StatusCode != System.Net.HttpStatusCode.OK)
{
UnityEngine.Debug.LogError($"Downloading patcher returned status code {((int)response.StatusCode)}");
return;
}
var archiveName = patcherDirectory + ".zip";
var buffer = new byte[1000000];
var stream = await response.Content.ReadAsStreamAsync();
int bytesRead = 0;
int totalBytesRead = 0;
var file = new FileStream(archiveName, FileMode.CreateNew);
while((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, default).ConfigureAwait(false)) != 0)
{
await file.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
EditorUtility.DisplayProgressBar("Build libunity.so", "Downloading patcher tool", totalBytesRead / (float)response.Content.Headers.ContentLength);
}
file.Close();
stream.Close();
ExtractWithExecutableBits(archiveName, patcherDirectory, (extracted, total) => EditorUtility.DisplayProgressBar("Build libunity.so", "Extracting patcher tool", (float)extracted / (float)total));
File.Delete(archiveName);
EditorUtility.ClearProgressBar();
}

EditorUtility.DisplayProgressBar("Build libunity.so", "Patching apk", .5f);
// zipalign fails to find libc++.so otherwise
System.Environment.SetEnvironmentVariable("LD_LIBRARY_PATH", Path.Join(patcherDirectory, "Data/StreamingAssets/Android/SDK/platform-tools/lib64"));
var process = new Process();
process.StartInfo.FileName = patcherExecutable;
process.StartInfo.UseShellExecute = true;
// versionCode 0 means ignore
process.StartInfo.Arguments = $"-android -versionCode 0 -applicationPath '{apkOutputFile}'";
EditorUtility.DisplayProgressBar("Build libunity.so", "Patching apk", .5f);
try
{
UnityEngine.Debug.Log(process.StartInfo.FileName);
UnityEngine.Debug.Log(process.StartInfo.Arguments);
process.Start();
process.WaitForExit();
UnityEngine.Debug.Log($"Process exited with code {process.ExitCode}");
}
catch(Exception e)
{
UnityEngine.Debug.LogError(e.ToString());
EditorUtility.ClearProgressBar();
}
EditorUtility.ClearProgressBar();

EditorUtility.DisplayProgressBar("Build libunity.so", "Extracting file from apk", .8f);
var apkExtractedFolder = Path.Join(Application.dataPath, "..", "game");
ZipFile.ExtractToDirectory(Path.Join(Application.dataPath, "..", "game.patched.apk"), apkExtractedFolder, true);
File.Copy(Path.Join(apkExtractedFolder, "lib/arm64-v8a/libunity.so"), Path.Join(Application.dataPath, "..", Application.unityVersion + ".so"), true);
Directory.Delete(apkExtractedFolder, true);
EditorUtility.ClearProgressBar();
}
}
2 changes: 2 additions & 0 deletions Assets/Editor/BuildLibunity.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

119 changes: 119 additions & 0 deletions Assets/link.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<linker>
<assembly fullname="UnityEngine.VRModule" preserve="all"/>
<assembly fullname="UnityEngine.WindModule" preserve="all"/>
<assembly fullname="UnityEngine.AudioModule" preserve="all"/>
<assembly fullname="Unity.Cecil" preserve="all"/>
<assembly fullname="Unity.Cecil.Pdb" preserve="all"/>
<assembly fullname="UnityEngine.UnityWebRequestWWWModule" preserve="all"/>
<assembly fullname="UnityEngine.AnimationModule" preserve="all"/>
<assembly fullname="UnityEngine.GraphicsStateCollectionSerializerModule" preserve="all"/>
<assembly fullname="UnityEngine.ImageConversionModule" preserve="all"/>
<assembly fullname="UnityEditor.UnityConnectModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityWebRequestAssetBundleModule" preserve="all"/>
<assembly fullname="UnityEngine.SpriteMaskModule" preserve="all"/>
<assembly fullname="UnityEngine.TilemapModule" preserve="all"/>
<assembly fullname="UnityEditor.TextCoreTextEngineModule" preserve="all"/>
<assembly fullname="UnityEngine.ARModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityTestProtocolModule" preserve="all"/>
<assembly fullname="UnityEngine.DSPGraphModule" preserve="all"/>
<assembly fullname="UnityEngine.ParticleSystemModule" preserve="all"/>
<assembly fullname="UnityEditor.AdaptivePerformanceModule" preserve="all"/>
<assembly fullname="UnityEngine.VehiclesModule" preserve="all"/>
<assembly fullname="UnityEngine.UmbraModule" preserve="all"/>
<assembly fullname="UnityEngine.ClothModule" preserve="all"/>
<assembly fullname="UnityEditor.TextCoreFontEngineModule" preserve="all"/>
<assembly fullname="UnityEditor.CoreModule" preserve="all"/>
<assembly fullname="UnityEditor" preserve="all"/>
<assembly fullname="UnityEditor.MultiplayerModule" preserve="all"/>
<assembly fullname="UnityEngine.JSONSerializeModule" preserve="all"/>
<assembly fullname="UnityEditor.SpriteShapeModule" preserve="all"/>
<assembly fullname="UnityEngine.Physics2DModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityWebRequestTextureModule" preserve="all"/>
<assembly fullname="UnityEditor.GraphViewModule" preserve="all"/>
<assembly fullname="UnityEngine.AMDModule" preserve="all"/>
<assembly fullname="UnityEditor.DiagnosticsModule" preserve="all"/>
<assembly fullname="UnityEditor.SafeModeModule" preserve="all"/>
<assembly fullname="UnityEngine.UIModule" preserve="all"/>
<assembly fullname="UnityEngine.SharedInternalsModule" preserve="all"/>
<assembly fullname="UnityEditor.TerrainModule" preserve="all"/>
<assembly fullname="UnityEditor.GraphicsStateCollectionSerializerModule" preserve="all"/>
<assembly fullname="UnityEditor.Physics2DModule" preserve="all"/>
<assembly fullname="UnityEngine.SubstanceModule" preserve="all"/>
<assembly fullname="UnityEditor.GIModule" preserve="all"/>
<assembly fullname="UnityEngine.DirectorModule" preserve="all"/>
<assembly fullname="UnityEditor.BuildProfileModule" preserve="all"/>
<assembly fullname="UnityEngine.ScreenCaptureModule" preserve="all"/>
<assembly fullname="UnityEditor.UIElementsSamplesModule" preserve="all"/>
<assembly fullname="UnityEngine.ClusterInputModule" preserve="all"/>
<assembly fullname="UnityEngine.VFXModule" preserve="all"/>
<assembly fullname="UnityEngine.TextCoreTextEngineModule" preserve="all"/>
<assembly fullname="UnityEngine.VirtualTexturingModule" preserve="all"/>
<assembly fullname="UnityEditor.QuickSearchModule" preserve="all"/>
<assembly fullname="UnityEngine.GameCenterModule" preserve="all"/>
<assembly fullname="UnityEngine.TerrainModule" preserve="all"/>
<assembly fullname="UnityEngine.MarshallingModule" preserve="all"/>
<assembly fullname="UnityEditor.PresetsUIModule" preserve="all"/>
<assembly fullname="UnityEngine.HotReloadModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityConnectModule" preserve="all"/>
<assembly fullname="UnityEditor.SubstanceModule" preserve="all"/>
<assembly fullname="UnityEditor.DeviceSimulatorModule" preserve="all"/>
<assembly fullname="UnityEngine.StreamingModule" preserve="all"/>
<assembly fullname="UnityEngine.SpriteShapeModule" preserve="all"/>
<assembly fullname="UnityEditor.GridModule" preserve="all"/>
<assembly fullname="UnityEngine.PhysicsModule" preserve="all"/>
<assembly fullname="UnityEngine.CoreModule" preserve="all"/>
<assembly fullname="UnityEngine.CrashReportingModule" preserve="all"/>
<assembly fullname="UnityEngine.SubsystemsModule" preserve="all"/>
<assembly fullname="UnityEngine.TerrainPhysicsModule" preserve="all"/>
<assembly fullname="UnityEngine.PropertiesModule" preserve="all"/>
<assembly fullname="UnityEditor.SceneTemplateModule" preserve="all"/>
<assembly fullname="UnityEngine.GIModule" preserve="all"/>
<assembly fullname="UnityEngine.IMGUIModule" preserve="all"/>
<assembly fullname="UnityEngine.HierarchyCoreModule" preserve="all"/>
<assembly fullname="UnityEngine.NVIDIAModule" preserve="all"/>
<assembly fullname="UnityEditor.PropertiesModule" preserve="all"/>
<assembly fullname="UnityEngine.ClusterRendererModule" preserve="all"/>
<assembly fullname="UnityEditor.UIElementsModule" preserve="all"/>
<assembly fullname="UnityEngine.InputForUIModule" preserve="all"/>
<assembly fullname="UnityEngine.InputLegacyModule" preserve="all"/>
<assembly fullname="UnityEditor.TilemapModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityWebRequestAudioModule" preserve="all"/>
<assembly fullname="UnityEngine.LocalizationModule" preserve="all"/>
<assembly fullname="UnityEngine.PerformanceReportingModule" preserve="all"/>
<assembly fullname="UnityEditor.CoreBusinessMetricsModule" preserve="all"/>
<assembly fullname="UnityEngine.XRModule" preserve="all"/>
<assembly fullname="UnityEditor.VFXModule" preserve="all"/>
<assembly fullname="UnityEditor.VideoModule" preserve="all"/>
<assembly fullname="UnityEditor.SpriteMaskModule" preserve="all"/>
<assembly fullname="UnityEditor.UmbraModule" preserve="all"/>
<assembly fullname="UnityEngine.UIElementsModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityAnalyticsCommonModule" preserve="all"/>
<assembly fullname="UnityEngine.InputModule" preserve="all"/>
<assembly fullname="UnityEditor.PhysicsModule" preserve="all"/>
<assembly fullname="UnityEngine.AndroidJNIModule" preserve="all"/>
<assembly fullname="UnityEditor.EmbreeModule" preserve="all"/>
<assembly fullname="UnityEngine.TextRenderingModule" preserve="all"/>
<assembly fullname="UnityEngine.MultiplayerModule" preserve="all"/>
<assembly fullname="UnityEditor.UIBuilderModule" preserve="all"/>
<assembly fullname="UnityEditor.EditorToolbarModule" preserve="all"/>
<assembly fullname="UnityEngine.AssetBundleModule" preserve="all"/>
<assembly fullname="Unity.Cecil.Mdb" preserve="all"/>
<assembly fullname="UnityEditor.GridAndSnapModule" preserve="all"/>
<assembly fullname="UnityEngine.TLSModule" preserve="all"/>
<assembly fullname="UnityEditor.UIAutomationModule" preserve="all"/>
<assembly fullname="UnityEditor.XRModule" preserve="all"/>
<assembly fullname="UnityEngine.GridModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityWebRequestModule" preserve="all"/>
<assembly fullname="UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule" preserve="all"/>
<assembly fullname="UnityEditor.TreeModule" preserve="all"/>
<assembly fullname="UnityEditor.SketchUpModule" preserve="all"/>
<assembly fullname="UnityEditor.ShaderFoundryModule" preserve="all"/>
<assembly fullname="UnityEditor.TextRenderingModule" preserve="all"/>
<assembly fullname="UnityEngine.ContentLoadModule" preserve="all"/>
<assembly fullname="UnityEngine" preserve="all"/>
<assembly fullname="UnityEngine.VideoModule" preserve="all"/>
<assembly fullname="UnityEngine.TextCoreFontEngineModule" preserve="all"/>
<assembly fullname="UnityEngine.ShaderVariantAnalyticsModule" preserve="all"/>
<assembly fullname="UnityEngine.UnityCurlModule" preserve="all"/>
<assembly fullname="UnityEditor.SceneViewModule" preserve="all"/>
</linker>
7 changes: 7 additions & 0 deletions Assets/link.xml.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading