2015年9月22日 星期二

Unity:解決 Unity 5.2 無法 Build 到 iOS 的問題

最近在開發的專案,自從安裝 Unity 5.2 之後,就沒有 Build 到 iOS 行動裝置測試過,最近因為 Xcode 7 發佈,就想 Build 測試看看是否有需要調整的地方,結果,卻卡在 Unity 要 Build 成 Xcode 專案的地方就發生錯誤,網路上找不到相關的解決辦法,幸好,最後有解決了,所以,在此記錄下來,希望可以幫助到有同樣困擾的朋友們。

這個問題,主要發生在 Player Settings 的 Scripting Backend 設置為 IL2CPP 來 Build 時,而且,並不是每個專案都會發生這個問題,如果,Scripting Backend 選擇 Mono2x 則完全不會發生這個問題,這應該是 Unity 5.2 的 Bug。

當 Build 到 iOS 時,在 Build 期間,Building Player 的進度條下方會顯示簡短的訊息,通常會依序看到正在 Building 哪個 scene 的訊息,當 scene 都 Build 結束之後,到出現 Postprocessing Player 這個階段即被終止並在 Console 視窗看到類似以下三個錯誤訊息,那麼,可能就是遇到相同的問題。

Build 到這個階段,會馬上中斷並出現錯誤訊息。
第一個 Error:
Failed running /Applications/Unity/Unity.app/Contents/Frameworks/Tools/UnusedByteCodeStripper2/UnusedBytecodeStripper2.exe -out "/Users/ [Project Path] /Temp/StagingArea/Data/Managed/tempStrip" -l none -c link -x "/Applications/Unity/Unity.app/Contents/Frameworks/Tools/UnusedByteCodeStripper/native_link.xml" -f "/Applications/Unity/Unity.app/Contents/Frameworks/il2cpp/LinkerDescriptors" -x "/Users/ [Project Path] /Temp/StagingArea/Data/Managed/../platform_native_link.xml" -x "/Users/ [Project Path] /Temp/StagingArea/Data/methods_pointedto_by_uievents.xml" -d "/Users/ [Project Path] /Temp/StagingArea/Data/Managed"

stdout:
ERROR: Failed to resolve base type System.Security.Principal.GenericIdentity for type System.Net.HttpListenerBasicIdentity
Fatal error in Mono CIL Linker
System.Exception: ERROR: Failed to resolve base type System.Security.Principal.GenericIdentity for type System.Net.HttpListenerBasicIdentity
  at UnusedBytecodeStripper2.ResolveFromMonoBehaviours.IsMonoBehaviourOrScriptableObject (Mono.Cecil.TypeDefinition type) [0x00000] in <filename unknown>:0
  at System.Linq.Enumerable+<CreateWhereIterator>c__Iterator1E`1[Mono.Cecil.TypeDefinition].MoveNext () [0x00000] in <filename unknown>:0
  at UnusedBytecodeStripper2.ResolveFromMonoBehaviours.Process (Mono.Linker.LinkContext context) [0x00000] in <filename unknown>:0
  at Mono.Linker.Pipeline.Process (Mono.Linker.LinkContext context) [0x00000] in <filename unknown>:0
  at Mono.Linker.Driver.Run () [0x00000] in <filename unknown>:0
  at Mono.Linker.Driver.RunDriver (Mono.Linker.Driver driver) [0x00000] in <filename unknown>:0
stderr:

UnityEngine.Debug:LogError(Object)
UnityEditorInternal.Runner:RunManagedProgram(String, String, String, CompilerOutputParserBase) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:66)
UnityEditorInternal.AssemblyStripper:RunAssemblyLinker(IEnumerable`1, String&, String&, String, String) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:192)
UnityEditorInternal.AssemblyStripper:StripAssembliesTo(String, String, String&, String&, String, String, IEnumerable`1) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:185)
UnityEditorInternal.AssemblyStripper:Strip(String, String, String&, String&, String, String, IEnumerable`1) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:136)
UnityEditorInternal.AssemblyStripper:Strip(String[], String[], String, String, String&, String&, String, String, IEnumerable`1) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:121)
UnityEditorInternal.IL2CPPBuilder:RunAssemblyStripper(IEnumerable, String, String[], String[], String) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:444)
UnityEditorInternal.IL2CPPBuilder:StripAssemblies(IEnumerable`1, String) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:417)
UnityEditorInternal.IL2CPPBuilder:Run() (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:291)
UnityEditorInternal.IL2CPPUtils:RunIl2Cpp(String, String, IIl2CppPlatformProvider, Action`1, RuntimeClassRegistry) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:211)
UnityEditor.HostView:OnGUI()

第一道錯誤訊息(點擊圖片放大)
第二個 Error:
Exception: /Applications/Unity/Unity.app/Contents/Frameworks/Tools/UnusedByteCodeStripper2/UnusedBytecodeStripper2.exe did not run properly!
UnityEditorInternal.Runner.RunManagedProgram (System.String exe, System.String args, System.String workingDirectory, UnityEditor.Scripting.Compilers.CompilerOutputParserBase parser) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:68)
UnityEditorInternal.AssemblyStripper.RunAssemblyLinker (IEnumerable`1 args, System.String& out, System.String& err, System.String linkerPath, System.String workingDirectory) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:192)
UnityEditorInternal.AssemblyStripper.StripAssembliesTo (System.String outputFolder, System.String workingDirectory, System.String& output, System.String& error, System.String linkerPath, System.String descriptorsFolder, IEnumerable`1 additionalBlacklist) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:185)
UnityEditorInternal.AssemblyStripper.Strip (System.String outputFolder, System.String workingDirectory, System.String& output, System.String& error, System.String monoLinkerPath, System.String descriptorsFolder, IEnumerable`1 additionalBlacklist) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:136)
UnityEditorInternal.AssemblyStripper.Strip (System.String[] assemblies, System.String[] searchDirs, System.String outputFolder, System.String workingDirectory, System.String& output, System.String& error, System.String monoLinkerPath, System.String descriptorsFolder, IEnumerable`1 additionalBlacklist) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:121)
UnityEditorInternal.IL2CPPBuilder.RunAssemblyStripper (IEnumerable assemblies, System.String managedAssemblyFolderPath, System.String[] assembliesToStrip, System.String[] searchDirs, System.String monoLinkerPath) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:444)
UnityEditorInternal.IL2CPPBuilder.StripAssemblies (IEnumerable`1 assemblies, System.String managedAssemblyFolderPath) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:417)
UnityEditorInternal.IL2CPPBuilder.Run () (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:291)
UnityEditorInternal.IL2CPPUtils.RunIl2Cpp (System.String tempFolder, System.String stagingAreaData, IIl2CppPlatformProvider platformProvider, System.Action`1 modifyOutputBeforeCompile, UnityEditor.RuntimeClassRegistry runtimeClassRegistry) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/Il2Cpp/IL2CPPUtils.cs:211)
UnityEditor.iOS.PostProcessiPhonePlayer.PostProcess (UnityEditor.iOS.iOSBuildPostprocessor pp, BuildTarget target, System.String stagingAreaData, System.String stagingArea, System.String stagingAreaDataManaged, System.String playerPackage, System.String installPath, System.String companyName, System.String productName, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry)
UnityEditor.iOS.iOSBuildPostprocessor.PostProcess (BuildPostProcessArgs args)
UnityEditor.PostprocessBuildPlayer.Postprocess (BuildTarget target, System.String installPath, System.String companyName, System.String productName, Int32 width, Int32 height, System.String downloadWebplayerUrl, System.String manualDownloadWebplayerUrl, BuildOptions options, UnityEditor.RuntimeClassRegistry usedClassRegistry) (at /Users/builduser/buildslave/unity/build/Editor/Mono/BuildPipeline/PostprocessBuildPlayer.cs:316)
UnityEditor.HostView:OnGUI()

第二道錯誤訊息(點擊圖片放大)
第三個 Error:
Error building Player: Exception: /Applications/Unity/Unity.app/Contents/Frameworks/Tools/UnusedByteCodeStripper2/UnusedBytecodeStripper2.exe did not run properly!

第三道錯誤訊息(點擊圖片放大)
我們從 Unity 5.2 的更新項目(http://unity3d.com/unity/whats-new/unity-5.2)中可以看到有一項改變「IL2CPP: Make engine stripping in iOS/WebGL a separate setting (PlayerSettings.stripEngineCode) from Mono stripping levels」,所以在 Unity 5.1.3 以前,原本 Player Settings 的 Stripping Level 選項,在 Unity 5.2 有些改變了;至於,Stripping Level 欄位的用途,可以參考官方文件裡有關改善 Build Size 相關的資訊「Optimizing the Size of the Built iOS Player」。



在 Unity 5.2,Player Settings 的 iOS 設置裡,Stripping Level 只有在 Scripting Backed 選擇 Mono2x 時才會出現,如果是選擇 IL2CPP 的話,Stripping Level 欄位的位置則會變成 Strip Engine Code 欄位。
在 Unity 5.1.3 時,Scripting Backend 選擇 IL2CPP,還有 Stripping Level 欄位選項。
在 Unity 5.2,Scripting Backend 選擇 IL2CPP,Stripping Level 欄位變為 Strip Engine Code 欄位。
這並非只是 Unity 編輯器上顯示方式不同而已,在專案的 ProjectSettings/ProjectSettings.asset 設定檔裡面,它們是個別獨立的設定值(stripEngineCode 與 iPhoneStrippingLevel),而問題就是出在這裡,如果,專案原本在升級到 Unity 5.2 之前,Stripping Level 已經選擇為 Use micro mscorlib,而當時的 Scripting Backend 是選擇 IL2CPP 的話,那麼在 Unity 5.2 的時候,Player Settings 裡就會只看到 Strip Engine Code 的欄位,可是不管這個欄位有沒有選取, Build 到 Postprocess Player 階段就會發生錯誤而無法繼續進行下去。

發生一長串的錯誤訊息,使用這些資料,上網查找到類似的資訊,最多就是看到要去確認所使用的 Plugin 是否支援 IL2CPP 而已,但如果專案內容都沒使用到其他 Plugin 的話,那就沒有頭緒了,因為問題發生在 Player Settings,所以,即使將整個 Project 視窗內的檔案全刪光,也是會出現相同的錯誤。

這個問題主要是 Stripping Level 被設置為 Use micro mscorlib 時,而 Scripting Backed 選擇 IL2CPP 去 Build 才會發生,所以,解決的辦法就是先把 Scripting Backed 選擇為 Mono2x,然後,將 Stripping Level 選擇其他的選項(不要設為 Use micro mscorlib 就可以),然後,將 Scripting Backed 選擇回 IL2CPP 再去 Build 就可以成功了。

如果原本選擇 Use micro mscorlib 的話,在 Unity 5.2 使用 IL2CPP 去 Build 就會出問題。
將 Scripting Backend 選擇 Mono2x,Stripping Level  選擇 Use micro mscorlib 以外的選項。
雖然,問題得以解決了,最後使用 Xcode 7 Build 到行動裝置上也都可以正常動作,不過在 Build 完成之後,在 Unity 的 Console 視窗中還是會額外出現 2 個相同的 Warning:

Unknown file extension: .dat
UnityEditor.HostView:OnGUI()

還是有奇怪的 Warning。
目前,還無法得知這是什麼意思,以及該如何解決,如果,有任何朋友有相關的資訊或問題,歡迎來粉絲專頁留言討論 ^_^
https://www.facebook.com/RandomExp/posts/1635858593335784

如果,喜歡「胡亂說・隨便寫」所提供的資訊,記得來幫忙按個讚哦~