-
-
Save jimmyeisenhauer/4177756 to your computer and use it in GitHub Desktop.
Command line iOS project builds and over-the-air distribution
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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!" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
**** 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! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment