系列傳送門
IOS:
IOS:使用shell命令打包并上傳Itunes
Unity3d:
Unity3d:Canvas適配屏幕分辨率與錨點(Anchors與Pivot)
Unity3d:在屏幕邊緣顯示其他玩家方位
Unity3d:命令行打包Android
Unity3d:命令行編譯IOS
Unity3d:使用Jenkins自動編譯打包IOS(只能打包Development)
Unity3d:使用Jenkins自動編譯打包IOS(打包Ad-hoc,上傳itunes)
安裝并配置Jenkns
1. 下載完后,安裝
官網(wǎng):https://jenkins.io/
2. 修改jenkins啟動用戶
參考:http://www.xuanyusong.com/archives/3349
安裝完之后jenkins會自動啟動,而且使用root用戶啟動的,這會在構建時造成一些麻煩,比如執(zhí)行權限,文件訪問權限等
所以需要把jenkins先關閉,然后修改jenkins的啟動用戶和當前登陸系統(tǒng)的用戶一致
- 停止jenkins
sudo launchctl unload /Library/LaunchDaemons/org.jenkins-ci.plis
- 修改org.jenkins-ci.plis文件
- 修改GroupName和當前登陸系統(tǒng)的用戶的Group Name一致
- 修改UserName和當前登陸系統(tǒng)的用戶的User Name一致
- 啟動jenkins
不推薦:launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist
推薦: java -jar jenkins.war
3. 訪問http://127.0.0.1:8008
打開網(wǎng)頁后,會讓輸入安裝密碼,這個密碼在:
/User/當前系統(tǒng)登陸用戶/.jenkins/secrets/initialAdminPassword
然后下一步配置Jenkins網(wǎng)頁的登陸密碼,信息要全部填寫完成后,會提示安裝插件,直接選安裝推薦的插件
4. 安裝我們構建打包需要插件
安裝時,記得勾選自動重啟jenkins
- Unity3d Plugin
- Xcode Integration:該插件只能打development的ipa包,不能打ad-hoc和app-store的包,也不能上傳iTunes
- Keychains and Provisioning Profiles Plugin
- Perforce Plugin(可選,如果Unity3d項目源代碼用Perforce管理,可以使用該插件)
5. 設置插件配置
配置Xcode Builder
進入jenkins主頁->左側系統(tǒng)管理->系統(tǒng)設置->Xcode Builder
Xcode路徑之類的,插件會自動補充,無需填寫
- Development Team(可選,配置構建時可自己指定)
- Team Name:***********(可以在開發(fā)者后臺查到)
- Team ID:***********(可以在開發(fā)者后臺查到)
- keychains
- keychain Name:login.keychain(自己隨便定義)
- keychain Path:/Users/當前系統(tǒng)登陸用戶/Library/Keychains/login.keychain(路徑中包括xxxx.keychain文件)
- keychain Password:********(當前系統(tǒng)登陸用戶的密碼)
配置Unity3d
進入jenkins主頁->左側系統(tǒng)管理->全局工具配置->Unity3d
- 別名:Unity3d(自己隨便定義)
- 安裝目錄:/Applications/Unity/Unity.app(注意:該插件會自己在后面拼接“Contents/MacOS”或“Editor/Unity.exe”)
配置Keychains and Provisioning Profiles Management
進入jenkins主頁->左側系統(tǒng)管理->全局工具配置->Keychains and Provisioning Profiles Management
證書說明:
- ios_development.cer:需要從開發(fā)者后臺下載(左側certificate欄目里)
- xxxxxxx.mobileprovision(有development版(這里用開發(fā)版),ad-hoc的distribution版,正式distribution版):需要從開發(fā)者后臺下載(左側Provisioning Profiles欄目里)
- xxxxxxx.developerprofile:需要從Xcode中導出(Xcode->Preferences->Accounts(需要在這里先登陸開發(fā)者賬號)->左下角齒輪按鈕->Export Apple ID And Code Signing Assets)
- 上傳login.keychain
- 配置Keychains
- Filename:login.keychain(會自動填寫)
- Password:當前系統(tǒng)登陸用戶的密碼
- Description:(自己隨便定義)
- Identities:
- Code Sign Identity:iPhone Developer:XXXXXX(鑰匙串中,蘋果開發(fā)者證書簡介信息中的常用名稱,打開系統(tǒng)鑰匙串,把xxxxxxx.developerprofile復制進去即可)
- 配置Keychains
- 上傳xxxxxxx.mobileprovision
- 配置Provisioning Profiles
- Provisioning Profiles Directory Path:/Users/當前系統(tǒng)登陸用戶/Library/MobileDevice/Provisioning Profiiles
- Filename:(會自動填寫)
- UUID:(會自動填寫)
- 配置Provisioning Profiles
Jenkins配置結束
正式開工,創(chuàng)建構建
1. 創(chuàng)建構建
創(chuàng)建一個自由風格的軟件項目
- 項目名:Unity3d_Build_IOS(自己隨便定義)
2. 構建配置
修改workspace
默認workspace:
/Users/當前系統(tǒng)登陸用戶/.jenkins/workspace/Unity3d_Build_IOS(項目名)
頂部選項卡->General->高級選項->選擇“使用自定義的工作空間”
- 目錄:自定義的工作空間路徑
- 顯示名稱:Unity3dBuildXXX(如果填寫了,會覆蓋上面的項目名:Unity3d_Build_IOS)
配置Unity3d編譯相關
頂部選項卡->構建->增加構建步驟->選擇Invoke Unity3d Editor
- Unity3d installation name:Unity3d(會自動填寫,也就是在全局工具配置配置時寫的"Unity3d"別名)
- Editor conmmand line arguments:
-quit -batchmode -executeMethod PerformBuild.CommandLineBuild -projectPath 要編譯的unity3d項目目錄
插件參考:https://wiki.jenkins.io/display/JENKINS/Unity3dBuilder+Plugin
腳本參考:http://www.cnblogs.com/yinghuochong/archive/2013/09/01/3294940.html
命令參考:https://docs.unity3d.com/Manual/CommandLineArguments.html
項目腳本 PerformBuild.cs,寫好后 ,放在Editor目錄下
- 注意:腳本里寫的unity3d的IOS編譯輸出目錄一定要記得,后面會用得著
- 此處unity3d的IOS編譯輸出目錄為:/Users/當前系統(tǒng)登陸用戶/Documents/Project/build/iPhone
配置完成后,可以點擊“立即構建”進行測試,看unity3d項目編譯是否正常
點擊左下角構建記錄,進入該記錄信息頁,再點擊左側“Console Output”即可查看構建日志輸出
注意:從日志里看到,編譯時,有無權限刪除IOS編譯輸出目錄的問題,此時需要做以下配置:
頂部選項卡->構建->增加構建步驟->選擇Execute shell
Commands輸入:
rm -rf /Users/當前系統(tǒng)登陸用戶/Documents/Project/build/iPhone(unity3d的IOS編譯輸出目錄)
命令配置好后,把Execute shell拖到Invoke Unity3d Editor的前面,此時在Unity3d指定編譯之前,會先執(zhí)行配置的shell命令
配置IOS編譯相關
上面配置好并測試完成后,繼續(xù)配置Xcode編譯相關
頂部選項卡->構建環(huán)境->勾選Keychains and Code signing Identities
勾選即可,保存后,刷新即可看到內容被自動填充(也就是之前配置的全局工具配置->Keychains and Provisioning Profiles Management)
頂部選項卡->構建環(huán)境->勾選Mobile Provisioning Profiles
勾選即可,保存后,刷新即可看到內容被自動填充(也就是之前配置的全局工具配置->Keychains and Provisioning Profiles Management)
頂部選項卡->構建->增加構建步驟->選擇Xcode
配置General build settings
- Target:Unity-iPhone
- 如果不知道應該寫,通過命令行工具,可以進入上一步生成的IOS項目目錄(unity3d的IOS編譯輸出目錄),執(zhí)行“xcodebuild -list”即可看到
- Clear before build:Yes
- Configuration:release( 或者 debug,看需要)
- 勾選 Pack applicatin,build and sign ipa
- Export method:develoment(看需要,如果Mobile Provisioning Profiles選擇的是develoment證書,則這里需要配置development,如果是ad-hoc的distribution證書,則這里需要配置ad-hoc,如果是正式上線的證書,則這里需要配置app-store)
- .ipa filename pattern:${BUILD_DATE}(生成的ipa文件名字)
- Output directory:/Users/當前系統(tǒng)登陸用戶/Desktop(這里是放在當前系統(tǒng)用戶的桌面,自己隨便定義)
配置Code signing & OS X keychain options
- Development Team:*******(下拉選擇這個,也就是之前配置的系統(tǒng)設置->Xcode Builder->Development Team->Team Name)
- Development Team ID:(當上面Development Team選擇None時,此處需要手動輸入TeamID,可以在開發(fā)者后臺查到)
- 勾選Unlock keychain:
- Keychain:login.keychain(下拉選擇這個,也就是之前配置的系統(tǒng)設置->Xcode Builder->keychains)
- Keychain path:(當上面Keychain選擇None時,此處需要手動輸入xxxx.keychain所在路徑,路徑中包括xxxx.keychain文件)
- Keychain password:(當上面Keychain選擇None時,此處需要手動輸入xxxx.keychain的解鎖密碼)
- Keychain:login.keychain(下拉選擇這個,也就是之前配置的系統(tǒng)設置->Xcode Builder->keychains)
配置Advanced Xcode build options
-
Xcode Schem File:Unity-iPhone
- 如果不知道應該寫,通過命令行工具,可以進入上一步生成的IOS項目目錄(unity3d的IOS編譯輸出目錄),執(zhí)行“xcodebuild -list”即可看到
SDK:iOS 11.2 - 如果不知道應該寫,通過命令行工具,可以進入上一步生成的IOS項目目錄(unity3d的IOS編譯輸出目錄),執(zhí)行“xcodebuild -list”即可看到
-
Custom xcodebuild arguments:-ENABLE_BITCODE=NO -allowProvisioningUpdates
- 比如,編譯時不需要開啟 BITCODE,自此出填寫:-ENABLE_BITCODE=NO,這個配置如果在Unity中配置過了,此處可以寫
- 比如,編譯時需要動態(tài)更新證書,自此出填寫:-allowProvisioningUpdates
Xcode Project Directory:/Users/當前系統(tǒng)登陸用戶/Documents/Project/build/iPhone(unity3d的IOS編譯輸出目錄)
創(chuàng)建構建并配置結束
注意事項#
- 如果出現(xiàn)“l(fā)d ... normal arm64”類的錯誤,就倒著分析log,可能有以下異常引起:
- 看有沒有什么framework not found的異常
- 打包發(fā)布版本的時候,會出現(xiàn)找不到對應的證書:
- 要鑰匙串中有開發(fā)證書
附:在Unity3d中動態(tài)添加IOS需要的Framework和plist參數(shù)方法
#if UNITY_IOS
using UnityEditor;
using UnityEditor.iOS.Xcode;
using System.Collections.Generic;
using System.IO;
#endif
public static class PBXHelper
{
public const string PROJECT_ROOT = "$(PROJECT_DIR)/";
public const string IMAGE_XCASSETS_DIRECTORY_NAME = "Unity-iPhone";
public const string LINKER_FLAG_KEY = "OTHER_LDFLAGS";
public const string FRAMEWORK_SEARCH_PATHS_KEY = "FRAMEWORK_SEARCH_PATHS";
public const string LIBRARY_SEARCH_PATHS_KEY = "LIBRARY_SEARCH_PATHS";
public const string ENABLE_BITCODE_KEY = "ENABLE_BITCODE";
public const string DEVELOPMENT_TEAM = "DEVELOPMENT_TEAM";
public const string GCC_ENABLE_CPP_EXCEPTIONS = "GCC_ENABLE_CPP_EXCEPTIONS";
public const string GCC_ENABLE_CPP_RTTI = "GCC_ENABLE_CPP_RTTI";
public const string GCC_ENABLE_OBJC_EXCEPTIONS = "GCC_ENABLE_OBJC_EXCEPTIONS";
public const string INFO_PLIST_NAME = "Info.plist";
public const string URL_TYPES_KEY = "CFBundleURLTypes";
public const string URL_TYPE_ROLE_KEY = "CFBundleTypeRole";
public const string URL_IDENTIFIER_KEY = "CFBundleURLName";
public const string URL_SCHEMES_KEY = "CFBundleURLSchemes";
public const string APPLICATION_QUERIES_SCHEMES_KEY = "LSApplicationQueriesSchemes";
#if UNITY_IOS
/// <summary>
/// </summary>
/// <param name="buildTarget">Build target.</param>
/// <param name="buildPath">Build path.</param>
[PostProcessBuild]
public static void OnPostprocessBuild (BuildTarget buildTarget, string buildPath)
{
if (buildTarget != BuildTarget.iOS)
return;
string pbxProjPath = PBXProject.GetPBXProjectPath (buildPath);
pbxProject = new PBXProject ();
pbxProject.ReadFromString (File.ReadAllText (pbxProjPath));
string targetGuid = pbxProject.TargetGuidByName (PBXProject.GetUnityTargetName ());
// 1、設置關閉Bitcode
pbxProject.SetBuildProperty (targetGuid, ENABLE_BITCODE_KEY, "NO");
// 2、添加Framework
pbxProject.AddFrameworkToProject (targetGuid, "系統(tǒng)自帶的.framework", false);
pbxProject.AddFrameworkToProject (targetGuid, "系統(tǒng)自帶的.framework", false);
pbxProject.AddFrameworkToProject (targetGuid, "系統(tǒng)自帶的.framework", false);
// 3、添加tbd
pbxProject.AddFileToBuild(targetGuid, pbxProject.AddFile("usr/lib/" + "系統(tǒng)自帶的.tbd", "Frameworks/" + "系統(tǒng)自帶的.tbd", PBXSourceTree.Sdk));
// 4、添加Privaty
SetInfoPlist (buildPath);
File.WriteAllText (pbxProjPath, pbxProject.WriteToString ());
UnityEngine.Debug.Log ("PBXProject : ---->" + pbxProject.WriteToString ());
}
public static void SetInfoPlist (string buildPath)
{
List<string> privacySensiticeData = new List<string> ();
// 添加權限
privacySensiticeData.Add ("NSMicrophoneUsageDescription");
privacySensiticeData.Add ("NSCameraUsageDescription");
privacySensiticeData.Add ("NSLocationAlwaysAndWhenInUseUsageDescription");
PlistDocument plist = GetInfoPlist (buildPath);
SetPrivacySensiticeData (plist, privacySensiticeData, "Privacy");
plist.WriteToFile (GetInfoPlistPath (buildPath));
UnityEngine.Debug.Log ("PLIST : ---->" + plist.WriteToString ());
}
private static void SetPrivacySensiticeData (PlistDocument plist, List<string> permission, string description = "")
{
PlistElementDict rootDict = plist.root;
int count = permission.Count;
for (int i = 0; i < count; i++)
{
rootDict.SetString (permission[i], description);
}
}
private static string GetInfoPlistPath (string buildPath)
{
return Path.Combine (buildPath, INFO_PLIST_NAME);
}
private static PlistDocument GetInfoPlist (string buildPath)
{
string plistPath = GetInfoPlistPath (buildPath);
PlistDocument plist = new PlistDocument ();
plist.ReadFromFile (plistPath);
return plist;
}
#endif
}