安装并配置 Jenkns
1. 下载完后,安装
官网: https://jenkins.io/
2. 修改 jenkins 启动用户
参考: http://www.xuanyusong.com/archives/3349
安装完之后 jenkins 会自动启动,而且使用 root 用户启动的,这会在构建时造成一些麻烦,比如执行权限,文件访问权限等
所以需要把 jenkins 先关闭,然后修改 jenkins 的启动用户和当前登陆系统的用户一致
停止 jenkins
sudo launchctl unload / Library / LaunchDaemons / org.jenkins - ci.plis
修改 org.jenkins-ci.plis 文件
修改 GroupName 和当前登陆系统的用户的 Group Name 一致
修改 UserName 和当前登陆系统的用户的 User Name 一致
启动 jenkins
不推荐:launchctl load /Library/LaunchDaemons/org.jenkins-ci.plist
推荐: java -jar jenkins.war
3. 访问 http://127.0.0.1:8008
打开网页后,会让输入安装密码,这个密码在:
/User/当前系统登陆用户 / .jenkins / secrets / initialAdminPassword
然后下一步配置 Jenkins 网页的登陆密码,信息要全部填写完成后,会提示安装插件,直接选安装推荐的插件
4. 安装我们构建打包需要插件
安装时,记得勾选自动重启 jenkins
Unity3d Plugin
Xcode Integration
Keychains and Provisioning Profiles Plugin
Perforce Plugin (可选,如果 Unity3d 项目源代码用 Perforce 管理,可以使用该插件)
5. 设置插件配置
配置 Xcode Builder
进入 jenkins 主页 -> 左侧系统管理 -> 系统设置 ->Xcode Builder
Xcode 路径之类的,插件会自动补充,无需填写
Development Team(可选,配置构建时可自己指定)
Team Name:***********(可以在开发者后台查到)
Team ID:***********(可以在开发者后台查到)
keychains
keychain Name:login.keychain(自己随便定义)
keychain Path:/Users / 当前系统登陆用户 / Library/Keychains/login.keychain(路径中包括 xxxx.keychain 文件)
keychain Password:********(当前系统登陆用户的密码)
配置 Unity3d
进入 jenkins 主页 -> 左侧系统管理 -> 全局工具配置 ->Unity3d
别名:Unity3d(自己随便定义)
安装目录:/Applications/Unity/Unity.app(注意:该插件会自己在后面拼接 "Contents/MacOS" 或 "Editor/Unity.exe")
配置 Keychains and Provisioning Profiles Management
进入 jenkins 主页 -> 左侧系统管理 -> 全局工具配置 ->Keychains and Provisioning Profiles Management
证书说明:
ios_development.cer:需要从开发者后台下载(左侧 certificate 栏目里)
xxxxxxx.mobileprovision(有 development 版(这里用开发版),ad-hoc 的 distribution 版,正式 distribution 版):需要从开发者后台下载(左侧 Provisioning Profiles 栏目里)
xxxxxxx.developerprofile:需要从 Xcode 中导出(Xcode->Preferences->Accounts(需要在这里先登陆开发者账号)-> 左下角齿轮按钮 ->Export Apple ID And Code Signing Assets)
上传 login.keychain
配置 Keychains
Filename:login.keychain(会自动填写)
Password:当前系统登陆用户的密码
Description:(自己随便定义)
Identities:
Code Sign Identity:iPhone Developer:XXXXXX(钥匙串中,苹果开发者证书简介信息中的常用名称,打开系统钥匙串,把 xxxxxxx.developerprofile 复制进去即可)
上传 xxxxxxx.mobileprovision
配置 Provisioning Profiles
Provisioning Profiles Directory Path:/Users / 当前系统登陆用户 / Library/MobileDevice/Provisioning Profiiles
Filename:(会自动填写)
UUID:(会自动填写)
Jenkins 配置结束
正式开工,创建构建
1. 创建构建
创建一个自由风格的软件项目
项目名:Unity3d_Build_IOS(自己随便定义)
2. 构建配置
修改 workspace
默认 workspace:
/Users/当前系统登陆用户 / .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/当前系统登陆用户/Documents/Project/build/iPhone
配置完成后,可以点击 "立即构建" 进行测试,看 unity3d 项目编译是否正常
点击左下角构建记录,进入该记录信息页,再点击左侧 "Console Output" 即可查看构建日志输出
注意:从日志里看到,编译时,有无权限删除 IOS 编译输出目录的问题,此时需要做以下配置:
顶部选项卡 -> 构建 -> 增加构建步骤 -> 选择 Execute shell
Commands 输入:
rm -rf /Users / 当前系统登陆用户 / Documents/Project/build/iPhone(unity3d 的 IOS 编译输出目录)
命令配置好后,把 Execute shell 拖到 Invoke Unity3d Editor 的前面,此时在 Unity3d 指定编译之前,会先执行配置的 shell 命令
配置 IOS 编译相关
上面配置好并测试完成后,继续配置 Xcode 编译相关
顶部选项卡 -> 构建环境 -> 勾选 Keychains and Code signing Identities
勾选即可,保存后,刷新即可看到内容被自动填充(也就是之前配置的全局工具配置 ->Keychains and Provisioning Profiles Management)
顶部选项卡 -> 构建环境 -> 勾选 Mobile Provisioning Profiles
勾选即可,保存后,刷新即可看到内容被自动填充(也就是之前配置的全局工具配置 ->Keychains and Provisioning Profiles Management)
顶部选项卡 -> 构建 -> 增加构建步骤 -> 选择 Xcode
配置 General build settings
Target:Unity-iPhone
如果不知道应该写,通过命令行工具,可以进入上一步生成的 IOS 项目目录(unity3d 的 IOS 编译输出目录),执行 "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 / 当前系统登陆用户 / Desktop(这里是放在当前系统用户的桌面,自己随便定义)
配置 Code signing & OS X keychain options
Development Team:*******(下拉选择这个,也就是之前配置的系统设置 ->Xcode Builder->Development Team->Team Name)
Development Team ID:(当上面 Development Team 选择 None 时,此处需要手动输入 TeamID,可以在开发者后台查到)
勾选 Unlock keychain:
Keychain:login.keychain(下拉选择这个,也就是之前配置的系统设置 ->Xcode Builder->keychains)
Keychain path:(当上面 Keychain 选择 None 时,此处需要手动输入 xxxx.keychain 所在路径,路径中包括 xxxx.keychain 文件)
Keychain password:(当上面 Keychain 选择 None 时,此处需要手动输入 xxxx.keychain 的解锁密码)
配置 Advanced Xcode build options
Xcode Schem File:Unity-iPhone
如果不知道应该写,通过命令行工具,可以进入上一步生成的 IOS 项目目录(unity3d 的 IOS 编译输出目录),执行 "xcodebuild -list" 即可看到
Custom xcodebuild arguments:ENABLE_BITCODE=NO
比如,编译时不需要开启 BITCODE,自此出填写:ENABLE_BITCODE=NO,这个配置如果在 Unity 中配置过了,此处可以写
Xcode Project Directory:/Users / 当前系统登陆用户 / Documents/Project/build/iPhone(unity3d 的 IOS 编译输出目录)
创建构建并配置结束
附:在 Unity3d 中动态添加 IOS 需要的 Framework 和 plist 参数方法
#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
///
///
/// Build target.
/// Build path.
[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, "系统自带的.framework", false);
pbxProject.AddFrameworkToProject (targetGuid, "系统自带的.framework", false);
pbxProject.AddFrameworkToProject (targetGuid, "系统自带的.framework", false);
// 3,添加tbd
pbxProject.AddFileToBuild(targetGuid, pbxProject.AddFile("usr/lib/" + "系统自带的.tbd", "Frameworks/" + "系统自带的.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 privacySensiticeData = new List ();
// 添加权限
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 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
}
来源: http://www.jianshu.com/p/e0338ab81fb8