From c58e317580d92b366e51263224ae168c368552b4 Mon Sep 17 00:00:00 2001 From: Shawn Kuang Date: Wed, 30 Mar 2022 23:08:34 -0700 Subject: [PATCH 1/3] Change the default value of iOS Resolver setting Change the default value of "Link Framework statically" in iOS Resolver settings to TRUE since it is very likely that some pod frameworks includes pre-built static libraries, and can cause unexpected crash in runtime if the app is build with with multiple targets (Unity 2019.3+). --- source/IOSResolver/src/IOSResolver.cs | 2 +- source/IOSResolver/src/IOSResolverSettingsDialog.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/IOSResolver/src/IOSResolver.cs b/source/IOSResolver/src/IOSResolver.cs index 336cd168..6a1a87fd 100644 --- a/source/IOSResolver/src/IOSResolver.cs +++ b/source/IOSResolver/src/IOSResolver.cs @@ -1032,7 +1032,7 @@ public static bool PodfileAddUseFrameworks { /// public static bool PodfileStaticLinkFrameworks { get { return settings.GetBool(PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS, - defaultValue: false); } + defaultValue: true); } set { settings.SetBool(PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS, value); } diff --git a/source/IOSResolver/src/IOSResolverSettingsDialog.cs b/source/IOSResolver/src/IOSResolverSettingsDialog.cs index 0a705f15..232c9407 100644 --- a/source/IOSResolver/src/IOSResolverSettingsDialog.cs +++ b/source/IOSResolver/src/IOSResolverSettingsDialog.cs @@ -222,6 +222,8 @@ public void OnGUI() { settings.podfileStaticLinkFrameworks = EditorGUILayout.Toggle(settings.podfileStaticLinkFrameworks); GUILayout.EndHorizontal(); + GUILayout.Label("Link frameworks statically is recommended just in case any pod " + + "framework includes static libraries."); } if (IOSResolver.MultipleXcodeTargetsSupported) { From fd33587283a7163d582a5f4e85bec34948372aa4 Mon Sep 17 00:00:00 2001 From: Shawn Kuang Date: Thu, 31 Mar 2022 10:33:52 -0700 Subject: [PATCH 2/3] Workaround to link Swift Standard Libraries The Xcode project generate from Unity may not be able to link Swift Standard Libaries properly if 1. Some pods include Swift frameworks 2. Podfile sets to link frameworks statically The workround attempts to fix this by 1. Add a Dummy.swift file to the Xcode project. 2. Enable `CLANG_ENABLE_MODULES` and `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` build settings. 3. Change `SWIFT_VERSION` to the value specified in iOS Resolver settings. Default to "5". This workaround is turned OFF by default. --- source/IOSResolver/src/IOSResolver.cs | 89 +++++++++++++++++++ .../src/IOSResolverSettingsDialog.cs | 50 ++++++++++- 2 files changed, 138 insertions(+), 1 deletion(-) diff --git a/source/IOSResolver/src/IOSResolver.cs b/source/IOSResolver/src/IOSResolver.cs index 6a1a87fd..eceb885b 100644 --- a/source/IOSResolver/src/IOSResolver.cs +++ b/source/IOSResolver/src/IOSResolver.cs @@ -480,6 +480,13 @@ protected override bool Read(string filename, Logger logger) { // Whether to statically link framework in the Podfile. private const string PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS = PREFERENCE_NAMESPACE + "PodfileStaticLinkFrameworks"; + // Whether to add Dummy.swift to the generated Xcode project as a workaround to support pods + // with Swift Framework. + private const string PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND = + PREFERENCE_NAMESPACE + "SwiftFrameworkSupportWorkaroundEnabled"; + // The Swift Language Version (SWIFT_VERSION) to update to the generated Xcode Project. + private const string PREFERENCE_SWIFT_LANGUAGE_VERSION = + PREFERENCE_NAMESPACE + "SwiftLanguageVersion"; // Whether to add an main target to Podfile for Unity 2019.3+. private const string PREFERENCE_PODFILE_ALWAYS_ADD_MAIN_TARGET = PREFERENCE_NAMESPACE + "PodfileAlwaysAddMainTarget"; @@ -499,6 +506,8 @@ protected override bool Read(string filename, Logger logger) { PREFERENCE_SKIP_POD_INSTALL_WHEN_USING_WORKSPACE_INTEGRATION, PREFERENCE_PODFILE_ADD_USE_FRAMEWORKS, PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS, + PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND, + PREFERENCE_SWIFT_LANGUAGE_VERSION, PREFERENCE_PODFILE_ALWAYS_ADD_MAIN_TARGET, PREFERENCE_PODFILE_ALLOW_PODS_IN_MULTIPLE_TARGETS }; @@ -1038,6 +1047,34 @@ public static bool PodfileStaticLinkFrameworks { } } + /// + /// Ehether to enable Swift Framework support workaround. + /// If enabled, iOS Resolver adds a Dummy.swift to the generated Xcode project, and change build + // properties in order to properly include Swift Standard Libraries. + /// + public static bool SwiftFrameworkSupportWorkaroundEnabled { + get { return settings.GetBool(PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND, + defaultValue: false); } + set { + settings.SetBool(PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND, value); + } + } + + /// + /// The value used to set Xcode build property: Swift Language Version (SWIFT_VERSION). + /// It is default to "5" but Xcode may add or remove options over time. + /// If blank, iOS Resolver will not override the build property. + /// Please check the build property "Swift Language Version" options in Xcode project first + /// before changing this value. + /// + public static string SwiftLanguageVersion { + get { return settings.GetString(PREFERENCE_SWIFT_LANGUAGE_VERSION, + defaultValue: "5.0"); } + set { + settings.SetString(PREFERENCE_SWIFT_LANGUAGE_VERSION, value); + } + } + /// /// Whether to add the main target to Podfile for Unity 2019.3+. True by default. /// If true, iOS Resolver will add the following lines to Podfile, on top of 'UnityFramework' @@ -1838,6 +1875,21 @@ public static void OnPostProcessPatchProject(BuildTarget buildTarget, PatchProject(buildTarget, pathToBuiltProject); } + /// + /// Post-processing build step to add dummy swift file + /// + [PostProcessBuildAttribute(BUILD_ORDER_PATCH_PROJECT)] + public static void OnPostProcessAddDummySwiftFile(BuildTarget buildTarget, + string pathToBuiltProject) { + if (!InjectDependencies() || + !PodfileGenerationEnabled || + !PodfileAddUseFrameworks || + !SwiftFrameworkSupportWorkaroundEnabled) { + return; + } + AddDummySwiftFile(buildTarget, pathToBuiltProject); + } + /// /// Get Xcode target names using a method that works across all Unity versions. /// @@ -1935,6 +1987,42 @@ internal static void PatchProject( File.WriteAllText(pbxprojPath, project.WriteToString()); } + internal static void AddDummySwiftFile( + BuildTarget buildTarget, string pathToBuiltProject) { + string pbxprojPath = GetProjectPath(pathToBuiltProject); + var project = new UnityEditor.iOS.Xcode.PBXProject(); + project.ReadFromString(File.ReadAllText(pbxprojPath)); + + string DUMMY_SWIFT_FILE_NAME = "Dummy.swift"; + string DUMMY_SWIFT_FILE_CONTENT = + "// Generated by External Dependency Manager for Unity\n" + + "import Foundation"; + string dummySwiftPath = Path.Combine(pathToBuiltProject, DUMMY_SWIFT_FILE_NAME); + if (!File.Exists(dummySwiftPath)) { + File.WriteAllText(dummySwiftPath, DUMMY_SWIFT_FILE_CONTENT); + } + + foreach (var target in GetXcodeTargetGuids(project, includeAllTargets: false)) { + project.AddFileToBuild( + target, + project.AddFile(DUMMY_SWIFT_FILE_NAME, + DUMMY_SWIFT_FILE_NAME, + UnityEditor.iOS.Xcode.PBXSourceTree.Source)); + if(!string.IsNullOrEmpty(SwiftLanguageVersion)) { + project.SetBuildProperty(target, "SWIFT_VERSION", SwiftLanguageVersion); + } + + // These build properties are only required for multi-target Xcode project, which is + // generated from 2019.3+. + if(MultipleXcodeTargetsSupported) { + project.SetBuildProperty(target, "CLANG_ENABLE_MODULES", "YES"); + project.SetBuildProperty(target, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES"); + } + } + + File.WriteAllText(pbxprojPath, project.WriteToString()); + } + /// /// Post-processing build step to generate the podfile for ios. /// @@ -1942,6 +2030,7 @@ internal static void PatchProject( public static void OnPostProcessGenPodfile(BuildTarget buildTarget, string pathToBuiltProject) { if (!InjectDependencies() || !PodfileGenerationEnabled) return; + Log("OnPostProcessGenPodfile!", level: LogLevel.Error); GenPodfile(buildTarget, pathToBuiltProject); } diff --git a/source/IOSResolver/src/IOSResolverSettingsDialog.cs b/source/IOSResolver/src/IOSResolverSettingsDialog.cs index 232c9407..c7d0b8d7 100644 --- a/source/IOSResolver/src/IOSResolverSettingsDialog.cs +++ b/source/IOSResolver/src/IOSResolverSettingsDialog.cs @@ -39,6 +39,8 @@ private class Settings { internal int cocoapodsIntegrationMenuIndex; internal bool podfileAddUseFrameworks; internal bool podfileStaticLinkFrameworks; + internal bool swiftFrameworkSupportWorkaroundEnabled; + internal string swiftLanguageVersion; internal bool podfileAlwaysAddMainTarget; internal bool podfileAllowPodsInMultipleTargets; internal bool useProjectSettings; @@ -57,6 +59,9 @@ internal Settings() { IOSResolver.CocoapodsIntegrationMethodPref); podfileAddUseFrameworks = IOSResolver.PodfileAddUseFrameworks; podfileStaticLinkFrameworks = IOSResolver.PodfileStaticLinkFrameworks; + swiftFrameworkSupportWorkaroundEnabled = + IOSResolver.SwiftFrameworkSupportWorkaroundEnabled; + swiftLanguageVersion = IOSResolver.SwiftLanguageVersion; podfileAlwaysAddMainTarget = IOSResolver.PodfileAlwaysAddMainTarget; podfileAllowPodsInMultipleTargets = IOSResolver.PodfileAllowPodsInMultipleTargets; useProjectSettings = IOSResolver.UseProjectSettings; @@ -76,6 +81,9 @@ internal void Save() { integrationMapping[cocoapodsIntegrationMenuIndex]; IOSResolver.PodfileAddUseFrameworks = podfileAddUseFrameworks; IOSResolver.PodfileStaticLinkFrameworks = podfileStaticLinkFrameworks; + IOSResolver.SwiftFrameworkSupportWorkaroundEnabled = + swiftFrameworkSupportWorkaroundEnabled; + IOSResolver.SwiftLanguageVersion = swiftLanguageVersion; IOSResolver.PodfileAlwaysAddMainTarget = podfileAlwaysAddMainTarget; IOSResolver.PodfileAllowPodsInMultipleTargets = podfileAllowPodsInMultipleTargets; IOSResolver.UseProjectSettings = useProjectSettings; @@ -99,6 +107,8 @@ internal void Save() { IOSResolver.CocoapodsIntegrationMethod.None, }; + private Vector2 scrollPosition = new Vector2(0, 0); + // enum to index (linear search because there's no point in creating a reverse mapping // with such a small list). private static int FindIndexFromCocoapodsIntegrationMethod( @@ -137,6 +147,8 @@ public void OnGUI() { IOSResolverVersionNumber.Value.Minor, IOSResolverVersionNumber.Value.Build)); + scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition); + GUILayout.BeginHorizontal(); GUILayout.Label("Podfile Generation", EditorStyles.boldLabel); settings.podfileGenerationEnabled = @@ -250,6 +262,33 @@ public void OnGUI() { } } + if (settings.podfileAddUseFrameworks) { + GUILayout.BeginHorizontal(); + GUILayout.Label("Enable Swift Framework Support Workaround", + EditorStyles.boldLabel); + settings.swiftFrameworkSupportWorkaroundEnabled = + EditorGUILayout.Toggle(settings.swiftFrameworkSupportWorkaroundEnabled); + GUILayout.EndHorizontal(); + GUILayout.Label("This workround patches the Xcode project to properly link Swift " + + "Standard Library when some plugins depend on Swift Framework " + + "pods by:"); + GUILayout.Label("1. Add a dummy Swift file to Xcode project."); + GUILayout.Label("2. Enable 'CLANG_ENABLE_MODULES' and " + + "'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES' build settings and set " + + "'SWIFT_VERSION' to the value below."); + + if (settings.swiftFrameworkSupportWorkaroundEnabled) { + GUILayout.BeginHorizontal(); + GUILayout.Label("Swift Framework Version", + EditorStyles.boldLabel); + settings.swiftLanguageVersion = + EditorGUILayout.TextField(settings.swiftLanguageVersion); + GUILayout.EndHorizontal(); + GUILayout.Label("Used to set 'SWIFT_VERSION' build setting in Xcode. Leave " + + "it blank to update it manually."); + } + } + GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1)); } @@ -265,8 +304,11 @@ public void OnGUI() { settings.useProjectSettings = EditorGUILayout.Toggle(settings.useProjectSettings); GUILayout.EndHorizontal(); - GUILayout.Space(10); + EditorGUILayout.EndScrollView(); + GUILayout.EndVertical(); + GUILayout.BeginVertical(); + GUILayout.Space(10); if (GUILayout.Button("Reset to Defaults")) { // Load default settings into the dialog but preserve the state in the user's // saved preferences. @@ -316,6 +358,12 @@ public void OnGUI() { new KeyValuePair( "podfileAllowPodsInMultipleTargets", IOSResolver.PodfileAllowPodsInMultipleTargets.ToString()), + new KeyValuePair( + "swiftFrameworkSupportWorkaroundEnabled", + IOSResolver.SwiftFrameworkSupportWorkaroundEnabled.ToString()), + new KeyValuePair( + "swiftLanguageVersion", + IOSResolver.SwiftLanguageVersion.ToString()), }, "Settings Save"); settings.Save(); From 604b422bf1e65e80e80d18752cb12217028f6f93 Mon Sep 17 00:00:00 2001 From: Shawn Kuang Date: Thu, 31 Mar 2022 10:33:52 -0700 Subject: [PATCH 3/3] Workaround to link Swift Standard Libraries The Xcode project generate from Unity may not be able to link Swift Standard Libaries properly if 1. Some pods include Swift frameworks 2. Podfile sets to link frameworks statically The workround attempts to fix this by 1. Add a Dummy.swift file to the Xcode project. 2. Enable `CLANG_ENABLE_MODULES` and `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` build settings. 3. Change `SWIFT_VERSION` to the value specified in iOS Resolver settings. Default to "5". This workaround is turned OFF by default. --- source/IOSResolver/src/IOSResolver.cs | 2 +- source/IOSResolver/src/IOSResolverSettingsDialog.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/IOSResolver/src/IOSResolver.cs b/source/IOSResolver/src/IOSResolver.cs index eceb885b..1ae1fa7d 100644 --- a/source/IOSResolver/src/IOSResolver.cs +++ b/source/IOSResolver/src/IOSResolver.cs @@ -1048,7 +1048,7 @@ public static bool PodfileStaticLinkFrameworks { } /// - /// Ehether to enable Swift Framework support workaround. + /// Whether to enable Swift Framework support workaround. /// If enabled, iOS Resolver adds a Dummy.swift to the generated Xcode project, and change build // properties in order to properly include Swift Standard Libraries. /// diff --git a/source/IOSResolver/src/IOSResolverSettingsDialog.cs b/source/IOSResolver/src/IOSResolverSettingsDialog.cs index c7d0b8d7..bfcb7932 100644 --- a/source/IOSResolver/src/IOSResolverSettingsDialog.cs +++ b/source/IOSResolver/src/IOSResolverSettingsDialog.cs @@ -284,8 +284,8 @@ public void OnGUI() { settings.swiftLanguageVersion = EditorGUILayout.TextField(settings.swiftLanguageVersion); GUILayout.EndHorizontal(); - GUILayout.Label("Used to set 'SWIFT_VERSION' build setting in Xcode. Leave " + - "it blank to update it manually."); + GUILayout.Label("Used to override 'SWIFT_VERSION' build setting in Xcode. " + + "Leave it blank to prevent override."); } }