Use xcodebuild (Xcode 8) and automatic signing in CI (Travis/Jenkins) environments - xcode

With the release of Xcode 8, Apple introduced a new way of managing the signing configuration. Now you have two options Manual and Automatic.
According to the WWDC 2016 Session about Code signing (WWDC 2016 - 401 - What's new in Xcode app signing), when you select Automatic signing, Xcode is going to:
Create signing certificates
Create and update App IDs
Create and update provisioning profiles
But according to what Apple says in that session, the Automatic Signing is going to use Development signing and will be limited to Xcode-created provisioning profiles.
The issue comes when you try to use Automatic Signing on a CI environment (like Travis CI or Jenkins). I'm not able to figure out an easy way to keep using Automatic and sign for Distribution (as Xcode forces you to use Development and Xcode-created provisioning profiles).
The new "Xcode-created provisioning profiles" do not show up in the developer portal, although I can find then in my machine... should I move those profiles to the CI machine, build for Development and export for Distribution? Is there a way to override the Automatic Signing using xcodebuild?

I basically run into the same issue using Jenkins CI and the Xcode Plugin.
I ended up doing the build and codesigning stuff myself using xcodebuild.
0. Prerequisites
In order to get the following steps done successfully, you need to have installed the necessary provisioning profiles and certificates. That means your code signing should already be working in general.
1. Building an .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: your 10 digit developer team id (something like A1B2C3D4E5)
2. Exporting to .ipa
xcodebuild -exportArchive -archivePath <path/to/your.xcarchive> -exportOptionsPlist <path/to/exportOptions.plist> -exportPath <output-path>
Example of an 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: is one of development, app-store, ad-hoc, enterprise
teamID: your 10 digit developer team id (something like A1B2C3D4E5)
This process is anyway closer to what you would do with Xcode manually, than what for example the Jenkins Xcode Plugin does.
Note: The .xcarchive file will always be develpment signed, but selecting "app-store" as method in the 2nd step will do the correct distribution signing and also include the distribution profile as "embedded.mobileprovision".
Hope this helps.

After trying a few options, these are the solutions that I was able to use on my CI server:
Include the Developer certificate and private key as well as the auto generated provisioning profiles in the CI environment:
Using Automatic signing forces you to use a Developer certificate and auto-generated provisioning profiles. One option is to export your development certificate and private key (Application -> Utilities -> Keychain Access) and the auto-generated provisioning profiles to the CI machine. A way to locate the auto-generated provisioning profiles is to navigate to ~/Library/MobileDevice/Provisioning\ Profiles/, move all files to a backup folder, open Xcode and archive the project. Xcode will create auto-generated development provisioning profiles and will copy them to the Provisioning Profiles folder.
xcodebuild archive ... will create a .xcarchive signed for Development. xcodebuild -exportArchive ... can then resign the build for Distribution
Replace 'Automatic' with 'Manual' when building on a CI environment
Before calling xcodebuild a workaround is to replace all instances of ProvisioningStyle = Automatic with ProvisioningStyle = Manual in the project file. sed can be used for a simple find an replace in the pbxproj file:
sed -i '' 's/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/' <ProjectName>.xcodeproj/project.pbxproj
#thelvis also created a Ruby script to do this using the xcodeproj gem. The script gives you a better control over what is changed.
xcodebuild will then use the code signing identity (CODE_SIGN_IDENTITY) set in the project, as well as the provisioning profiles (PROVISIONING_PROFILE_SPECIFIER). Those settings can also be provided as parameters to xcodebuild and they will override the code signing identity and/or provisioning profile set in the project.
EDIT: with Xcode 9, xcodebuild has a new build settings parameter CODE_SIGN_STYLE to select between Automatic and Manual so there's no need to find and replace instances of automatic with manual in the project file, more info in WWDC 2017 Session 403 What's New in Signing for Xcode and Xcode Server
Switch to manual signing
Manual signing will provide total control over the code signing identities and provisioning profiles being used. It's probably the cleanest solution, but with the downside of losing all the benefits of Automatic signing.
To learn more about code signing with Xcode 8 I really recommend this article as well as the WWDC2016 session 401 - What's new in Xcode app signing

I'm considering another option I've not seen mentioned here yet. Setup two identical targets, that only differ in their signing settings.
Development Target uses automatic signing to get all of those benefits when new devices / developers are added
CI Target uses manual signing
Downside is that you would have to manage two identical targets. Upside is that get the benefits of automatic signing for development, and don't have to maintain potentially brittle scripts that modify your project just before build time.

If you are using Xcode 8.x and Jenkins for CI. Then probably you would face issue with "Signing for “YourProjectName" requires a development team. Select a development team in the project editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.1’”.** BUILD FAILED ** when running the job.
What is the solution?.
Solution is:
set Provisioning profile to None in Xcode project build settings.
In jenkins, Create a execute shell before the Xcode setting and write the below command
sed -i '' 's/ProvisioningStyle = Automatic;/ProvisioningStyle = Manual;/' ProjectName.xcodeproj/project.pbxproj
Remember: keep that execute shell before Xcode settings in Build section of jenkins.
This works.

There is one more way to workaround nonfunctional signing in CI/CD pipeline when the signing specified in the target (or project) fails.
We use automatic signing for our apps to have a good developer experience, and in CI/CD only signing is done in the last step when .ipa is produced.
Produce an unsigned .xcarchive
xcodebuild -workspace Runner.workspace CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=NO <more parameters follow>
Sign the final .ipa file with configuration in exportOptions.plist
xcodebuild -exportArchive -archivePath <.xcarchive> -exportOptionsPlist <exportOptions.plist> -exportPath <output-path>

For me, nothing worked. I solved my problem by changing a file in Xcode app installed on your Mac Mini (CI server with Jenkins), as shown in this link:
https://www.jayway.com/2015/05/21/fixing-your-ios-build-scripts/
Additionally I turned off automatic signing from Xcode.
All done! Finally works!

I noticed my Unity build was never adding a ProvisioningStyle key to my XCode project. I then found a way to manually add the ProvisioningStyle by using a "PostProcessBuild" build script. i.e. a unit of code that is called after the IOS XCode project has been built by Unity.
First I had a look at what the project.pbxproj file should look like - when it is set to Manual Provisioning:
/* Begin PBXDictionary section */
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
TargetAttributes = {
1D6058900D05DD3D006BFB54 /* Unity-iPhone */ = {
ProvisioningStyle = Manual;
};
5623C57217FDCB0800090B9E /* Unity-iPhone Tests */ = {
TestTargetID = 1D6058900D05DD3D006BFB54 /* Unity-iPhone */;
};
};
};
Then I created my code to replicate the "structure" of the file seen above. (using the XCodeEditor project found here: 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 "";
}

What fixed it for me was this: http://code-dojo.blogspot.jp/2012/09/fix-ios-code-signing-issue-when-using.html
... copying certificates from Login keychain to System keychain.
You might also want to set all dev certificates to 'Allow all applications to access this item' (Right-click/Get Info/Access Control).

There is a tool called fastlane which makes using xcodebuild much easier and it is maintained meaning new updates will continue to provide support for changes to xcode. It makes it much easier to create scripts and config for building and codesigning your app among many other xcode automation tools it supports. I'd recommend giving it a look into.

Related

jenkins provisioning profile issue

Check dependencies
No iOS profile matching 'Nitin xxxxxxx/xyzCAppStore' found: Xcode couldn't find a profile matching 'Nitin xxxxxxx/xyzCAppStore'. Install the profile (by dragging and dropping it onto Xcode's dock item) or select a different one in the General tab of the target editor.
Code signing is required for product type 'Application' in SDK 'iOS 10.3'
** BUILD FAILED **
The following build commands failed:
Check dependencies
(1 failure)
Build step 'Xcode' marked build as failure
Finished: FAILURE
have tried below things
http://code-dojo.blogspot.in/2012/09/fix-ios-code-signing-issue-when-using.html
https://wiki.jenkins-ci.org/display/JENKINS/Keychains+and+Provisioning+Profiles+Plugin
I have solved same problem by following steps
Switch to your Jenkin Account [Login to your Jenkins Account]
Install all required certificates and provisioning in keychain in Jenkin-Account
Jenkins/Home/workspace or may be different on your Mac [you need to locate the workspace] go to this location.
You will find the Xcode project which is created by Jenkin local server-- Open this Xcode project -- set provisioning and certificates
close the project
open localhost:8080 build your project from Jenkin
jenkins provisioning profile issue will be solved

xcodebuild flag overrides code signing for pods project targets

I have a problem with building (archiving) the workspace because whenever I run
xcodebuild archive -workspace app.xcworkspace/ -scheme app-scheme -configuration Production -derivedDataPath ./build -archivePath ./build/Products/app.xcarchive DEVELOPMENT_TEAM=AAABBBCCCD PROVISIONING_PROFILE_SPECIFIER="prod DistProf" CODE_SIGN_IDENTITY="iPhone Distribution"
I get
XXX does not support provisioning profiles. XXX does not support provisioning profiles, but provisioning profile YYY has been manually specified. Set the provisioning profile value to "Automatic" in the build settings editor.
for each pod.
When I omit the DEVELOPMENT_TEAM flag then I get
Signing for "myAPP" requires a development team. Select a development team in the build settings editor that matches the selected profile "YYY".
All the pods do not need signing. Specifying the flag in the command line seems to ignore the settings for different project. I can't use automatic signing as I am not a member of the team that issued the certificate, I only have cert and provisioning profile on my machine so any fastlane solutions won't work. Also I can't set it up once in the project as it comes from a 3rd party company and we can't share our profiles.
How can I set up this project to continuous integration chain?
I was having the same issue and found a working solution after much trial an error.
I couldn't get the command line approach to work, despite a claim to the contrary that i found on this Google group https://groups.google.com/forum/#!topic/cocoapods/q5x653je7MA
What worked for me was to stop specifying the team, provisioning and identity in the command line and instead move that to a xconfig file.
In the particular case of working with Cocoapods it goes like this:
Create the xconfig file. This is done by simply creating a new "Configuration Settings" file with Xcode (it's under 'Other' in the new file dialog). This file will be empty.
Fill in the values for code signing in the xconfig file. This can be done by first setting the values in xcode's build settings and then copy & pasting over. The resulting file looks something like this:
#include "Pods/Target Support Files/Pods-xxx/xxx.release.xcconfig"
//:configuration = Release
DEVELOPMENT_TEAM = xxx
//:configuration = Release
PROVISIONING_PROFILE_SPECIFIER = xxx/xxx
Replace xxx with the right values for your project. The PROVISIONING_PROFILE_SPECIFIER value is
a combination of the Team ID and profile name (as it is named in the
Developer Portal, not necessarily the actual filename)
as specified here https://possiblemobile.com/2016/06/code-signing-xcode-8/
Note that the first line is to include the release.xconfig generated by cocoapods. This is important! if you don't do this and run pod update, you will see a warning pop up asking you to do it or else nothing will work
Assing your project to use the xconfig file. This is done by going to the Project's General tab and scrolling to the Configurations setting. You can then select your newly created xconfig file from the dropdown under Release
(further information on how to use a xconfig file can be found here http://www.jontolof.com/cocoa/using-xcconfig-files-for-you-xcode-project/)
With all that in place, you can proceed to build the archive:
xcodebuild archive \
-workspace "xxx" \
-scheme "xxx" \
-sdk iphoneos \
-archivePath "xxx"

Import .ProvisionProfile when using Circle.CI and FastLane

For my personal project, I am using Circle.ci to test and deploy the OSX application (with upload hook to S3, to distribute it outside the AppStore - using the signed with Developer ID distribution method). I am using FastLane to build the app, which works flawlessly when building it from my local terminal, but I cannot get past code signing step when using the CI server.
The issue is very simple, the keychain does not import the provision profile, which I can tell from the pre-build step:
1 key imported.
No provisioning profiles found in repository.
You must add a provisioning profile to your repository
to enable CircleCI code-signing support.
Currently installed Code-Signing identities:
Policy: Code Signing
Matching identities
0 identities found
Valid identities only
0 valid identities found
I have my .p12 with private key and certificate uploaded to the repository, no issue there. I have also added the .provisionprofile to the repository (root, even different locations) but to no avail. The documentation states (https://circleci.com/docs/ios-code-signing/) that there is a need for .mobileprovision, but that only covers the iOS, not the OSX, while the system should be nearly identical so I assumed that would work as well.
So the TLDR question is: How do I import the provisioning profile of the OSX distribution on the Circle.CI, so the keychain accepts the entry? Or is there a way around it - like skipping the signing step (disabling it in XCode) and signing it by hand with some .sh?
Thanks everyone!
I am sharing my experience of deploying iOS app to Testflight using CircleCI. Maybe this helps.
Put the provision profile file in the root of your project directory. Make sure it is a normal "Distribution Profile" not a App Store submission profile.
Just add the .p12 key in the project settings of CircleCI. Remove all other certificates / .p12 file from the repository.
I tried using fastlane to build and distribute the build but it was failing in CircleCI. I had these three steps in my Fastfile beta environment.
increment_build_number
gym(scheme: "myScheme”)
pilot
I changed that to just
increment_build_number
My Circle CI file
machine:
environment:
GYM_CODE_SIGNING_IDENTITY: "iPhone Distribution: Company Name (XXXXXX)"
xcode:
version: "8.0"
test:
override:
- set -o pipefail && xcodebuild -workspace 'my.xcworkspace' -scheme 'myscheme' clean build test -sdk iphonesimulator -destination 'id=AC291080-8EFE-4095-8C55-B1E952EFFC36' CODE_SIGNING_REQUIRED=NO CODE_SIGN_IDENTITY= PROVISIONING_PROFILE=
dependencies:
pre:
- gem update fastlane
deployment:
beta_distribution:
branch: master
commands:
- fastlane beta
- gym --scheme "myscheme" --workspace "my.xcworkspace" --export_method app-store --use_legacy_build_api false
- pilot upload

Is there a way of automating the process of refreshing profiles for XCode / XCodeBuild?

I'm setting up a CI build machine and wondering if there is anyway of making sure the machine always has an up to date set of profiles.
If a new device is added to the provisioning portal for example then the CI build will fail until Xcode
/Organizer has its profiles refreshed.
Is there an XCodeBuild command for doing this so that I can automate it (within Jenkins)?
This answer might be helpful, but I haven't implemented it yet:
Command line Update of Provisioning Profiles
For our system, I was just planning on putting the profiles into version control and then running those commands in a prebuild shell script.

How to compile a project with app and library in the same workspace with different configuration names?

I am developing an app and I am using an open source component.
I have a workspace containing both MyApp.xcodeproj and Component.xcodeproj. My app has three configurations: Debug, App Store and In House but the component has only two: Debug and Release
In the Debug configuration, everything works fine, but I can't compile my app in App Store or In House configuration because the configuration names do not match. I get a file not found error when trying to #import <Component/Component.h>
I need both App Store and In House configurations and I would really like to avoid modifying the component's configurations in order to ease future updates of the component.
I know I could use CocoaPods to solve this issue but I would like to know if there is a simple solution in Xcode
You can get your project to compile with some tweaks to your app’s settings.
I suggest you to modify all settings at the project level so that all your targets can inherit these settings.
Add a new DEFAULT_CONFIGURATION user-defined setting and define your configuration mapping. This is how it should look like:
Set FRAMEWORK_SEARCH_PATHS to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME) for all configurations, add Any OS X SDK variants and set the value to $(BUILD_DIR)/$(DEFAULT_CONFIGURATION). Set HEADER_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS)/include and LIBRARY_SEARCH_PATHS to $(FRAMEWORK_SEARCH_PATHS). This is how it should look like:
This step is quite tedious, it can be automated with the xcproj tool and by running this script in your project directory. Edit your configurations mapping as needed.
#!/bin/bash
CONFIGURATIONS=( "App Store:Release" "In House:Release" "Debug:Debug" )
for CONFIGURATION in "${CONFIGURATIONS[#]}"; do
xcproj --configuration "${CONFIGURATION%%:*}" write-build-setting DEFAULT_CONFIGURATION "${CONFIGURATION#*:}"
done
xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)-$(PLATFORM_NAME)'
xcproj write-build-setting 'FRAMEWORK_SEARCH_PATHS[sdk=macosx*]' '$(BUILD_DIR)/$(DEFAULT_CONFIGURATION)'
xcproj write-build-setting 'HEADER_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)/include'
xcproj write-build-setting 'LIBRARY_SEARCH_PATHS' '$(FRAMEWORK_SEARCH_PATHS)'
If the component is distributed as a static library, you are done here. If the component comes as a framework you have to update its path reference by editing your project.pbxproj file in a text editor. In the PBXFileReference section (under /* Begin PBXFileReference section */) find Component.framework and update its path like this:
name = Component.framework; path = "../$(DEFAULT_CONFIGURATION)/Component.framework"; sourceTree = BUILT_PRODUCTS_DIR; };
Also make sure that the sourceTree is set to BUILT_PRODUCTS_DIR, i.e. relative to built products. Once you edited the project file, this should look like:
Your project should now build as expected.
I had this same problem, but I had multiple configurations (Debug, TestFlight, Release, Enterprise) in my app, and the bolded configurations would always fail to build cause it couldn't find the frameworks. I really didn't want to mess with the project settings of my sub projects in order to make updating them easy.
The answer I found was to just update the framework search path to account for the fact that the frameworks would be dropped in Release (or whatever the default configuration is set to) of the sub projects.
Specifically I set it to:
$(BUILD_DIR)/Release-$(PLATFORM_NAME)
I set it to be recursive too. This works both for Simulator and Device, building in Xcode and command line.
I solved it in the following way,
In my dependency project,
Project -> Target -> Build Phases, added new Run Script
TARGET_DIR="Build"
TARGET_FILE="${TARGET_DIR}/${FULL_PRODUCT_NAME}"
mkdir -p ${TARGET_DIR}
rm -rf ${TARGET_FILE}
cp -rf "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" ${TARGET_DIR}
After the every build, I copy the build to my Build directory inside the project.
And from the main project,
Project -> Target -> General, I drag and dropped the dependency Framework (which is inside dependency project's Build folder)
then,
Project -> Target -> Build Settings -> Framework Search Paths, under my custom Build Configuration, I added the following
$(PROJECT_DIR)/../DependencyProject/Build
The folder is relative to my main project, and this should be relative to your project.
Then in my all the schemes, I added a Pre-actions script for Build with
rm -Rf "${PROJECT_DIR}/../DependencyProject/Build"
Also you need to select the app against Provide build settings from drop down.

Resources