From bb1f560366a7fb9e693fe4453bfc21e114f306e2 Mon Sep 17 00:00:00 2001 From: Rex Raphael Date: Mon, 15 Jan 2024 01:24:08 -0600 Subject: [PATCH] refactor: major c# build code refactor --- .../Editor/BaseBuild.cs | 78 ++ .../Editor/BaseBuild.cs.meta | 3 + .../FlutterUnityIntegration/Editor/Build.cs | 829 ++++++------------ .../Editor/BuildAndroid.cs | 272 ++++++ .../Editor/BuildAndroid.cs.meta | 3 + .../Editor/BuildIOS.cs | 200 +++++ .../Editor/BuildIOS.cs.meta | 3 + .../Editor/BuildWeb.cs | 178 ++++ .../Editor/BuildWeb.cs.meta | 3 + .../Editor/BuildWindows.cs | 88 ++ .../Editor/BuildWindows.cs.meta | 3 + .../Editor/FuwPlatform.cs | 48 + .../Editor/FuwPlatform.cs.meta | 3 + 13 files changed, 1145 insertions(+), 566 deletions(-) create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs.meta create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildAndroid.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildAndroid.cs.meta create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildIOS.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildIOS.cs.meta create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildWeb.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildWeb.cs.meta create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildWindows.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BuildWindows.cs.meta create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/FuwPlatform.cs create mode 100644 examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/FuwPlatform.cs.meta diff --git a/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs new file mode 100644 index 00000000..083ace38 --- /dev/null +++ b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs @@ -0,0 +1,78 @@ +using System; +using System.IO; +using System.Linq; +using UnityEditor; +using UnityEditor.Build.Reporting; +using UnityEngine; + +// uncomment for addressables +//using UnityEditor.AddressableAssets; +//using UnityEditor.AddressableAssets.Settings; + +namespace FlutterUnityIntegration.Editor +{ + public record FuwBuildOptions + { + public string OutputDir { get; set; } + public string BuildPath { get; set; } + public bool PackageMode { get; set; } + public bool Release { get; set; } + } + + public class BaseBuild + { + public string ProjectPath; + public string APKPath; + public string OutputDir { get; set; } + public string BuildDir { get; set; } + + public void Bootstrap(FuwBuildOptions options) + { + ProjectPath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); + APKPath = Path.Combine(ProjectPath, "Builds/" + Application.productName + ".apk"); + OutputDir = Path.GetFullPath(Path.Combine(ProjectPath, options.OutputDir)); + } + + protected void Copy(string source, string destinationPath) + { + if (Directory.Exists(destinationPath)) + Directory.Delete(destinationPath, true); + + Directory.CreateDirectory(destinationPath); + + foreach (var dirPath in Directory.GetDirectories(source, "*", + SearchOption.AllDirectories)) + Directory.CreateDirectory(dirPath.Replace(source, destinationPath)); + + foreach (var newPath in Directory.GetFiles(source, "*.*", + SearchOption.AllDirectories)) + File.Copy(newPath, newPath.Replace(source, destinationPath), true); + } + + protected string[] GetEnabledScenes() + { + var scenes = EditorBuildSettings.scenes + .Where(s => s.enabled) + .Select(s => s.path) + .ToArray(); + + return scenes; + } + + protected void ExportAddressables() + { + // Debug.Log("Start building player content (Addressables)"); + // Debug.Log("BuildAddressablesProcessor.PreExport start"); + // + // AddressableAssetSettings.CleanPlayerContent( + // AddressableAssetSettingsDefaultObject.Settings.ActivePlayerDataBuilder); + // + // AddressableAssetProfileSettings profileSettings = AddressableAssetSettingsDefaultObject.Settings.profileSettings; + // string profileId = profileSettings.GetProfileId("Default"); + // AddressableAssetSettingsDefaultObject.Settings.activeProfileId = profileId; + // + // AddressableAssetSettings.BuildPlayerContent(); + // Debug.Log("BuildAddressablesProcessor.PreExport done"); + } + } +} \ No newline at end of file diff --git a/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs.meta b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs.meta new file mode 100644 index 00000000..a11b855e --- /dev/null +++ b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/BaseBuild.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 859c5b9d29f94955a1996ef2a289089d +timeCreated: 1705295157 \ No newline at end of file diff --git a/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/Build.cs b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/Build.cs index 15a082fe..5296e50a 100644 --- a/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/Build.cs +++ b/examples/unity/DemoApp/Assets/FlutterUnityIntegration/Editor/Build.cs @@ -1,11 +1,5 @@ -using System; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using UnityEditor; +using UnityEditor; using UnityEngine; -using Application = UnityEngine.Application; -using BuildResult = UnityEditor.Build.Reporting.BuildResult; // uncomment for addressables //using UnityEditor.AddressableAssets; @@ -13,616 +7,319 @@ namespace FlutterUnityIntegration.Editor { + /// + /// Represents a Unity Editor window for exporting Flutter projects to different platforms. + /// public class Build : EditorWindow { - private static readonly string ProjectPath = Path.GetFullPath(Path.Combine(Application.dataPath, "..")); - private static readonly string APKPath = Path.Combine(ProjectPath, "Builds/" + Application.productName + ".apk"); - - private static readonly string AndroidExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../android/unityLibrary")); - private static readonly string WindowsExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../windows/unityLibrary/data")); - private static readonly string IOSExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../ios/UnityLibrary")); - private static readonly string WebExportPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../web/UnityLibrary")); - private static readonly string IOSExportPluginPath = Path.GetFullPath(Path.Combine(ProjectPath, "../../ios_xcode/UnityLibrary")); - - private bool _pluginMode = false; - private static string _persistentKey = "flutter-unity-widget-pluginMode"; - - //#region GUI Member Methods - [MenuItem("Flutter/Export Android (Debug) %&n", false, 101)] - public static void DoBuildAndroidLibraryDebug() - { - DoBuildAndroid(Path.Combine(APKPath, "unityLibrary"), false, false); - - // Copy over resources from the launcher module that are used by the library - Copy(Path.Combine(APKPath + "/launcher/src/main/res"), Path.Combine(AndroidExportPath, "src/main/res")); - } + /// + /// The key used to access the Android project path value in the Editor's preferences. + /// + private string editorAndroidPrefKey = "BuildWindow.androidProjectPath"; - [MenuItem("Flutter/Export Android (Release) %&m", false, 102)] - public static void DoBuildAndroidLibraryRelease() - { - DoBuildAndroid(Path.Combine(APKPath, "unityLibrary"), false, true); + /// + /// Represents the key used to store the Android plugin project path in the editor preferences. + /// + private string editorAndroidPluginPrefKey = "BuildWindow.androidPluginProjectPath"; - // Copy over resources from the launcher module that are used by the library - Copy(Path.Combine(APKPath + "/launcher/src/main/res"), Path.Combine(AndroidExportPath, "src/main/res")); - } + /// + /// The variable represents the key used to store and retrieve the iOS project path in the build window preferences. + /// + private string editorIOSPrefKey = "BuildWindow.iosProjectPath"; - [MenuItem("Flutter/Export Android Plugin %&p", false, 103)] - public static void DoBuildAndroidPlugin() - { - DoBuildAndroid(Path.Combine(APKPath, "unityLibrary"), true, true); + /// + /// The key used to store the iOS plugin project path in the editor preferences. + /// + private string editorIOSPluginPrefKey = "BuildWindow.iosPluginProjectPath"; - // Copy over resources from the launcher module that are used by the library - Copy(Path.Combine(APKPath + "/launcher/src/main/res"), Path.Combine(AndroidExportPath, "src/main/res")); - } + /// + /// Represents the key used in editor preferences to store the web project path for the build window. + /// + private string editorWebPrefKey = "BuildWindow.webProjectPath"; - [MenuItem("Flutter/Export IOS (Debug) %&i", false, 201)] - public static void DoBuildIOSDebug() - { - BuildIOS(IOSExportPath, false); - } + /// / + private string editorWindowsPrefKey = "BuildWindow.windowsProjectPath"; - [MenuItem("Flutter/Export IOS (Release) %&i", false, 202)] - public static void DoBuildIOSRelease() { - BuildIOS(IOSExportPath, true); - } + /// + /// The path to the Android project. + /// + /// + /// A string representing the file path to the Android project. + /// + private static string androidProjectPath = ""; - [MenuItem("Flutter/Export IOS Plugin %&o", false, 203)] - public static void DoBuildIOSPlugin() - { - BuildIOS(IOSExportPluginPath, true); + /// + /// Represents the file path of the Android plugin project. + /// + private static string androidPluginProjectPath = ""; - // Automate so manual steps - SetupIOSProjectForPlugin(); + /// + /// Represents the path to the iOS project. + /// / + private static string iosProjectPath = ""; - // Build Archive - // BuildUnityFrameworkArchive(); + /// + /// The path to the iOS plugin project. + /// + private static string iosPluginProjectPath = ""; - } + /// + /// Represents the file path to the web project. + /// + private static string webProjectPath = ""; - [MenuItem("Flutter/Export Web GL %&w", false, 301)] - public static void DoBuildWebGL() - { - BuildWebGL(WebExportPath); - } + /// + /// The path of the Windows project. + /// + private static string windowsProjectPath = ""; + /// + /// Default export path for Android project in Unity. + /// + private static readonly string defaultAndroidExportPath = "../../standard/android/unityLibrary"; - [MenuItem("Flutter/Export Windows %&d", false, 401)] - public static void DoBuildWindowsOS() - { - BuildWindowsOS(WindowsExportPath); - } + /// + /// The default export path for Android plugins in Unity. + /// + private static readonly string defaultAndroidPluginExportPath = "../../standard/android/unityLibrary"; - [MenuItem("Flutter/Settings %&S", false, 501)] - public static void PluginSettings() - { - EditorWindow.GetWindow(typeof(Build)); - } + /// + /// The default export path for Windows platform in Unity Library. + /// + private static readonly string defaultWindowsExportPath = "../../standard/windows/unityLibrary/data"; - private void OnGUI() - { - GUILayout.Label("Flutter Unity Widget Settings", EditorStyles.boldLabel); + /// + /// The default export path for iOS projects in Unity. + /// + private static readonly string defaultIOSExportPath = "../../standard/ios/UnityLibrary"; - EditorGUI.BeginChangeCheck(); - _pluginMode = EditorGUILayout.Toggle("Plugin Mode", _pluginMode); + /// + /// The default path for web export in UnityLibrary. + /// + private static readonly string defaultWebExportPath = "../../standard/web/UnityLibrary"; - if (EditorGUI.EndChangeCheck()) - { - EditorPrefs.SetBool(_persistentKey, _pluginMode); - } - } + /// + /// The default path for the iOS export plugin. + /// + private static readonly string defaultIOSExportPluginPath = "../../standard/ios_xcode/UnityLibrary"; - private void OnEnable() + /// + /// This method is used to build an Android library in debug mode using the Flutter framework. + /// + /// + /// This method is invoked when the "Export Android (Debug)" menu item is clicked. It generates a build with the specified build options. + /// + [MenuItem("Flutter/Export Android (Debug) %&n", false, 101)] + public static void DoBuildAndroidLibraryDebug() => GenerateBuild(new FuwBuildOptions { - _pluginMode = EditorPrefs.GetBool(_persistentKey, false); - } - //#endregion - - - //#region Build Member Methods + OutputDir = androidProjectPath, + PackageMode = false, + Release = false + }); - private static void BuildWindowsOS(String path) + /// + /// Builds the Android library in release mode. + /// + /// + /// This method is called when the "Export Android (Release)" menu item is clicked. + /// It generates the build using the class and the specified build options. + /// The build options include the output directory, build path, package mode, and release mode. + /// + [MenuItem("Flutter/Export Android (Release) %&m", false, 102)] + public static void DoBuildAndroidLibraryRelease() => GenerateBuild(new FuwBuildOptions { - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android); - - if (Directory.Exists(path)) - Directory.Delete(path, true); - - if (Directory.Exists(WindowsExportPath)) - Directory.Delete(WindowsExportPath, true); - - var playerOptions = new BuildPlayerOptions - { - scenes = GetEnabledScenes(), - target = BuildTarget.StandaloneWindows64, - locationPathName = path, - options = BuildOptions.AllowDebugging - }; - - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Standalone, BuildTarget.StandaloneWindows64); - - // build addressable - ExportAddressables(); - var report = BuildPipeline.BuildPlayer(playerOptions); - - if (report.summary.result != BuildResult.Succeeded) - throw new Exception("Build failed"); - - Debug.Log("-- Windows Build: SUCCESSFUL --"); - } + OutputDir = androidProjectPath, + BuildPath = "unityLibrary", + PackageMode = false, + Release = true + }); - private static void BuildWebGL(String path) + /// + /// Builds an Android plugin for the Flutter project. + /// + /// + /// This method is invoked via the menu item "Flutter/Export Android Plugin" with the shortcut + /// "%&p". It generates the build using the class. + /// + [MenuItem("Flutter/Export Android Plugin %&p", false, 103)] + public static void DoBuildAndroidPlugin() => GenerateBuild(new FuwBuildOptions { - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android); - - if (Directory.Exists(path)) - Directory.Delete(path, true); - - if (Directory.Exists(WebExportPath)) - Directory.Delete(WebExportPath, true); - - // EditorUserBuildSettings. = true; - - var playerOptions = new BuildPlayerOptions(); - playerOptions.scenes = GetEnabledScenes(); - playerOptions.target = BuildTarget.WebGL; - playerOptions.locationPathName = path; - - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.WebGL, BuildTarget.WebGL); - // build addressable - ExportAddressables(); - var report = BuildPipeline.BuildPlayer(playerOptions); - - if (report.summary.result != BuildResult.Succeeded) - throw new Exception("Build failed"); - - // Copy(path, WebExportPath); - ModifyWebGLExport(); - - Debug.Log("-- WebGL Build: SUCCESSFUL --"); - } + OutputDir = androidPluginProjectPath, + BuildPath = "unityLibrary", + PackageMode = true, + Release = true + }); - private static void DoBuildAndroid(String buildPath, bool isPlugin, bool isReleaseBuild) + /// + /// This method is used to build an iOS debug version of a Flutter project. + /// It is executed when the menu item "Flutter/Export IOS (Debug)" is clicked. + /// + /// + /// The generated build will have the following options: + /// - Output directory will be set to the 'iosProjectPath' variable + /// - Package mode will be disabled + /// - Release mode will be disabled + /// + [MenuItem("Flutter/Export IOS (Debug) %&i", false, 201)] + public static void DoBuildIOSDebug() => GenerateBuild(new FuwBuildOptions { - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android); - - if (Directory.Exists(APKPath)) - Directory.Delete(APKPath, true); - - if (Directory.Exists(AndroidExportPath)) - Directory.Delete(AndroidExportPath, true); - - EditorUserBuildSettings.androidBuildSystem = AndroidBuildSystem.Gradle; - EditorUserBuildSettings.exportAsGoogleAndroidProject = true; - - var playerOptions = new BuildPlayerOptions(); - playerOptions.scenes = GetEnabledScenes(); - playerOptions.target = BuildTarget.Android; - playerOptions.locationPathName = APKPath; - if (!isReleaseBuild) - { - // remove this line if you don't use a debugger and you want to speed up the flutter build - playerOptions.options = BuildOptions.AllowDebugging | BuildOptions.Development; - } - #if UNITY_2022_1_OR_NEWER - PlayerSettings.SetIl2CppCompilerConfiguration(BuildTargetGroup.Android, isReleaseBuild ? Il2CppCompilerConfiguration.Release : Il2CppCompilerConfiguration.Debug); - PlayerSettings.SetIl2CppCodeGeneration(UnityEditor.Build.NamedBuildTarget.Android, UnityEditor.Build.Il2CppCodeGeneration.OptimizeSize); - #elif UNITY_2021_2_OR_NEWER - PlayerSettings.SetIl2CppCompilerConfiguration(BuildTargetGroup.Android, isReleaseBuild ? Il2CppCompilerConfiguration.Release : Il2CppCompilerConfiguration.Debug); - EditorUserBuildSettings.il2CppCodeGeneration = UnityEditor.Build.Il2CppCodeGeneration.OptimizeSize; - #endif - - // Switch to Android standalone build. - EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTargetGroup.Android, BuildTarget.Android); - // build addressable - ExportAddressables(); - var report = BuildPipeline.BuildPlayer(playerOptions); - - if (report.summary.result != BuildResult.Succeeded) - throw new Exception("Build failed"); - - Copy(buildPath, AndroidExportPath); - - // Modify build.gradle - ModifyAndroidGradle(isPlugin); - - if(isPlugin) - { - SetupAndroidProjectForPlugin(); - } else - { - SetupAndroidProject(); - } - - if (isReleaseBuild) { - Debug.Log($"-- Android Release Build: SUCCESSFUL --"); - } else - { - Debug.Log($"-- Android Debug Build: SUCCESSFUL --"); - } - } + OutputDir = iosProjectPath, + PackageMode = false, + Release = false + }); - private static void ModifyWebGLExport() + /// + /// Builds the IOS project for release. + /// + /// + /// This method is triggered when the menu item "Flutter/Export IOS (Release)" is clicked. It executes the GenerateBuild method + /// by passing in BuildIOS as the generic type and a new instance of FuwBuildOptions with the necessary parameters for building + /// the IOS project in release mode. + /// + [MenuItem("Flutter/Export IOS (Release) %&ir", false, 202)] + public static void DoBuildIOSRelease() => GenerateBuild(new FuwBuildOptions { - // Modify index.html - var indexFile = Path.Combine(WebExportPath, "index.html"); - var indexHtmlText = File.ReadAllText(indexFile); - - indexHtmlText = indexHtmlText.Replace("