Unity3d:使用Jenkins自动编译打包IOS(只能打包Development)

系列传送门

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. 下载完后,安装

官网: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

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”即可看到
  • SDK:iOS 11.2 - 如果不知道应该写,通过命令行工具,可以进入上一步生成的IOS项目目录(unity3d的IOS编译输出目录),执行“xcodebuild -list”即可看到

  • Custom xcodebuild arguments:-ENABLE_BITCODE=NO -allowProvisioningUpdates

    • 比如,编译时不需要开启 BITCODE,自此出填写:-ENABLE_BITCODE=NO,这个配置如果在Unity中配置过了,此处可以写
    • 比如,编译时需要动态更新证书,自此出填写:-allowProvisioningUpdates
  • Xcode Project Directory:/Users/当前系统登陆用户/Documents/Project/build/iPhone(unity3d的IOS编译输出目录)

创建构建并配置结束

注意事项#

  1. 如果出现“ld ... normal arm64”类的错误,就倒着分析log,可能有以下异常引起:
  • 看有没有什么framework not found的异常
  1. 打包发布版本的时候,会出现找不到对应的证书:
  • 要钥匙串中有开发证书

附:在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
    /// <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, "系统自带的.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<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
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容