Automated ad hoc builds using Xcode 4
来源:互联网 发布:淘宝好的手办店 编辑:程序博客网 时间:2024/05/22 15:53
I’ve previously discussed Continuous Integration for iPhone Projects in TeamCity using Xcode 3 and Building Xcode 4 Projects from the Command Line. Now I’ll tie those together and use TeamCity to automatically create ad hoc builds I can install over the air (directly onto a device without using iTunes) every time I check in code.
I created a basic project configuration in TeamCity 6 to checkout my iOS project from git.
I set the artifact paths for this configuration to
project_name.acceptance.app*
ad_hoc/*.png
This will eventually allow TeamCity to collect the icons, project_name.acceptance.app.ipa, and project_name.acceptance.app.plist files needed to perform an over the air install of the ad hoc build.
Finally I created the following custom script build step (available as https://gist.github.com/949831).
#!/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.htmlproject_dir=`pwd`# Configurationenvironment_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_keychainechoecho "**** Describe SDKs"describe_sdksechoecho "**** Describe Workspace"describe_workspaceechoecho "**** Set Environment"set_environmentechoecho "**** Increment Bundle Version"increment_versionechoecho "**** Build"build_appechoecho "**** Package Application"sign_appechoecho "**** Verify"verify_appechoecho "**** Prepare OTA Distribution"build_ota_plistechoecho "**** Complete!"
That is quite a few functions but the bottom of the script steps through them in what is hopefully an understandable sequence.
- Unlock the keychain containing the private key and provisioning profile used to sign the ad hoc build. Necessary since the TeamCity user’s login keychain may be locked when this build runs.
- List the available sdks on the build machine (unnecessary but I found it helpful when debugging build settings).
- List the schemes found in the workspace to be built (again purely for debugging).
- Copy a plist containing application settings to “environment.plist” which will be copied into the app bundle when built and used to define application behavior, for example it contains the url of the server this build should communicate with.
- Build the app using the specified workspace and scheme. Copy the resulting app and dSYM to the project directory so TeamCity can easily find them as build artifacts.
- Sign the app using the specified mobile provisioning profile and create a “.ipa” package.
- Verify that the app was successfully signed.
- Create a plist to allow over the air installation of the app.
Once run any device which has been added to the mobile provisioning profile used to sign this build can install the app just by visiting (using an appropriate %system.teamcity.buildType.id% for the TeamCity build configuration).
itms-services://?action=download-manifest&url=http://teamcity.example.com:8111/guestAuth/repository/download/%system.teamcity.buildType.id%/.lastSuccessful/project_name.acceptance.app.plist
Possible issues:
- Access to the keychain will present a security dialog the first time this build runs so it was necessary for me to sign into the TeamCity user’s account using VNC and allow access to that keychain.
- I found that builds occasionally failed to correctly create the CodeResources symlink so I recreate it manually. When this link was broken the ipa would fail verification.
- An iOS device won’t be able to install the app if the artifacts require authenticating to the TeamCity server so I enabled guest access. Alternately I could have exposed those artifacts through some other service and created a nice installation guide page which links to them if I didn’t want to allow guest access to my TeamCity server.
For additional resources for building over the air distribution builds take a look at:
Mike Nachbaur’s posts on “How to Automate your iPhone App Builds with Hudson” and “Building iOS Apps for Over the Air Ad Hoc Distribution“.
Vincent Daubry’s “Automating Over The Air Deployment for iPhone“.
Basil Shkara’s “Automated OTA iOS App Distribution“.
From: http://blog.carbonfive.com/2011/05/04/automated-ad-hoc-builds-using-xcode-4/
- Automated ad hoc builds using Xcode 4
- xcode [CCBReader readFloat] Ad Hoc Build
- Xcode 6.1 导出ad hoc的ipa
- Unity3d and automated builds
- [iOS] Xcode 4透過Ad-Hoc發佈App給其它裝置測試使用
- Xcode 4透過Ad-Hoc發佈App給其它裝置測試使用
- Xcode 4透過Ad-Hoc發佈App給其它裝置測試使用 <详细>
- [iOS] Xcode 4透過Ad-Hoc發佈App給其它裝置測試使用
- Ad-hoc
- Ad hoc
- Ad hoc
- Ad hoc
- Automated Builds on Docker Hub
- [iOS] Xcode 3打包Ad Hoc版本及安装
- Xcode透過Ad-Hoc發佈App給其它裝置測試使用
- Ad Hoc网络技术浅析
- Ad Hoc网络概述
- Ad Hoc Problems
- Windows下配置python环境变量
- C++继承中覆盖和隐藏基类成员变量或成员函数
- lxc
- 关于线程分离
- spring事务配置
- Automated ad hoc builds using Xcode 4
- gem5添加共享的L3cache,并将L2cache改为独立的
- S参数的含义
- 对vector的各种操作
- 数论基础
- HDU3613:Best Reward(拓展KMP)
- solarwinds kiwi syslog web access配置时报错
- 用hbase(0.92版本以上)的协处理器实现快速返回查询结果总数
- 二进制信号量,互斥信号和计数信号量的区别