最近又重新回去做一些有關於 Unity 的 Continuous integration 有關的研究,之前卡住的點是在於 Unity 產生出來的 Xcode Project 可能會有一些設定沒有弄好,然後要手工去設定。當然這在 CI 裡面是不能接受的。不過當時一忙就沒有研究下去了,剛好最近 Unity Cloud Build 使用的人變多,也有很多人有同樣的需求,所以就把官方的討論整理一下貼上來。
自動設定 Xcode 的好處主要有
- 給 CI 系統使用
- 避免人為操作失誤造成 build 出去的 binary 有問題
不過麻煩的點就在於 Apple 官方沒有給出操作 Xcode Project 的 API,目前有一些第三方做的 API 像是使用 Ruby 的 CocoaPods/Xcodeproj:
https://github.com/CocoaPods/Xcodeproj
使用 obj-C 的 appsquickly/XcodeEditor:
https://github.com/appsquickly/XcodeEditor
然後 C# 有 Unity 官方做的 Xcode Manipulation API:
https://bitbucket.org/Unity-Technologies/xcodeapi
文件在:
http://docs.unity3d.com/ScriptReference/iOS.Xcode.PBXProject.html
使用 C# 應該是最方便我們使用的,不過可惜的是這個 API 功能並不完全,在處理 Entitlement 的時候我們還是要自己手動做一點字串取代。
安裝 Xcode Manipulation API
如果你是 Unity 5 的使用者的話 Xcode Manipulation API 已經包含在 UnityEditor 裡面了,Unity 4 的使用者需要去上面的 Bitbucket 網址 clone 原始檔,放在自己 Unity 專案底下的某個 Editor 資料夾下。然後要注意 xcodeapi 底下 Utils.cs 的 class UnityEditor.iOS.Xcode.PBX.Utils 會跟 Unity 4 底下的 UnityEditor.Utils 衝突。要把 UnityEditor.iOS.Xcode.PBX.Utils 改成別的名字。
Xcode 專案結構
Build 完設定完的 Xcode Project 大概會長的像這樣,我們要操作的內容主要是 Info.plist、Unity-iPhone 底下的 .entitlements、還有 Unity-iPhone.xcodeproj。xcodeproj 是一個 package ,右鍵點選選 Show Package Content 可以看到 project.pbxproj。
Info.plist、.entitlements、還有 project.pbxproj 這三個就是我們主要操作的對象。
PostProcessBuild
PostProcessBuild 這個 attribute 修飾的 static function 會在 Unity 建置完之後被呼叫。這個函式需要接受兩個參數,一個是 BuildTarget enum ,代表建置的目標平台。另一個是 string 是建置的目標目錄。
一般的設定會像這樣:
|
|
PostProcessBuild 可以帶一個數字參數代表執行順序,但是詭異的是 Unity 沒有 PreProcessBuild 有時候會造成一些不便。
PostProcessBuild 的參數在這裡:
http://docs.unity3d.com/ScriptReference/Callbacks.PostProcessBuildAttribute.html
增加 Required Device Capability
預設的 Unity Xcode 專案會開 Game Center 的 Entitlements 但是沒有把 gamekit 加到 Required device capability 裡面,所以開起來會跳 issue ,解決方法是把它加進 Info.plist。
這邊用的是 Unity Manipulation API ,code 大概像是下面這樣:
|
|
大致上就是用 PlistDocument 開啟 Info.plist ,加入 UIRequiredDeviceCapabilities 這個屬性,然後在上面加入 gamekit。因為實驗結果 Xcode Manipulation API 會做一個覆寫的動作,所以原本存在的 armv7 也要加回去。然後如果你的 app 有需要其他的 Required device capability 也都在這裡可以加。
[Xcode 7/iOS9] Require Full Screen
在 Xcode 7 裡面有新增了一個 Require full screen 的選項,意思是宣告你的 app 不想讓使用者在 iOS 9 新的分割視窗裡面被開啟。
一般的遊戲應該都會設定成 yes ,這個設定也在 Info.plist ,key 值是 UIRequiresFullScreen
|
|
增加引入的 Framework
如果說你的 app 需要加入別的 .framework ,這個需要用 Xcode Manipulation API 的 PBXProject 開啟 project.pbxproj
|
|
weak 參數是設定這個 framework 是 required 還是 optional。
iCloud
因為接下來的操作 Xcode Manipulation API 不支援,所以就要搞很髒的字串替換了。
建議將 Unity 剛剛建置完的 Xcode 專案複製一份起來,然後用 Xcode 打開 iCloud 的 Entitlement ,拿打開之前跟打開之後的 project.pbxproj 做 diff。
首先是 Unity-iPhone 底下的 .entitlements 檔。這個建議就直接複製出來,然後在 PostProcessing 腳本裡面複製回 Unity-iPhone 。
接下來就是要把這個 .entitlements 檔案加到 project.pbxproj。因為每個 PBXProject 的元素前面有一組 24 位的 hex code,然後沒有人知道 Xcode 是怎麼產生的。所以只能乖乖的比對開啟跟沒開啟 iCloud 的 PBXProject 然後填回去。
首先是 Unity-iPhone PBXFileReference
搜尋目標是:
|
|
取代成
|
|
你的 hex code 跟 .entitlements 檔案名稱不會一樣,要用你的專案裡面看到的為準。建議在字串前面加 @ 作為 verbatim string,這樣就可以直接從 pbxproj 裡面複製出來把 "
跳脫成 ""
就可以拿來比對了。不用自己再把換行換成 \n
tab 換成 \t
。
然後是 Custom template 要把:
|
|
取代成
|
|
Target Attribute:
|
|
取代成
|
|
一樣那個 hex code 跟那個 DevelopmentTeam 還是以你在啟用過 iCloud 的 PBXProject 版本為準。
最後是要在 XCBuildConfiguration section 底下的 buildSettings 加入 CODE_SIGN_ENTITLEMENTS。這個我是隨便找一個 build settings 然後直接黏在它後面。
例如選擇用:
|
|
取代成:
|
|
這樣就大功告成了。
P.S. 原來在 Unity 論壇上面原作者還有手動加入 CloudKit.framework ,不過我照做反而 Link fail,不做就編過了。這邊不太確定是怎麼回事。如果在你的機器上會跳 CloudKit 的 Link fail 的話就試著加加看吧。
[Xcode 7] Bitcode
Bitcode 是 Apple 新的 App thinning 機制所需的編譯方式,不過因為絕大多數既有的 Plugin 都還沒有改成使用 Bitcode 編譯,所以我們也沒辦法開啟。
關閉的方法是在 build settings 加入
|
|
方法跟 CODE_SIGN_ENTITLEMENTS 一樣。
希望大家也 Happy building 啦
參考資料
PBXProject 格式參考資料(非官方):
http://www.monobjc.net/xcode-project-file-format.html
iCloud 的開啟方式是參考這篇論壇文章:
http://forum.unity3d.com/threads/icloud-with-cloud-build.303844/#post-2266181
這邊是 Unity Cloud Build 的集中討論串,裡面有一區 Xcode 操作的討論。