-
Star
(209)
You must be signed in to star a gist -
Fork
(74)
You must be signed in to fork a gist
-
-
Save jonah-williams/949831 to your computer and use it in GitHub Desktop.
| #!/bin/bash | |
| # https://gist.github.com/949831 | |
| # http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/ | |
| # command line OTA distribution references and examples | |
| # http://nachbaur.com/blog/how-to-automate-your-iphone-app-builds-with-hudson | |
| # http://nachbaur.com/blog/building-ios-apps-for-over-the-air-adhoc-distribution | |
| # http://blog.octo.com/en/automating-over-the-air-deployment-for-iphone/ | |
| # http://www.neat.io/posts/2010/10/27/automated-ota-ios-app-distribution.html | |
| project_dir=`pwd` | |
| # Configuration | |
| environment_name="staging" | |
| keychain="ci_keys" | |
| keychain_password="super secret" | |
| workspace="MyApp.xcworkspace" | |
| scheme="Ad Hoc" | |
| info_plist="$project_dir/MyApp-Info.plist" | |
| environment_plist="$environment_name.plist" | |
| environment_info_plist="$environment_name-Info.plist" | |
| product_name="My App $environment_name" | |
| mobileprovision="$project_dir/ad_hoc/MyAppStaging.mobileprovision" | |
| provisioning_profile="iPhone Distribution: My Company, LLC" | |
| build_number="%env.BUILD_NUMBER%" | |
| artifacts_url="http://my_ci_server.example/artifacts/$build_number" | |
| display_image_name="Icon-57.png" | |
| full_size_image_name="Icon-512.png" | |
| function failed() | |
| { | |
| local error=${1:-Undefined error} | |
| echo "Failed: $error" >&2 | |
| exit 1 | |
| } | |
| function validate_keychain() | |
| { | |
| # unlock the keychain containing the provisioning profile's private key and set it as the default keychain | |
| security unlock-keychain -p "$keychain_password" "$HOME/Library/Keychains/$keychain.keychain" | |
| security default-keychain -s "$HOME/Library/Keychains/$keychain.keychain" | |
| #describe the available provisioning profiles | |
| echo "Available provisioning profiles" | |
| security find-identity -p codesigning -v | |
| #verify that the requested provisioning profile can be found | |
| (security find-certificate -a -c "$provisioning_profile" -Z | grep ^SHA-1) || failed provisioning_profile | |
| } | |
| function describe_sdks() | |
| { | |
| #list the installed sdks | |
| echo "Available SDKs" | |
| xcodebuild -showsdks | |
| } | |
| function describe_workspace() | |
| { | |
| #describe the project workspace | |
| echo "Available schemes" | |
| xcodebuild -list -workspace $workspace | |
| } | |
| function increment_version() | |
| { | |
| cd "MyApp" | |
| agvtool -noscm new-version -all $build_number | |
| cd .. | |
| } | |
| function set_environment() | |
| { | |
| #copy the info plist for the selected environment into place | |
| cp -v "MyApp/$environment_info_plist" $info_plist || failed environment_plist | |
| #copy the environment settings plist into place | |
| cp -v "MyApp/$environment_plist" "MyApp/environment.plist" || failed environment | |
| #extract settings from the Info.plist file | |
| info_plist_domain=$(ls $info_plist | sed -e 's/\.plist//') | |
| short_version_string=$(defaults read "$info_plist_domain" CFBundleShortVersionString) | |
| bundle_identifier=$(defaults read "$info_plist_domain" CFBundleIdentifier) | |
| echo "Environment set to $bundle_identifier at version $short_version_string" | |
| } | |
| function build_app() | |
| { | |
| local devired_data_path="$HOME/Library/Developer/Xcode/DerivedData" | |
| #get the name of the workspace to be build, used as the prefix of the DerivedData directory for this build | |
| local workspace_name=$(echo "$workspace" | sed -n 's/\([^\.]\{1,\}\)\.xcworkspace/\1/p') | |
| #build the app | |
| echo "Running xcodebuild > xcodebuild_output ..." | |
| # disabled overriding PRODUCT_NAME, setting applies to all built targets in Xcode 4 which renames static library target dependencies and breaks linking | |
| # xcodebuild -verbose -workspace "$workspace" -scheme "$scheme" -sdk iphoneos -configuration Release clean build PRODUCT_NAME="$product_name" >| xcodebuild_output | |
| xcodebuild -verbose -workspace "$workspace" -scheme "$scheme" -sdk iphoneos -configuration Release clean build >| xcodebuild_output | |
| if [ $? -ne 0 ] | |
| then | |
| tail -n20 xcodebuild_output | |
| failed xcodebuild | |
| fi | |
| #locate this project's DerivedData directory | |
| local project_derived_data_directory=$(grep -oE "$workspace_name-([a-zA-Z0-9]+)[/]" xcodebuild_output | sed -n "s/\($workspace_name-[a-z]\{1,\}\)\//\1/p" | head -n1) | |
| local project_derived_data_path="$devired_data_path/$project_derived_data_directory" | |
| #locate the .app file | |
| # infer app name since it cannot currently be set using the product name, see comment above | |
| # project_app="$product_name.app" | |
| project_app=$(ls -1 "$project_derived_data_path/Build/Products/Release-iphoneos/" | grep ".*\.app$" | head -n1) | |
| # if [ $(ls -1 "$project_derived_data_path/Build/Products/Release-iphoneos/$project_app" | wc -l) -ne 1 ] | |
| if [ $(ls -1 "$project_derived_data_path/Build/Products/Release-iphoneos/" | grep ".*\.app$" | wc -l) -ne 1 ] | |
| then | |
| echo "Failed to find a single .app build product." | |
| # echo "Failed to locate $project_derived_data_path/Build/Products/Release-iphoneos/$project_app" | |
| failed locate_built_product | |
| fi | |
| echo "Built $project_app in $project_derived_data_path" | |
| #copy app and dSYM files to the working directory | |
| cp -Rf "$project_derived_data_path/Build/Products/Release-iphoneos/$project_app" $project_dir | |
| cp -Rf "$project_derived_data_path/Build/Products/Release-iphoneos/$project_app.dSYM" $project_dir | |
| #rename app and dSYM so that multiple environments with the same product name are identifiable | |
| echo "Retrieving build products..." | |
| rm -rf $project_dir/$bundle_identifier.app | |
| rm -rf $project_dir/$bundle_identifier.app.dSYM | |
| mv -f "$project_dir/$project_app" "$project_dir/$bundle_identifier.app" | |
| echo "$project_dir/$bundle_identifier.app" | |
| mv -f "$project_dir/$project_app.dSYM" "$project_dir/$bundle_identifier.app.dSYM" | |
| echo "$project_dir/$bundle_identifier.app.dSYM" | |
| project_app=$bundle_identifier.app | |
| #relink CodeResources, xcodebuild does not reliably construct the appropriate symlink | |
| rm "$project_app/CodeResources" | |
| ln -s "$project_app/_CodeSignature/CodeResources" "$project_app/CodeResources" | |
| } | |
| function sign_app() | |
| { | |
| echo "Codesign as \"$provisioning_profile\", embedding provisioning profile $mobileprovision" | |
| #sign build for distribution and package as a .ipa | |
| xcrun -sdk iphoneos PackageApplication "$project_dir/$project_app" -o "$project_dir/$project_app.ipa" --sign "$provisioning_profile" --embed "$mobileprovision" || failed codesign | |
| } | |
| function verify_app() | |
| { | |
| #verify the resulting app | |
| codesign -d -vvv --file-list - "$project_dir/$project_app" || failed verification | |
| } | |
| function build_ota_plist() | |
| { | |
| echo "Generating $project_app.plist" | |
| cat << EOF > $project_app.plist | |
| <?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>items</key> | |
| <array> | |
| <dict> | |
| <key>assets</key> | |
| <array> | |
| <dict> | |
| <key>kind</key> | |
| <string>software-package</string> | |
| <key>url</key> | |
| <string>$artifacts_url/$project_app.ipa</string> | |
| </dict> | |
| <dict> | |
| <key>kind</key> | |
| <string>full-size-image</string> | |
| <key>needs-shine</key> | |
| <true/> | |
| <key>url</key> | |
| <string>$artifacts_url/$full_size_image_name</string> | |
| </dict> | |
| <dict> | |
| <key>kind</key> | |
| <string>display-image</string> | |
| <key>needs-shine</key> | |
| <true/> | |
| <key>url</key> | |
| <string>$artifacts_url/$display_image_name</string> | |
| </dict> | |
| </array> | |
| <key>metadata</key> | |
| <dict> | |
| <key>bundle-identifier</key> | |
| <string>$bundle_identifier</string> | |
| <key>bundle-version</key> | |
| <string>$short_version_string $build_number</string> | |
| <key>kind</key> | |
| <string>software</string> | |
| <key>subtitle</key> | |
| <string>$environment_name</string> | |
| <key>title</key> | |
| <string>$project_app</string> | |
| </dict> | |
| </dict> | |
| </array> | |
| </dict> | |
| </plist> | |
| EOF | |
| } | |
| echo "**** Validate Keychain" | |
| validate_keychain | |
| echo | |
| echo "**** Describe SDKs" | |
| describe_sdks | |
| echo | |
| echo "**** Describe Workspace" | |
| describe_workspace | |
| echo | |
| echo "**** Set Environment" | |
| set_environment | |
| echo | |
| echo "**** Increment Bundle Version" | |
| increment_version | |
| echo | |
| echo "**** Build" | |
| build_app | |
| echo | |
| echo "**** Package Application" | |
| sign_app | |
| echo | |
| echo "**** Verify" | |
| verify_app | |
| echo | |
| echo "**** Prepare OTA Distribution" | |
| build_ota_plist | |
| echo | |
| echo "**** Complete!" |
| **** Validate Keychain | |
| Available provisioning profiles | |
| 1) 0b1a9aaa619c6022e2f0e91c46af5209 "iPhone Distribution: MyCompany, LLC" | |
| 1 valid identities found | |
| SHA-1 hash: 0b1a9aaa619c6022e2f0e91c46af5209 | |
| **** Describe SDKs | |
| Available SDKs | |
| Mac OS X SDKs: | |
| Mac OS X 10.6 -sdk macosx10.6 | |
| iOS SDKs: | |
| iOS 4.3 -sdk iphoneos4.3 | |
| iOS Simulator SDKs: | |
| Simulator - iOS 3.2 -sdk iphonesimulator3.2 | |
| Simulator - iOS 4.0 -sdk iphonesimulator4.0 | |
| Simulator - iOS 4.1 -sdk iphonesimulator4.1 | |
| Simulator - iOS 4.2 -sdk iphonesimulator4.2 | |
| Simulator - iOS 4.3 -sdk iphonesimulator4.3 | |
| **** Describe Workspace | |
| Available schemes | |
| Information about workspace "My_App": | |
| Schemes: | |
| Ad Hoc | |
| Development | |
| **** Set Environment | |
| My_App/My_App/staging-Info.plist -> /Users/tester/TeamCity/build-agent-1/work/My_App_staging/My_App/My_App/My_App-Info.plist | |
| My_App/My_App/staging.plist -> My_App/My_App/environment.plist | |
| Environment set to com.MyCompany.My_App.staging at version 1.0 | |
| **** Increment Bundle Version | |
| Setting version of project My_App to: | |
| 24. | |
| Also setting CFBundleVersion key (assuming it exists) | |
| Updating CFBundleVersion in Info.plist(s)... | |
| Updated CFBundleVersion in "My_App.xcodeproj/../My_App/My_App-Info.plist" to 24 | |
| Updated CFBundleVersion in "My_App.xcodeproj/../My_AppTests/My_AppTests-Info.plist" to 24 | |
| **** Build | |
| Running xcodebuild > xcodebuild_output ... | |
| Built My_App staging.app in /Users/tester/Library/Developer/Xcode/DerivedData/My_App-dnzbsdgcbuvddhcenlrdqhdfjjmh | |
| Retrieving build products... | |
| /Users/tester/TeamCity/build-agent-1/work/My_App_staging/com.MyCompany.My_App.staging.app | |
| /Users/tester/TeamCity/build-agent-1/work/My_App_staging/com.MyCompany.My_App.staging.app.dSYM | |
| **** Package Application | |
| Codesign as "iPhone Distribution: MyCompany, LLC", embedding provisioning profile /Users/tester/TeamCity/build-agent-1/work/My_App_staging/ad_hoc/My_App_Staging_Ad_Hoc.mobileprovision | |
| **** Verify | |
| Executable=/Users/tester/TeamCity/build-agent-1/work/My_App_staging/com.MyCompany.My_App.staging.app/My_App staging | |
| Identifier=com.MyCompany.My_App.staging | |
| Format=bundle with Mach-O universal (armv6 armv7) | |
| CodeDirectory v=20100 size=3515 flags=0x0(none) hashes=167+5 location=embedded | |
| CDHash=eb62e8fe529a4dbdaef163509ffff137 | |
| Signature size=4317 | |
| Authority=iPhone Distribution: MyCompany, LLC | |
| Authority=Apple Worldwide Developer Relations Certification Authority | |
| Authority=Apple Root CA | |
| Signed Time=Jun 9, 2011 4:31:52 PM | |
| Info.plist entries=33 | |
| /Users/tester/TeamCity/build-agent-1/work/My_App_staging/com.MyCompany.My_App.staging.app/My_App staging | |
| Sealed Resources rules=3 files=97 | |
| /Users/tester/TeamCity/build-agent-1/work/My_App_staging/com.MyCompany.My_App.staging.app/_CodeSignature/CodeResources | |
| Internal requirements count=1 size=180 | |
| **** Prepare OTA Distribution | |
| Generating com.MyCompany.My_App.staging.app.plist | |
| **** Complete! |
As far as I can tell, setting the default keychain only affects which keychain new items are added to. I was having trouble because the keychain with my cert wasn't in the search list, and so wasn't picking up anything on it - despite setting the keychain to be the default.
I now have the following:
function backup_keychain_search_list() {
KEYCHAIN_SEARCH_LIST=`security list-keychains | cut -f 2 -d"`
}
function use_and_validate_keychain {
...
echo "Changing keychain search path to be ${full_keychain_path}"
security list-keychain -s "${full_keychain_path}"
echo "Changing default keychain to ${full_keychain_path}"
security default-keychain -s "${full_keychain_path}"
....
}
function cleanup() {
echo "Resetting the keychain search list"
security list-keychains -s ${KEYCHAIN_SEARCH_LIST}
echo "Resetting the default keychain to login"
security default-keychain -s login.keychain
}
have you try to change this to suit XCode-runner?
Thanks!
Hi, I am trying to use this script for automating my iOS project. I have one concern here is, I am finding it tough to do it with a workspace based project. Because, I have only worked in project based templates in Xcode and thus finding it tough to find the paths.
Could you please tell me how can I make it work for a project based template. It will be great if I can do that...
Thank you, very useful script!
Hi jonah , Can You Please Exp-lance how to use this script
Customize the variables in the "Configuration" section to match your app and build machine. You may also need to update the paths in "set_environment".
Once complete visit itms-services://?action=download-manifest&url=http://my_ci_server.example/path/to/project_app.plist to install ad hoc builds over the air. Requires that the installing device be added to your ad hoc provisioning profile and running iOS 4 or later.