@@ -21,53 +21,19 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2121#if UNITY_IOS
2222
2323using System ;
24- using System . Linq ;
24+
2525using System . Collections . Generic ;
2626using System . IO ;
27- using System . Text ;
2827
29- using UnityEngine ;
3028using UnityEditor ;
3129using UnityEditor . Callbacks ;
32- using UnityEditor . iOS . Xcode ;
33- using Application = UnityEngine . Application ;
30+
3431
3532/// <summary>
3633/// Adding this post build script to Unity project enables the flutter-unity-widget to access it
3734/// </summary>
3835public static class XcodePostBuild
3936{
40- /// <summary>
41- /// Path to the root directory of Xcode project.
42- /// This should point to the directory of '${XcodeProjectName}.xcodeproj'.
43- /// It is recommended to use relative path here.
44- /// Current directory is the root directory of this Unity project, i.e. the directory of 'Assets' folder.
45- /// Sample value: "../xcode"
46- /// </summary>
47- private const string XcodeProjectRoot = "../../ios" ;
48-
49- /// <summary>
50- /// Name of the Xcode project.
51- /// This script looks for '${XcodeProjectName} + ".xcodeproj"' under '${XcodeProjectRoot}'.
52- /// Sample value: "DemoApp"
53- /// </summary>
54- private static string XcodeProjectName = Application . productName ;
55-
56- /// <summary>
57- /// Directories, relative to the root directory of the Xcode project, to put generated Unity iOS build output.
58- /// </summary>
59- private static string ClassesProjectPath = "UnityExport/Classes" ;
60- private static string LibrariesProjectPath = "UnityExport/Libraries" ;
61- private static string DataProjectPath = "UnityExport/Data" ;
62-
63- /// <summary>
64- /// Path, relative to the root directory of the Xcode project, to put information about generated Unity output.
65- /// </summary>
66- private static string ExportsConfigProjectPath = "UnityExport/Exports.xcconfig" ;
67-
68- private static string PbxFilePath = XcodeProjectName + ".xcodeproj/project.pbxproj" ;
69-
70- private const string BackupExtension = ".bak" ;
7137
7238 /// <summary>
7339 /// The identifier added to touched file to avoid double edits when building to existing directory without
@@ -84,144 +50,48 @@ public static void OnPostBuild(BuildTarget target, string pathToBuiltProject)
8450 }
8551
8652 PatchUnityNativeCode ( pathToBuiltProject ) ;
87-
88- }
89-
90- /// <summary>
91- /// Update pbx project file by adding src files and removing extra files that
92- /// exists in dest but not in src any more.
93- ///
94- /// This method only updates the pbx project file. It does not copy or delete
95- /// files in Swift Xcode project. The Swift Xcode project will do copy and delete
96- /// during build, and it should copy files if contents are different, regardless
97- /// of the file time.
98- /// </summary>
99- /// <param name="pbx">The pbx project.</param>
100- /// <param name="src">The directory where Unity project is built.</param>
101- /// <param name="dest">The directory of the Swift Xcode project where the
102- /// Unity project is embedded into.</param>
103- /// <param name="projectPathPrefix">The prefix of project path in Swift Xcode
104- /// project for Unity code files. E.g. "DempApp/Unity/Classes" for all files
105- /// under Classes folder from Unity iOS build output.</param>
106- private static void ProcessUnityDirectory ( PBXProject pbx , string src , string dest , string projectPathPrefix )
107- {
108- var targetGuid = pbx . TargetGuidByName ( XcodeProjectName ) ;
109- if ( string . IsNullOrEmpty ( targetGuid ) ) {
110- throw new Exception ( string . Format ( "TargetGuid could not be found for '{0}'" , XcodeProjectName ) ) ;
111- }
112-
113- // newFiles: array of file names in build output that do not exist in project.pbx manifest.
114- // extraFiles: array of file names in project.pbx manifest that do not exist in build output.
115- // Build output files that already exist in project.pbx manifest will be skipped to minimize
116- // changes to project.pbx file.
117- string [ ] newFiles , extraFiles ;
118- CompareDirectories ( src , dest , out newFiles , out extraFiles ) ;
119-
120- foreach ( var f in newFiles )
121- {
122- if ( ShouldExcludeFile ( f ) )
123- {
124- continue ;
125- }
126-
127- var projPath = Path . Combine ( projectPathPrefix , f ) ;
128- if ( ! pbx . ContainsFileByProjectPath ( projPath ) )
129- {
130- var guid = pbx . AddFile ( projPath , projPath ) ;
131- pbx . AddFileToBuild ( targetGuid , guid ) ;
132-
133- Debug . LogFormat ( "Added file to pbx: '{0}'" , projPath ) ;
134- }
135- }
136-
137- foreach ( var f in extraFiles )
138- {
139- var projPath = Path . Combine ( projectPathPrefix , f ) ;
140- if ( pbx . ContainsFileByProjectPath ( projPath ) )
141- {
142- var guid = pbx . FindFileGuidByProjectPath ( projPath ) ;
143- pbx . RemoveFile ( guid ) ;
144-
145- Debug . LogFormat ( "Removed file from pbx: '{0}'" , projPath ) ;
146- }
147- }
148- }
149-
150- /// <summary>
151- /// Compares the directories. Returns files that exists in src and
152- /// extra files that exists in dest but not in src any more.
153- /// </summary>
154- private static void CompareDirectories ( string src , string dest , out string [ ] srcFiles , out string [ ] extraFiles )
155- {
156- srcFiles = GetFilesRelativePath ( src ) ;
157-
158- var destFiles = GetFilesRelativePath ( dest ) ;
159- var extraFilesSet = new HashSet < string > ( destFiles ) ;
160-
161- extraFilesSet . ExceptWith ( srcFiles ) ;
162- extraFiles = extraFilesSet . ToArray ( ) ;
163- }
164-
165- private static string [ ] GetFilesRelativePath ( string directory )
166- {
167- var results = new List < string > ( ) ;
168-
169- if ( Directory . Exists ( directory ) )
170- {
171- foreach ( var path in Directory . GetFiles ( directory , "*" , SearchOption . AllDirectories ) )
172- {
173- var relative = path . Substring ( directory . Length ) . TrimStart ( '/' ) ;
174- results . Add ( relative ) ;
175- }
176- }
177-
178- return results . ToArray ( ) ;
179- }
180-
181- private static bool ShouldExcludeFile ( string fileName )
182- {
183- if ( fileName . EndsWith ( ".bak" , StringComparison . OrdinalIgnoreCase ) )
184- {
185- return true ;
186- }
187-
188- return false ;
18953 }
19054
19155 /// <summary>
19256 /// Make necessary changes to Unity build output that enables it to be embedded into existing Xcode project.
19357 /// </summary>
19458 private static void PatchUnityNativeCode ( string pathToBuiltProject )
19559 {
196- EditMainMM ( Path . Combine ( pathToBuiltProject , "Classes/main.mm " ) ) ;
60+ EditUnityFrameworkH ( Path . Combine ( pathToBuiltProject , "UnityFramework/UnityFramework.h " ) ) ;
19761 EditUnityAppControllerH ( Path . Combine ( pathToBuiltProject , "Classes/UnityAppController.h" ) ) ;
19862 EditUnityAppControllerMM ( Path . Combine ( pathToBuiltProject , "Classes/UnityAppController.mm" ) ) ;
199-
200- if ( Application . unityVersion == "2017.1.1f1" )
201- {
202- EditMetalHelperMM ( Path . Combine ( pathToBuiltProject , "Classes/Unity/MetalHelper.mm" ) ) ;
203- }
204-
205- // TODO: Parse unity version number and do range comparison.
206- if ( Application . unityVersion . StartsWith ( "2017.3.0f" ) || Application . unityVersion . StartsWith ( "2017.3.1f" ) )
207- {
208- EditSplashScreenMM ( Path . Combine ( pathToBuiltProject , "Classes/UI/SplashScreen.mm" ) ) ;
209- }
21063 }
21164
65+
21266 /// <summary>
213- /// Edit 'main.mm ': removes 'main' entry that would conflict with the Xcode project it embeds into.
67+ /// Edit 'UnityFramework.h ': add 'frameworkWarmup'
21468 /// </summary>
215- private static void EditMainMM ( string path )
69+ private static void EditUnityFrameworkH ( string path )
21670 {
71+ var inScope = false ;
72+
73+ // Add frameworkWarmup method
21774 EditCodeFile ( path , line =>
21875 {
219- if ( line . TrimStart ( ) . StartsWith ( "int main" , StringComparison . Ordinal ) )
76+ inScope |= line . Contains ( "- (void)runUIApplicationMainWithArgc:" ) ;
77+
78+ if ( inScope )
22079 {
221- return line . Replace ( "int main" , "int old_main" ) ;
80+ if ( line . Trim ( ) == "" )
81+ {
82+ inScope = false ;
83+
84+ return new string [ ]
85+ {
86+ "" ,
87+ "// Added by " + TouchedMarker ,
88+ "- (void)frameworkWarmup:(int)argc argv:(char*[])argv;" ,
89+ ""
90+ } ;
91+ }
22292 }
22393
224- return line ;
94+ return new string [ ] { line } ;
22595 } ) ;
22696 }
22797
@@ -264,11 +134,11 @@ private static void EditUnityAppControllerH(string path)
264134 // Modify inline GetAppController
265135 EditCodeFile ( path , line =>
266136 {
267- inScope |= line . Contains ( "inline UnityAppController" ) ;
137+ inScope |= line . Contains ( "extern UnityAppController* GetAppController " ) ;
268138
269139 if ( inScope && ! markerDetected )
270140 {
271- if ( line . Trim ( ) == "} " )
141+ if ( line . Trim ( ) == "" )
272142 {
273143 inScope = false ;
274144 markerDetected = true ;
@@ -284,21 +154,13 @@ private static void EditUnityAppControllerH(string path)
284154 } ;
285155 }
286156
287- if ( ! markerAdded )
288- {
289- markerAdded = true ;
290- return new string [ ]
291- {
292- "// Modified by " + TouchedMarker ,
293- "// " + line ,
294- } ;
295- }
296-
297157 return new string [ ] { "// " + line } ;
298158 }
299159
300160 return new string [ ] { line } ;
301161 } ) ;
162+
163+
302164 }
303165
304166 /// <summary>
@@ -356,100 +218,35 @@ private static void EditUnityAppControllerMM(string path)
356218
357219 return new string [ ] { line } ;
358220 } ) ;
359- }
360-
361- /// <summary>
362- /// Edit 'MetalHelper.mm': fixes a bug (only in 2017.1.1f1) that causes crash.
363- /// </summary>
364- private static void EditMetalHelperMM ( string path )
365- {
366- var markerDetected = false ;
367-
368- EditCodeFile ( path , line =>
369- {
370- markerDetected |= line . Contains ( TouchedMarker ) ;
371-
372- if ( ! markerDetected && line . Trim ( ) == "surface->stencilRB = [surface->device newTextureWithDescriptor: stencilTexDesc];" )
373- {
374- return new string [ ]
375- {
376- "" ,
377- " // Modified by " + TouchedMarker ,
378- " // Default stencilTexDesc.usage has flag 1. In runtime it will cause assertion failure:" ,
379- " // validateRenderPassDescriptor:589: failed assertion `Texture at stencilAttachment has usage (0x01) which doesn't specify MTLTextureUsageRenderTarget (0x04)'" ,
380- " // Adding MTLTextureUsageRenderTarget seems to fix this issue." ,
381- " stencilTexDesc.usage |= MTLTextureUsageRenderTarget;" ,
382- line ,
383- } ;
384- }
385-
386- return new string [ ] { line } ;
387- } ) ;
388- }
389221
390- /// <summary>
391- /// Edit 'SplashScreen.mm': Unity introduces its own 'LaunchScreen.storyboard' since 2017.3.0f3.
392- /// Disable it here and use Swift project's launch screen instead.
393- /// </summary>
394- private static void EditSplashScreenMM ( string path ) {
395- var markerDetected = false ;
396- var markerAdded = false ;
397- var inScope = false ;
398- var level = 0 ;
222+ inScope = false ;
223+ markerDetected = false ;
399224
225+ // Modify inline GetAppController
400226 EditCodeFile ( path , line =>
401227 {
402- inScope |= line . Trim ( ) == "void ShowSplashScreen(UIWindow* window)" ;
403- markerDetected |= line . Contains ( TouchedMarker ) ;
228+ inScope |= line . Contains ( "UnityAppController* GetAppController()" ) ;
404229
405230 if ( inScope && ! markerDetected )
406231 {
407- if ( line . Trim ( ) == "{" )
408- {
409- level ++ ;
410- }
411- else if ( line . Trim ( ) == "}" )
412- {
413- level -- ;
414- }
415-
416- if ( line . Trim ( ) == "}" && level == 0 )
232+ if ( line . Trim ( ) == "}" )
417233 {
418234 inScope = false ;
419- }
235+ markerDetected = true ;
420236
421- if ( level > 0 && line . Trim ( ) . StartsWith ( "bool hasStoryboard" ) )
422- {
423237 return new string [ ]
424238 {
425- " // " + line ,
426- " bool hasStoryboard = false;" ,
239+ "" ,
427240 } ;
428241 }
429242
430- if ( ! markerAdded )
431- {
432- markerAdded = true ;
433- return new string [ ]
434- {
435- "// Modified by " + TouchedMarker ,
436- line ,
437- } ;
438- }
243+ return new string [ ] { "// " + line } ;
439244 }
440245
441246 return new string [ ] { line } ;
442247 } ) ;
443248 }
444249
445- private static void EditCodeFile ( string path , Func < string , string > lineHandler )
446- {
447- EditCodeFile ( path , line =>
448- {
449- return new string [ ] { lineHandler ( line ) } ;
450- } ) ;
451- }
452-
453250 private static void EditCodeFile ( string path , Func < string , IEnumerable < string > > lineHandler )
454251 {
455252 var bakPath = path + ".bak" ;
0 commit comments