Skip to content

Commit 56aaa44

Browse files
committed
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.
1 parent 5f3e9c0 commit 56aaa44

File tree

2 files changed

+138
-1
lines changed

2 files changed

+138
-1
lines changed

source/IOSResolver/src/IOSResolver.cs

+89
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,13 @@ protected override bool Read(string filename, Logger logger) {
480480
// Whether to statically link framework in the Podfile.
481481
private const string PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS =
482482
PREFERENCE_NAMESPACE + "PodfileStaticLinkFrameworks";
483+
// Whether to add Dummy.swift to the generated Xcode project as a workaround to support pods
484+
// with Swift Framework.
485+
private const string PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND =
486+
PREFERENCE_NAMESPACE + "SwiftFrameworkSupportWorkaroundEnabled";
487+
// The Swift Language Version (SWIFT_VERSION) to update to the generated Xcode Project.
488+
private const string PREFERENCE_SWIFT_LANGUAGE_VERSION =
489+
PREFERENCE_NAMESPACE + "SwiftLanguageVersion";
483490
// Whether to add an main target to Podfile for Unity 2019.3+.
484491
private const string PREFERENCE_PODFILE_ALWAYS_ADD_MAIN_TARGET =
485492
PREFERENCE_NAMESPACE + "PodfileAlwaysAddMainTarget";
@@ -499,6 +506,8 @@ protected override bool Read(string filename, Logger logger) {
499506
PREFERENCE_SKIP_POD_INSTALL_WHEN_USING_WORKSPACE_INTEGRATION,
500507
PREFERENCE_PODFILE_ADD_USE_FRAMEWORKS,
501508
PREFERENCE_PODFILE_STATIC_LINK_FRAMEWORKS,
509+
PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND,
510+
PREFERENCE_SWIFT_LANGUAGE_VERSION,
502511
PREFERENCE_PODFILE_ALWAYS_ADD_MAIN_TARGET,
503512
PREFERENCE_PODFILE_ALLOW_PODS_IN_MULTIPLE_TARGETS
504513
};
@@ -1038,6 +1047,34 @@ public static bool PodfileStaticLinkFrameworks {
10381047
}
10391048
}
10401049

1050+
/// <summary>
1051+
/// Ehether to enable Swift Framework support workaround.
1052+
/// If enabled, iOS Resolver adds a Dummy.swift to the generated Xcode project, and change build
1053+
// properties in order to properly include Swift Standard Libraries.
1054+
/// </summary>
1055+
public static bool SwiftFrameworkSupportWorkaroundEnabled {
1056+
get { return settings.GetBool(PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND,
1057+
defaultValue: false); }
1058+
set {
1059+
settings.SetBool(PREFERENCE_SWIFT_FRAMEWORK_SUPPORT_WORKAROUND, value);
1060+
}
1061+
}
1062+
1063+
/// <summary>
1064+
/// The value used to set Xcode build property: Swift Language Version (SWIFT_VERSION).
1065+
/// It is default to "5" but Xcode may add or remove options over time.
1066+
/// If blank, iOS Resolver will not override the build property.
1067+
/// Please check the build property "Swift Language Version" options in Xcode project first
1068+
/// before changing this value.
1069+
/// </summary>
1070+
public static string SwiftLanguageVersion {
1071+
get { return settings.GetString(PREFERENCE_SWIFT_LANGUAGE_VERSION,
1072+
defaultValue: "5.0"); }
1073+
set {
1074+
settings.SetString(PREFERENCE_SWIFT_LANGUAGE_VERSION, value);
1075+
}
1076+
}
1077+
10411078
/// <summary>
10421079
/// Whether to add the main target to Podfile for Unity 2019.3+. True by default.
10431080
/// 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,
18381875
PatchProject(buildTarget, pathToBuiltProject);
18391876
}
18401877

1878+
/// <summary>
1879+
/// Post-processing build step to add dummy swift file
1880+
/// </summary>
1881+
[PostProcessBuildAttribute(BUILD_ORDER_PATCH_PROJECT)]
1882+
public static void OnPostProcessAddDummySwiftFile(BuildTarget buildTarget,
1883+
string pathToBuiltProject) {
1884+
if (!InjectDependencies() ||
1885+
!PodfileGenerationEnabled ||
1886+
!PodfileAddUseFrameworks ||
1887+
!SwiftFrameworkSupportWorkaroundEnabled) {
1888+
return;
1889+
}
1890+
AddDummySwiftFile(buildTarget, pathToBuiltProject);
1891+
}
1892+
18411893
/// <summary>
18421894
/// Get Xcode target names using a method that works across all Unity versions.
18431895
/// </summary>
@@ -1935,13 +1987,50 @@ internal static void PatchProject(
19351987
File.WriteAllText(pbxprojPath, project.WriteToString());
19361988
}
19371989

1990+
internal static void AddDummySwiftFile(
1991+
BuildTarget buildTarget, string pathToBuiltProject) {
1992+
string pbxprojPath = GetProjectPath(pathToBuiltProject);
1993+
var project = new UnityEditor.iOS.Xcode.PBXProject();
1994+
project.ReadFromString(File.ReadAllText(pbxprojPath));
1995+
1996+
string DUMMY_SWIFT_FILE_NAME = "Dummy.swift";
1997+
string DUMMY_SWIFT_FILE_CONTENT =
1998+
"// Generated by External Dependency Manager for Unity\n" +
1999+
"import Foundation";
2000+
string dummySwiftPath = Path.Combine(pathToBuiltProject, DUMMY_SWIFT_FILE_NAME);
2001+
if (!File.Exists(dummySwiftPath)) {
2002+
File.WriteAllText(dummySwiftPath, DUMMY_SWIFT_FILE_CONTENT);
2003+
}
2004+
2005+
foreach (var target in GetXcodeTargetGuids(project, includeAllTargets: false)) {
2006+
project.AddFileToBuild(
2007+
target,
2008+
project.AddFile(DUMMY_SWIFT_FILE_NAME,
2009+
DUMMY_SWIFT_FILE_NAME,
2010+
UnityEditor.iOS.Xcode.PBXSourceTree.Source));
2011+
if(!string.IsNullOrEmpty(SwiftLanguageVersion)) {
2012+
project.SetBuildProperty(target, "SWIFT_VERSION", SwiftLanguageVersion);
2013+
}
2014+
2015+
// These build properties are only required for multi-target Xcode project, which is
2016+
// generated from 2019.3+.
2017+
if(MultipleXcodeTargetsSupported) {
2018+
project.SetBuildProperty(target, "CLANG_ENABLE_MODULES", "YES");
2019+
project.SetBuildProperty(target, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
2020+
}
2021+
}
2022+
2023+
File.WriteAllText(pbxprojPath, project.WriteToString());
2024+
}
2025+
19382026
/// <summary>
19392027
/// Post-processing build step to generate the podfile for ios.
19402028
/// </summary>
19412029
[PostProcessBuildAttribute(BUILD_ORDER_GEN_PODFILE)]
19422030
public static void OnPostProcessGenPodfile(BuildTarget buildTarget,
19432031
string pathToBuiltProject) {
19442032
if (!InjectDependencies() || !PodfileGenerationEnabled) return;
2033+
Log("OnPostProcessGenPodfile!", level: LogLevel.Error);
19452034
GenPodfile(buildTarget, pathToBuiltProject);
19462035
}
19472036

source/IOSResolver/src/IOSResolverSettingsDialog.cs

+49-1
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ private class Settings {
3939
internal int cocoapodsIntegrationMenuIndex;
4040
internal bool podfileAddUseFrameworks;
4141
internal bool podfileStaticLinkFrameworks;
42+
internal bool swiftFrameworkSupportWorkaroundEnabled;
43+
internal string swiftLanguageVersion;
4244
internal bool podfileAlwaysAddMainTarget;
4345
internal bool podfileAllowPodsInMultipleTargets;
4446
internal bool useProjectSettings;
@@ -57,6 +59,9 @@ internal Settings() {
5759
IOSResolver.CocoapodsIntegrationMethodPref);
5860
podfileAddUseFrameworks = IOSResolver.PodfileAddUseFrameworks;
5961
podfileStaticLinkFrameworks = IOSResolver.PodfileStaticLinkFrameworks;
62+
swiftFrameworkSupportWorkaroundEnabled =
63+
IOSResolver.SwiftFrameworkSupportWorkaroundEnabled;
64+
swiftLanguageVersion = IOSResolver.SwiftLanguageVersion;
6065
podfileAlwaysAddMainTarget = IOSResolver.PodfileAlwaysAddMainTarget;
6166
podfileAllowPodsInMultipleTargets = IOSResolver.PodfileAllowPodsInMultipleTargets;
6267
useProjectSettings = IOSResolver.UseProjectSettings;
@@ -76,6 +81,9 @@ internal void Save() {
7681
integrationMapping[cocoapodsIntegrationMenuIndex];
7782
IOSResolver.PodfileAddUseFrameworks = podfileAddUseFrameworks;
7883
IOSResolver.PodfileStaticLinkFrameworks = podfileStaticLinkFrameworks;
84+
IOSResolver.SwiftFrameworkSupportWorkaroundEnabled =
85+
swiftFrameworkSupportWorkaroundEnabled;
86+
IOSResolver.SwiftLanguageVersion = swiftLanguageVersion;
7987
IOSResolver.PodfileAlwaysAddMainTarget = podfileAlwaysAddMainTarget;
8088
IOSResolver.PodfileAllowPodsInMultipleTargets = podfileAllowPodsInMultipleTargets;
8189
IOSResolver.UseProjectSettings = useProjectSettings;
@@ -99,6 +107,8 @@ internal void Save() {
99107
IOSResolver.CocoapodsIntegrationMethod.None,
100108
};
101109

110+
private Vector2 scrollPosition = new Vector2(0, 0);
111+
102112
// enum to index (linear search because there's no point in creating a reverse mapping
103113
// with such a small list).
104114
private static int FindIndexFromCocoapodsIntegrationMethod(
@@ -137,6 +147,8 @@ public void OnGUI() {
137147
IOSResolverVersionNumber.Value.Minor,
138148
IOSResolverVersionNumber.Value.Build));
139149

150+
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
151+
140152
GUILayout.BeginHorizontal();
141153
GUILayout.Label("Podfile Generation", EditorStyles.boldLabel);
142154
settings.podfileGenerationEnabled =
@@ -250,6 +262,33 @@ public void OnGUI() {
250262
}
251263
}
252264

265+
if (settings.podfileAddUseFrameworks) {
266+
GUILayout.BeginHorizontal();
267+
GUILayout.Label("Enable Swift Framework Support Workaround",
268+
EditorStyles.boldLabel);
269+
settings.swiftFrameworkSupportWorkaroundEnabled =
270+
EditorGUILayout.Toggle(settings.swiftFrameworkSupportWorkaroundEnabled);
271+
GUILayout.EndHorizontal();
272+
GUILayout.Label("This workround patches the Xcode project to properly link Swift " +
273+
"Standard Library when some plugins depend on Swift Framework " +
274+
"pods by:");
275+
GUILayout.Label("1. Add a dummy Swift file to Xcode project.");
276+
GUILayout.Label("2. Enable 'CLANG_ENABLE_MODULES' and " +
277+
"'ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES' build settings and set " +
278+
"'SWIFT_VERSION' to the value below.");
279+
280+
if (settings.swiftFrameworkSupportWorkaroundEnabled) {
281+
GUILayout.BeginHorizontal();
282+
GUILayout.Label("Swift Framework Version",
283+
EditorStyles.boldLabel);
284+
settings.swiftLanguageVersion =
285+
EditorGUILayout.TextField(settings.swiftLanguageVersion);
286+
GUILayout.EndHorizontal();
287+
GUILayout.Label("Used to set 'SWIFT_VERSION' build setting in Xcode. Leave " +
288+
"it blank to update it manually.");
289+
}
290+
}
291+
253292
GUILayout.Box("", GUILayout.ExpandWidth(true), GUILayout.Height(1));
254293
}
255294

@@ -265,8 +304,11 @@ public void OnGUI() {
265304
settings.useProjectSettings = EditorGUILayout.Toggle(settings.useProjectSettings);
266305
GUILayout.EndHorizontal();
267306

268-
GUILayout.Space(10);
307+
EditorGUILayout.EndScrollView();
308+
GUILayout.EndVertical();
269309

310+
GUILayout.BeginVertical();
311+
GUILayout.Space(10);
270312
if (GUILayout.Button("Reset to Defaults")) {
271313
// Load default settings into the dialog but preserve the state in the user's
272314
// saved preferences.
@@ -316,6 +358,12 @@ public void OnGUI() {
316358
new KeyValuePair<string, string>(
317359
"podfileAllowPodsInMultipleTargets",
318360
IOSResolver.PodfileAllowPodsInMultipleTargets.ToString()),
361+
new KeyValuePair<string, string>(
362+
"swiftFrameworkSupportWorkaroundEnabled",
363+
IOSResolver.SwiftFrameworkSupportWorkaroundEnabled.ToString()),
364+
new KeyValuePair<string, string>(
365+
"swiftLanguageVersion",
366+
IOSResolver.SwiftLanguageVersion.ToString()),
319367
},
320368
"Settings Save");
321369
settings.Save();

0 commit comments

Comments
 (0)