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
}

    原文作者:Alisallon
    原文地址: https://www.jianshu.com/p/e0338ab81fb8
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞