在 CI (Travis/Jenkins) 环境中使用 xcodebuild (Xcode 8) 和自动签名

Posted

技术标签:

【中文标题】在 CI (Travis/Jenkins) 环境中使用 xcodebuild (Xcode 8) 和自动签名【英文标题】:Use xcodebuild (Xcode 8) and automatic signing in CI (Travis/Jenkins) environments 【发布时间】:2017-01-22 20:40:41 【问题描述】:

随着 Xcode 8 的发布,Apple 引入了一种管理签名配置的新方法。现在你有两个选项ManualAutomatic

根据WWDC 2016 Session about Code signing (WWDC 2016 - 401 - What's new in Xcode app signing),当你选择Automatic 签名时,Xcode 将会:

创建签名证书 创建和更新应用 ID 创建和更新配置文件

但根据 Apple 在该会话中的说法,Automatic Signing 将使用 Development signing,并将仅限于 Xcode 创建的配置文件。

当您尝试在 CI 环境(如 Travis CI 或 Jenkins)上使用 Automatic Signing 时会出现问题。我无法找到一种简单的方法来继续使用自动并签署分发(因为 Xcode 强制您使用开发和 Xcode 创建的配置文件)。

新的“Xcode 创建的配置文件”没有显示在开发者门户中,虽然我可以在我的机器中找到...我应该将这些配置文件移动到 CI 机器,为Development 构建并导出为Distribution?有没有办法使用xcodebuild 覆盖Automatic Signing

【问题讨论】:

我遇到了同样的问题,这让我很抓狂。 我创建了一个简单的ruby script,允许您在自动和手动签名之间切换。您可以切换到手动签名并使用PROVISIONING_PROFILE_SPECIFIERCODE_SIGN_IDENTITY 组合。请注意它使用xcodeproj gem,您必须先安装gem install xcodeproj。我希望这会对你有所帮助。 太棒了,我最终也做了同样的事情。在我的情况下,一个简单的查找和替换工作正常。我会分享我的发现。 问题仍然存在,即使您切换到Manual signing,您也必须找到一种方法将您的证书和配置文件(开发或生产)共享给所有 CI 服务器(因为 cli xcodebuild 命令无法管理那些像xcode一样)。话虽如此,您又回到手动管理某些配置文件(例如使用 fastlane),而自动功能失去了一点兴趣。 事实上,只要您使用 Xcode,自动签名就是一项很棒的功能。它终于奏效了!可悲的是,如果你不打开 Xcode(就像在 CI 中一样),它就不起作用。因此,我们最终在开发时使用自动签名,并使用上面的 Jenkins 构建脚本切换到手动签名。不过,如果xcodebuild 可以自己进行自动签名,那就太好了。让我们希望签名将在 Xcode 的下一个版本中完全自动化。 ^^ 【参考方案1】:

我在使用 Jenkins CI 和 Xcode 插件时基本上遇到了同样的问题。 我最终使用xcodebuild 自己进行构建和代码设计。

0。先决条件

为了成功完成以下步骤,您需要安装必要的配置文件和证书。这意味着您的代码签名应该已经正常工作了。

1。构建 .xcarchive

xcodebuild -project <path/to/project.xcproj> -scheme <scheme-name> -configuration <config-name> clean archive -archivePath <output-path> DEVELOPMENT_TEAM=<dev-team-id>
DEVELOPMENT_TEAM:您的 10 位开发团队 ID(类似于 A1B2C3D4E5)

2。导出到 .ipa

xcodebuild -exportArchive -archivePath <path/to/your.xcarchive> -exportOptionsPlist <path/to/exportOptions.plist> -exportPath <output-path>

exportOptions.plist 示例:

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>method</key>
    <string>development</string>
    <key>teamID</key>
    <string> A1B2C3D4E5 </string>
</dict>
</plist>
method:是developmentapp-storead-hocenterprise 之一 teamID:你的 10 位开发团队 ID(类似于 A1B2C3D4E5)

无论如何,这个过程更接近于手动使用 Xcode 执行的操作,而不是 Jenkins Xcode 插件所做的操作。

注意:.xcarchive 文件将始终经过开发签名,但在第二步中选择“app-store”作为方法将执行正确的分发签名,并将分发配置文件包含为“embedded.mobileprovision”。

希望这会有所帮助。

【讨论】:

当签名设置为Automatic 时,Xcode 仍在使用iPhone Developer,即使设置了DEVELOPMENT_TEAMCODE_SIGNING_IDENTITY='Phone Distribution'。如果您查看xcodebuild 的日志,您可以看到协同设计正在使用Signing Identity: "iPhone Developer: XXXX (XXXXX)",因此您的CI 环境需要开发人员证书和自动生成的配置文件,您使用的是Manual 还是Automatic 基本上,如果您尝试强制CODE_SIGNING_IDENTIY,但您启用了Automatic 签名,您将收到此错误:&lt;YourTarget&gt; has conflicting provisioning settings. &lt;YourTarget&gt; is automatically signed, but code signing identity iPhone Distribution: ... has been manually specified. Set the code signing identity value to "iPhone Developer" in the build settings editor, or switch to manual signing in the project editor. 其实我是用Unity3D来创建Xcode项目的,但是打开项目,可以看到“自动管理签名”被打勾了。我刚刚尝试使用iPhone Distribution(直到现在我才使用Developer)。但它只对我有用。命令行输出:Build settings from command line: CODE_SIGNING_IDENTITY = iPhone Distribution DEVELOPMENT_TEAM = MY_TEAM_ID 你能粘贴你实际使用的命令吗(当然你可以混淆团队ID,或者任何其他私人的东西)。 如果我尝试CODE_SIGNING_IDENTITY= 'iPhone Distribution',我可以看到与您看到的相同的输出,但是如果您检查构建日志的完整输出并检查CodeSign 阶段,您会看到这是实际使用Signing Identity: "iPhone Developer:....(尝试使用&gt; build.log 保存xcodebuild 终端输出)。因此,如果您与代码签名身份名称不完全匹配,则仍在使用开发中。如果您匹配您的代码签名身份名称 (CODE_SIGNING_IDENTITY= 'iPhone Distribution: My Company Name'),那么您将看到另一个错误 恐怕您目前无法使用工具在自动和手动签名之间切换。我想如果您找到一种方法来编辑project.pbxproj 文件并在TargetAttributes 中为您的目标添加ProvisioningStyle = Manual;,它可能会奏效。但这似乎很棘手,如果您想在 CI 环境上构建,手动管理证书和配置文件似乎是一种更直接的方法。【参考方案2】:

在尝试了几个选项后,这些是我能够在我的 CI 服务器上使用的解决方案:

在 CI 环境中包含开发者证书和私钥以及自动生成的配置文件:

使用Automatic signing 会强制您使用Developer 证书和auto-generated provisioning profiles。一种选择是将您的开发证书和私钥(应用程序 -> 实用程序 -> 钥匙串访问)以及自动生成的配置文件导出到 CI 机器。找到自动生成的配置文件的一种方法是导航到~/Library/MobileDevice/Provisioning\ Profiles/,将所有文件移动到备份文件夹,打开 Xcode 并存档项目。 Xcode 将创建自动生成的开发配置文件并将它们复制到Provisioning Profiles 文件夹。

xcodebuild archive ... 将创建一个为Development 签名的.xcarchive。然后xcodebuild -exportArchive ... 可以为Distribution 退出构建

在 CI 环境中构建时将“自动”替换为“手动”

在调用xcodebuild 之前,一种解决方法是在项目文件中将ProvisioningStyle = Automatic 的所有实例替换为ProvisioningStyle = Manualsed 可用于在pbxproj 文件中进行简单的查找替换:

sed -i '' 's/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/' &lt;ProjectName&gt;.xcodeproj/project.pbxproj

@thelvis 还使用 xcodeproj gem 创建了一个 Ruby script 来执行此操作。该脚本使您可以更好地控制更改的内容。

xcodebuild 然后将使用项目中设置的代码签名身份 (CODE_SIGN_IDENTITY) 以及配置文件 (PROVISIONING_PROFILE_SPECIFIER)。这些设置也可以作为参数提供给xcodebuild,它们将覆盖项目中设置的代码签名身份和/或配置文件。

编辑:使用 Xcode 9,xcodebuild 有一个新的构建设置参数 CODE_SIGN_STYLE 可以在 AutomaticManual 之间进行选择,因此无需在项目文件中查找和替换自动与手动的实例,更多WWDC 2017 Session 403 What's New in Signing for Xcode and Xcode Server中的信息

切换到手动签名

手动签名将提供对正在使用的代码签名身份和配置文件的完全控制。这可能是最干净的解决方案,但缺点是失去了自动签名的所有好处。

要了解有关使用 Xcode 8 进行代码签名的更多信息,我强烈推荐 article 以及 WWDC2016 会议 401 - What's new in Xcode app signing

【讨论】:

我在关闭所有目​​标的手动签名后仍然遇到问题,Jenkins 控制台输出中的错误是:### Codesigning '' with 'iPhone Distribution' + /usr/bin/codesign - -force --preserve-metadata=identifier,entitlements,resource-rules --sign iPhone Distribution。 --resource-rules=/var/folders/9v/.../Payload/YourApp.app/ResourceRules.plist --entitlements /var/folders/9v/.../entitlements_plistHBx8AyjS /var/folders/9v/.. ./Payload/YourApp.app 程序 /usr/bin/codesign 返回 1:[警告:使用带有选项“resource-rules”的 --preserve-metadata(在 Mac OS X >= 10.10 中已弃用)! 如果您使用Automatic 不能使用iPhone Distribution 构建,您需要执行上述选项之一,使用开发签名,然后使用分发或“强制”手册导出签署 对不起,我写错了,我的意思是关闭自动签名后 您的问题似乎与新签名无关,链接到该网站的快速 Google 搜索可能会对您有所帮助 jayway.com/2015/05/21/fixing-your-ios-build-scripts 此外,由于 Xcode 7,使用 xcrun PackageApplication 已被弃用,你应该改用xcodebuild -exportArchive PROVISIONING_PROFILE_SPECIFIER 如果切换到手动配置则无法使用...【参考方案3】:

我正在考虑另一个我还没有在这里提到的选项。设置两个相同的目标,它们的签名设置不同。

开发目标在添加新设备/开发人员时使用自动签名来获得所有这些好处 CI Target 使用手动签名

缺点是您必须管理两个相同的目标。好处是可以获得自动签名以进行开发的好处,并且不必维护可能会在构建时间之前修改您的项目的脆弱脚本。

【讨论】:

【参考方案4】:

如果您使用 Xcode 8.x 和 Jenkins 进行 CI。那么您可能会面临“为“YourProjectName”签名需要开发团队的问题。在项目编辑器中选择一个开发团队。

SDK 'iOS 10.1' 中的产品类型'Application' 需要代码签名。** BUILD FAILED ** 运行作业时。

解决办法是什么?

解决办法是:

    在 Xcode 项目构建设置中将 Provisioning profile 设置为 None。

    在 jenkins 中,在 Xcode 设置之前创建一个执行 shell 并编写以下命令

    sed -i '' 's/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/' ProjectName.xcodeproj/project.pbxproj 
    

    记住:在 jenkins 的 Build 部分中保留 Xcode 设置之前的执行 shell。

这行得通。

【讨论】:

【参考方案5】:

对我来说,没有任何效果。我通过更改安装在 Mac Mini(带有 Jenkins 的 CI 服务器)上的 Xcode 应用程序中的文件解决了我的问题,如以下链接所示:https://www.jayway.com/2015/05/21/fixing-your-ios-build-scripts/ 另外我关闭了 Xcode 的自动签名。

全部完成!终于成功了!

【讨论】:

你的詹金斯服务器在哪里?我的在 AWS 实例 Ubuntu 和 mac 笔记本电脑上作为奴隶【参考方案6】:

我注意到我的 Unity 构建从未向我的 XCode 项目添加 ProvisioningStyle 键。然后,我找到了一种使用“PostProcessBuild”构建脚本手动添加 ProvisioningStyle 的方法。即在 Unity 构建 IOS XCode 项目之后调用的代码单元。

首先我看看 project.pbxproj 文件应该是什么样子 - 当它设置为手动配置时:

/* Begin PBXDictionary section */
    29B97313FDCFA39411CA2CEA /* Project object */ = 
        isa = PBXProject;
        attributes = 
            TargetAttributes = 
                1D6058900D05DD3D006BFB54 /* Unity-iPhone */ = 
                    ProvisioningStyle = Manual;
                ;
                5623C57217FDCB0800090B9E /* Unity-iPhone Tests */ = 
                    TestTargetID = 1D6058900D05DD3D006BFB54 /* Unity-iPhone     */;
                ;
            ;
        ;

然后我创建了代码来复制上面看到的文件的“结构”。 (使用此处找到的 XCodeEditor 项目:XCodeEditor)

[PostProcessBuild]
public static void OnPostProcessBuild(BuildTarget target, string path)

    // Create a new project object from build target
    XCProject project = new XCProject(path);

    if (target == BuildTarget.iOS)
    
        //Add Manual ProvisioningStyle - this is to force manual signing of the XCode project
        bool provisioningSuccess = AddProvisioningStyle(project, "Manual");

        if (provisioningSuccess)
            project.Save();
    


private static bool AddProvisioningStyle(XCProject project, string style)

    var pbxProject = project.project;

    var attr = pbxProject.data["attributes"] as PBXDictionary;
    var targetAttributes = attr["TargetAttributes"] as PBXDictionary;

    var testTargetIDGuid = FindValue(targetAttributes, "TestTargetID");

    if (!string.IsNullOrEmpty(testTargetIDGuid))
    
        var settings = new PBXDictionary();
        //here we set the ProvisioningStyle value
        settings.Add("ProvisioningStyle", style);

        targetAttributes.Add(testTargetIDGuid, settings);

        var masterTest = FindValue(targetAttributes, "ProvisioningStyle");

        if (masterTest == style)
        
            return true;
        
    

    return false;


private static string FindValue(PBXDictionary targetAttributes, string key)

    foreach (var item in targetAttributes)
    
        var ma = item.Value as PBXDictionary;

        foreach (var di in ma)
        
            var lookKey = di.Key;

            if (lookKey == key)
            
                return di.Value.ToString();
            
        
    

    return "";

【讨论】:

【参考方案7】:

为我解决的问题是:http://code-dojo.blogspot.jp/2012/09/fix-ios-code-signing-issue-when-using.html

... 将证书从登录钥匙串复制到系统钥匙串。 您可能还希望将所有开发证书设置为“允许所有应用程序访问此项目”(右键单击/获取信息/访问控制)。

【讨论】:

【参考方案8】:

有一个名为fastlane 的工具使使用 xcodebuild 变得更加容易,并且它得到维护意味着新的更新将继续为 xcode 的更改提供支持。在它支持的许多其他 xcode 自动化工具中,它可以更轻松地创建用于构建和代码设计应用程序的脚本和配置。我建议你看看。

【讨论】:

fastlane 和任何其他声称可以自动消除所有这些复杂性的工具都会给您留下一个您不了解的黑匣子。它们工作正常,直到它们坏了,然后你需要弄清楚代码签名和 Fastlane 进程是如何工作的。 任何搜索两秒钟的人都知道快车道、比赛和健身房,这些都是非常复杂的解决方案,也会带来很多问题。我对 fastlane 和 match 的经验是,你的项目需要设置为本地手动签名,这在很多情况下是不可接受的。

以上是关于在 CI (Travis/Jenkins) 环境中使用 xcodebuild (Xcode 8) 和自动签名的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CI 环境中运行 postman 的 newman?

在 CI/dev 环境中启动 Ember 测试

如何在 Kubernetes 中隔离 CI 管道每个分支环境?

在 docker 环境中成功 CI 后如何部署到自定义服务器?

您能否在具有苹果 2 因素身份验证的 CI 环境中使用“expo build:ios”以及如何

在CI/CD环境中部署Jenkins