0

I am trying to build multiple concurrent builds of my app (one for mocking environment, one for development environment, one for testing environment, one for production release).

I have gotten very far in getting this working, but am having issues with the codesigning of an app with a auto-generated bundle identifier (one running off a variable).

WHAT I HAVE DONE SO FAR

I am using xCode 4.6.3 using an adhoc provisioning profile.

To attempt to get this to work, I am setting my bundle identifier in the info plist file to somewhat running off a variable - so the app can be signed in different ways. E.g. my actual bundle identifiers are:

  • UXXXXXX.au.com.blah.MOCK
  • UXXXXXX.au.com.blah.DEV
  • UXXXXXX.au.com.blah.TEST
  • UXXXXXX.au.com.blah.PROD

Therefore my bundle identifier in my info plist has been configured as "UXXXXXX.au.com.blah.${BUNDLE_SUFFIX}"

Now to allow me to build the app differently for each build, I did the following:

  • I have 4 different bundle identifiers with 4 different provisioning profiles assigned to those bundle identifiers
  • To begin with i added a new configuration called "MOCK" (I will add the others in later)
  • Then under the project build settings I added a BUNDLE_SUFFIX user defined variable to my project and set it to MOCK for the MOCK configuration (I will add the others in later). This is used to set the bundle identifier for a build that uses the MOCK configuration.
  • Then under the project build settings, selected my MOCK provisioning profile for the MOCK configuration in build settings
  • I notice if i go to the summary view on my app target it displays the bundle id as UXXXXXX.au.com.blah.MOCK with the 'MOCK' part being in grey font - so it has picked up the bundle suffix variable
  • Then i created a new scheme called MOCK to use MOCK configuration for 'Profile' and 'Archive'. I left defaults for the rest (uses DEBUG).

So now I can run an xcodebuild and use scheme MOCK to do a MOCK specific build that will use the MOCK configuration to set the bundle identifier to .MOCK and set my provisoning profile to use _MOCK profile.

So i then run a jenkins build which does an xcodebuild and xcrun (which will call codesign).

This is my xcodebuild command:

/usr/bin/xcodebuild -scheme MOCK -sdk iphoneos -project MyApp.xcodeproj -configuration MOCK clean build "CONFIGURATION_BUILD_DIR=/Users/CI/Documents/workspace/build3" ONLY_ACTIVE_ARCH=NO DEPLOY_ENVIRONMENT=MOCK "CODE_SIGN_IDENTITY=iPhone Distribution: My Company" "PROVISIONING_PROFILE=XXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"

This is my xcrun command:

/usr/bin/xcrun -sdk iphoneos PackageApplication -v "/Users/Shared/Jenkins/Home/jobs/MyApp.app" -o "/Users/Shared/Jenkins/Home/jobs/MyApp/workspace/build/MyApp-0.9.5.0.ipa" --embed "/Users/Shared/Jenkins/Home/Library/MobileDevice/Provisioning Profiles/20130816_Distribution_MOCK.mobileprovision" --sign "iPhone Distribution: My Company"

NOTE: I specifically sign the app with the MOCK provisioning profile, as I worked out that I cannot sign the app with a .* profile, as the app uses push notifications and if I build the app with a .* and then re-sign the app with the proper profile, my embedded.mobileprovision profile gets updated, but the actual executable within the .app file never gets updated. And this causes push notifications to never get to the device. So what i need to get working is the ability to build and sign an app from command line with the app having a bundle id that is populated dynamically using a variable. And I cannot seem to get this working.

THE RESULTS

The xcodebuild runs successfully and works perfectly. The app appears to be built and signed properly as .MOCK and using the _MOCK provisioning profile!

BUT! The generating of the IPA file has an issue, I have an issue with the codesign.

Notice, that I built the app without any code signing entitlements. codesign gives me this error: warning: Application failed codesign verification. The signature was invalid, contains disallowed entitlements, or it was not signed with an iPhone Distribution Certificate. (-19011) Executable=/Users/CI/Documents/workspace/build3/MyApp.app/MyApp codesign_wrapper-4.1: using Apple CA for profile evaluation Illegal entitlement key/value pair: application-identifier, UXXXXXX.au.com.blah. AssertMacros: filter_entitlements(entitlements_whitelist, entitlements_requested, allowable_entitlements), file: codesign_wrapper.c, line: 932 - (null

Notice that it has not picked up the bundle_suffix. Also when i view the MyApp.xcent file that codesign references, I notice it has UXXXXXX.au.com.blah. in it. It has not picked up the value of the bundle_suffix!

So then, what i tried is to create an entitlements.plist file for my MOCK build configuration and add a link to the file under 'code signing entitlements' for MOCK configuration under the build settings. But now i get a different error, and its rather disturbing:

/usr/bin/codesign --force --sign 5XXXXXXXXXXXXXXXXXXX2c --resource-rules=/Users/CI/Documents/workspace/build3/MyApp.app/ResourceRules.plist --entitlements /Users/CI/Library/Developer/Xcode/DerivedData/MyApp-fasiktlyysoxjpgalujkfjpyiyeo/Build/Intermediates/MyApp.build/MOCK-iphoneos/MyApp.build/MyApp.xcent /Users/CI/Documents/workspace/build3/MyApp.app

Validate /Users/CI/Documents/workspace/build3/MyApp.app cd /Users/Shared/Jenkins/Home/jobs/MyApp-MOCK-HourlyBuilds/workspace setenv PATH "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/git/bin" setenv PRODUCT_TYPE com.apple.product-type.application /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/Validation /Users/CI/Documents/workspace/build3/MyApp.app warning: This bundle is invalid. The application-identifier entitlement is not formatted correctly; it should contain your 10-character App ID Seed, followed by a dot, followed by your bundle identifier: UXXXXXXXX.au.com.amp.blah.MOCK (-19054) Unable to validate your application. - (null)

This time is has actually picked up the proper bundle identifier!! It says MOCK it it. But it is complaining that this bundle is invalid... but it looks perfectly valid to me!! Why is it not working?

This is my entitlements.plist file that I manually created and added to the project (and reference in 'code signing entitlements'):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>application-identifier</key>
    <string>UXXXXXXXXXXX.au.com.amp.blah.MOCK</string>
    <key>aps-environment</key>
    <string>production</string>
    <key>get-task-allow</key>
    <false/>
    <key>keychain-access-groups</key>
    <array>
            <string>UXXXXXXXXXXX.au.com.amp.blah.MOCK</string>
    </array>
</dict>
</plist>

Any help would be greatly appeciated, many thanks!

P.S. I know that a way to get around this issue would be to create a different Target for each of my builds. But i dont really want this, as it is a pain maintaining multiple Targets. I really wanted to try and get away with this without having multiple Targets if I can.

P.S.S. I know another way to get around this issue is to sign the app initially with a .* provisioning profile and then resign the app after with the proper profile, however this does not work for me. As the executable file within .app still keeps references to the .* provisioning profile. And thus push notifications can never be picked up by this device. I get the “no valid 'aps-environment' entitlement string found for application” error.

4

1 回答 1

0

I am running a similar setup for my iOS builds via Jenkins, with the goal of allowing side-by-side installation of the app (production, staging, qa, dev) and ran into the same problem as you.

In the end, I stumbled upon this answer and modified it to include the .xcent file which is part of the xcodebuild (check build output for the path) for the --entitlements flag. This means you do not have to manually create the entitlements file, but can use the exact one xcodebuild produces for you.

I too was using xcrun PackageApplication, but this does NOT support entitlements so re-signing using this tool would lose the entitlements.

So, after running xcodebuild I use plistbuddy to modify my info.plist file to update the settings bundle, etc. (this may not be required for you) and I unpack the ipa, copy the profile and info.plist into the unpacked payload, re-sign and re-pack:

pushd ${SCRIPT_DIR}
unzip "${PROJECT_NAME}.${CURRENT_ENV_NAME}.ipa"
rm -r "Payload/${PROJECT_NAME}.app/_CodeSignature" "Payload/${PROJECT_NAME}.app/CodeResources" 2> /dev/null | true
cp "${PROFILE}" "Payload/${PROJECT_NAME}.app/embedded.mobileprovision"
cp "${BUILD_DIR}/${BUILD_TARGET}-iphoneos/${PROJECT_NAME}.app/Info.plist" "Payload/Yappem.app/Info.plist"
/usr/bin/codesign -f -s "${CODE_SIGN_IDENTITY}" --resource-rules "Payload/${PROJECT_NAME}.app/ResourceRules.plist" --entitlements "${XCENT_FILE}" "Payload/${PROJECT_NAME}.app"
if [ $? != 0 ]; then
  echo Error Signing Project
  exit 1
fi
rm "${PROJECT_NAME}.${CURRENT_ENV_NAME}.ipa"
zip -qr "${PROJECT_NAME}.${CURRENT_ENV_NAME}.ipa" Payload
popd
于 2013-12-27T08:24:54.790 回答