├── README.md
├── certificates
├── 650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision
├── apple.cer
├── dist.cer
└── dist.p12
├── circle_sample_xcodeproj.yml
├── circle_sample_xcworkspace.yml
└── scripts
├── add-key.sh
├── build-ipa.sh
├── deploy.sh
├── remove-key.sh
└── upload-ipa-to-deploygate.sh
/README.md:
--------------------------------------------------------------------------------
1 | # ios-circleci-deploygate-scripts
2 | ## これは何?
3 | iOSアプリケーションを[CircleCI](https://circleci.com/)でビルドして[DeployGate](https://deploygate.com/)でアドホックビルドを配布するための手順、設定ファイル、シェルスクリプトをまとめています。
4 |
5 | ## ファイル一覧
6 |
7 | |ファイル|内容|
8 | |:-------|:---|
9 | |certificates|ipaファイルを作成するために必要になる証明書、プロビジョニングファイルの見本|
10 | |circle_sample_xcodeproj.yml|CocoaPodsを使用しない場合のcircle.ymlの見本|
11 | |circle_sample_xcworkspace.yml|CocoaPodsを使用する場合のcircle.ymlの見本|
12 | |scripts|ビルドするためのシェルスクリプト|
13 |
14 | ## 手順
15 |
16 | 1. CircleCIの設定
17 | 2. 証明書、プロビジョニングファイル作成
18 | 3. circle.yml作成
19 | 4. 環境変数の設定
20 | 5. deploy.shの修正
21 |
22 | ## 1. CircleCIの設定
23 | CircleCIにログインして、Project Setting -> Experimental Settings の Build iOS projectをONにします。
24 |
25 | ## 2. 証明書、プロビジョニングファイル作成
26 | 以下のプロビジョニングファイルを作成します。
27 |
28 | - <PROFILE_UUID>.mobileprovision
29 |
30 |
31 | Appleの「Certificates, Identifiers & Profiles」サイトからアドホックビルド用のプロビジョニングファイルをダウンロードします。
32 | ファイル名は「<PROFILE_UUID>.mobileprovision」という形式とします。PROFILE_UUIDは、mobileprovisionファイルを開いて以下の箇所を確認します。
33 |
34 | ```
35 | UUID
36 | xxxxxxxxxx-11111-0000-xxxx-111111111
37 | ```
38 |
39 | 以下の証明書を作成します。
40 |
41 | - apple.cer
42 | - dist.cer
43 | - dist.p12
44 |
45 | ### apple.cer
46 | キーチェーンで"Apple Worldwide Developer Relations Certification Authority"という項目を選び、書き出します。出力するフォーマットとしては「証明書 (.cer)」を選びます。
47 |
48 | ### dist.cer
49 | 使用するプロビジョニングファイルに対応している証明書をキーチェーンで選び、書き出します。出力するフォーマットとしては「証明書 (.cer)」を選びます。
50 |
51 | ### dist.p12
52 | 使用するプロビジョニングファイルに対応している証明書をキーチェーンで選び、書き出します。出力するフォーマットとしては「個人情報交換 (.p12)」を選びます。書き出しのときにパスワードを設定します。このパスワードは後で使用するので覚えておきます。
53 |
54 | 作成した証明書、プロビジョニングファイルはcertificatesディレクトリ以下に配置します。
55 |
56 | ## 3. circle.yml作成
57 | circle.ymlを作成します。CocoaPodsを使用しない(.xcodeprojを使用する)場合はcircle_sample_xcodeproj.yml、CocoaPodsを使用する(.xcworkspaceを使用する)場合はcircle_sample_xcworkspace.ymlを元にして作成します。
58 |
59 | 「machine: environment:」の箇所は以下の表を参考に値を設定します。
60 |
61 | |変数名|内容|設定例|
62 | |:-----|:---|:-----|
63 | |XCODE_WORKSPACE|Xcodeのworkspace名|CircleCI-Sample.xcworkspace|
64 | |XCODE_SCHEME|Xcodeのビルド対象スキーム名|CircleCI-Sample|
65 | |XCODE_PROJECT|Xcodeのプロジェクト名|CircleCI-Sample.xcodeproj|
66 | |XCODE_TARGET|Xcodeのビルドターゲット名|CircleCI-Sample|
67 | |APPNAME|アプリケーション名|CircleCI-Sample|
68 | |DEPLOYGATE_USER_NAME|deploygateユーザ名|XXX|
69 | |DEVELOPER_NAME|キーチェーンの証明書の「通称」|"iPhone Distribution: XXX (CTQDM00000)"|
70 | |PROFILE_NAME|プロビジョニングファイル名|"650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision"|
71 |
72 | ## 4. 環境変数の設定
73 | CircleCIのWeb画面で、以下のふたつの環境変数を設定します。
74 |
75 | - DEPLOYGATE_API_TOKEN
76 | - P12_FILE_PASSWORD
77 |
78 | DEPLOYGATE_API_TOKENは、deploygateのAPI keyです。[https://deploygate.com/settings](https://deploygate.com/settings)から確認できます。
79 |
80 | P12_FILE_PASSWORDは、p12ファイルを書き出したときに指定したパスワードです。
81 |
82 | ## 5. deploy.shの修正
83 |
84 | CocoaPodsを使うかどうかによってビルド方法が変わるので、scripts/deploy.shを修正します。
85 |
86 | ### CocoaPodsを使う場合の例
87 |
88 | ```
89 | ./scripts/build-ipa.sh \
90 | -d "$DEVELOPER_NAME" -a "$APPNAME" \
91 | -p "$PROFILE_NAME" \
92 | -s "$XCODE_SCHEME" \
93 | -w "$XCODE_WORKSPACE" \
94 | -c "$config" \
95 | -o "$output_path"
96 | ```
97 |
98 | ### CocoaPodsを使わない場合の例
99 |
100 | ```
101 | ./scripts/build-ipa.sh \
102 | -d "$DEVELOPER_NAME" -a "$APPNAME" \
103 | -p "$PROFILE_NAME" \
104 | -t "$XCODE_TARGET" \
105 | -c "$config" \
106 | -o "$output_path"
107 | ```
108 |
109 | ## その他
110 | このビルドスクリプトでは、XcodeのConfigurationごとにAdhocビルドを作成するようになっています。ConfigurationごとにアプリのBundleIDを変更して、一度に複数のAdhocビルドを作成することを想定しています。
111 |
112 | 標準ではConfigurationとしてReleaseを指定してビルドします。それを変更するには、scripts/deploy.shの以下の箇所を変更します。
113 |
114 | ```
115 | configuration_list=("Release")
116 | ```
117 |
118 | ここにビルドしたいConfigurationを書きます。例えば「Release」「Adhoc」というふたつのConfigurationでビルドするときは次のように設定します。
119 |
120 | ```
121 | configuration_list=("Release" "Adhoc")
122 | ```
123 |
124 | この設定の場合、ReleaseとAdhocでそれぞれAdhocビルドを作成してdeploygateにデプロイします。
125 |
126 | ## 参考
127 | - [Test iOS applications - CircleCI](https://circleci.com/docs/ios)
128 | - [DeployGate API](https://deploygate.com/docs/api)
129 | - [infolens/CircleCI-iOS-TestFlight-Sample](https://github.com/infolens/CircleCI-iOS-TestFlight-Sample)
130 |
131 |
--------------------------------------------------------------------------------
/certificates/650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faithcreates/ios-circleci-deploygate-scripts/c554987deb399c7b42108a1a2c01e26d94261cb6/certificates/650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision
--------------------------------------------------------------------------------
/certificates/apple.cer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faithcreates/ios-circleci-deploygate-scripts/c554987deb399c7b42108a1a2c01e26d94261cb6/certificates/apple.cer
--------------------------------------------------------------------------------
/certificates/dist.cer:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faithcreates/ios-circleci-deploygate-scripts/c554987deb399c7b42108a1a2c01e26d94261cb6/certificates/dist.cer
--------------------------------------------------------------------------------
/certificates/dist.p12:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/faithcreates/ios-circleci-deploygate-scripts/c554987deb399c7b42108a1a2c01e26d94261cb6/certificates/dist.p12
--------------------------------------------------------------------------------
/circle_sample_xcodeproj.yml:
--------------------------------------------------------------------------------
1 | # CocoaPodsを使用しない(.xcodeprojを使用する)場合の例
2 | machine:
3 | environment:
4 | XCODE_SCHEME: CircleCI-Sample
5 | XCODE_PROJECT: CircleCI-Sample.xcodeproj
6 | XCODE_TARGET: CircleCI-Sample
7 | APPNAME: CircleCI-Sample
8 | DEPLOYGATE_USER_NAME: XXX
9 | DEVELOPER_NAME: "iPhone Distribution: XXX (CTQDM00000)"
10 | PROFILE_NAME: "650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision"
11 | # DEPLOYGATE_API_TOKEN: set from web form
12 | # P12_FILE_PASSWORD: set from web form
13 | test:
14 | override:
15 | - xcodebuild
16 | CODE_SIGNING_REQUIRED=NO
17 | CODE_SIGN_IDENTITY=
18 | PROVISIONING_PROFILE=
19 | -project CircleCI-Sample.xcodeproj -scheme CircleCI-Sample -configuration Release -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=8.1,name=iPhone 6'
20 | clean test
21 |
22 | deployment:
23 | deploygate:
24 | branch: master
25 | owner: xxx
26 | commands:
27 | - ./scripts/add-key.sh
28 | - ./scripts/deploy.sh
29 | - ./scripts/remove-key.sh
30 |
31 |
--------------------------------------------------------------------------------
/circle_sample_xcworkspace.yml:
--------------------------------------------------------------------------------
1 | # CocoaPodsを使用する(.xcworkspaceを使用する)場合の例
2 | machine:
3 | environment:
4 | XCODE_SCHEME: CircleCI-Sample
5 | XCODE_WORKSPACE: CircleCI-Sample.xcworkspace
6 | APPNAME: CircleCI-Sample
7 | DEPLOYGATE_USER_NAME: XXX
8 | DEVELOPER_NAME: "iPhone Distribution: XXX (CTQDM00000)"
9 | PROFILE_NAME: "650f2f4c-f93d-40c2-b91a-1111111111.mobileprovision"
10 | # DEPLOYGATE_API_TOKEN: set from web form
11 | # P12_FILE_PASSWORD: set from web form
12 | dependencies:
13 | override:
14 | - pod install:
15 | timeout: 300
16 | test:
17 | override:
18 | - xctool -workspace CircleCI-Sample.xcworkspace -scheme CircleCI-Sample -sdk iphonesimulator clean build test
19 | deployment:
20 | deploygate:
21 | branch: master
22 | owner: xxx
23 | commands:
24 | - ./scripts/add-key.sh
25 | - ./scripts/deploy.sh
26 | - ./scripts/remove-key.sh
27 |
28 |
--------------------------------------------------------------------------------
/scripts/add-key.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | main()
4 | {
5 | local keychain_password=circleci
6 | local certificates_dir=$1
7 | local p12_file_password=$2
8 |
9 | security create-keychain -p "$keychain_password" ios-build.keychain
10 | security import "${certificates_dir}/apple.cer" -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
11 | security import "${certificates_dir}/dist.cer" -k ~/Library/Keychains/ios-build.keychain -T /usr/bin/codesign
12 | security import "${certificates_dir}/dist.p12" -k ~/Library/Keychains/ios-build.keychain -P "$p12_file_password" -T /usr/bin/codesign
13 | security list-keychain -s ~/Library/Keychains/ios-build.keychain
14 | security unlock-keychain -p "$keychain_password" ~/Library/Keychains/ios-build.keychain
15 |
16 | mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
17 | cp "${certificates_dir}"/*.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/
18 | }
19 |
20 | main "./certificates" "$P12_FILE_PASSWORD"
21 |
22 |
--------------------------------------------------------------------------------
/scripts/build-ipa.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | # ビルドしてipaファイルを作成する
5 | #
6 |
7 | declare -r SCRIPT_NAME=${0##*/}
8 |
9 | print_usage()
10 | {
11 | cat << EOF
12 | Usage:
13 | 1st form:
14 | $SCRIPT_NAME [-o OUTPUT_PATH] [-c CONFIGURATION] [-m PROVISIONING_FILE_DIR] -d DEVELOPER_NAME -a APPNAME -p PROVISIONING_FILE -s XCODE_SCHEME -w XCODE_WORKSPACE
15 |
16 | 2nd form:
17 | $SCRIPT_NAME [-o OUTPUT_PATH] [-c CONFIGURATION] [-m PROVISIONING_FILE_DIR] -d DEVELOPER_NAME -a APPNAME -p PROVISIONING_FILE -t XCODE_TARGET
18 |
19 | Build iOS project and create ipa file. Use 1st form to build iOS project with CocoaPods. Use 2nd form to build iOS project without CocoaPods.
20 |
21 | -o OUTPUT_PATH Output path (default: \$PWD/build)
22 | -c CONFIGURATION Build configuration (default: Release)
23 | -d DEVELOPER_NAME Identity in Keychanin
24 | -a APPNAME iOS application name
25 | -p PROVISIONING_FILE mobileprovision file name
26 | -m PROVISIONING_FILE_DIR mobileprovision file directory (default: \$HOME/Library/MobileDevice/Provisioning Profiles)
27 | -s XCODE_SCHEME Xcode scheme(build target name)
28 | -w XCODE_WORKSPACE Xcode workspace name
29 | -t XCODE_TARGET Xcode target
30 | -h display this help and exit
31 |
32 | Examples
33 | $SCRIPT_NAME -o \$PWD/build -d "iPhone Distribution: FaithCreates Inc." -a CircleCI-Sample -p 6d7927d4-5e5d-4d32-b4bc-111111111111.mobileprovision -s CircleCI-Sample -w CircleCI-Sample.xcworkspace
34 |
35 | $SCRIPT_NAME -o \$PWD/build -d "iPhone Distribution: FaithCreates Inc." -a CircleCI-Sample -p 6d7927d4-5e5d-4d32-b4bc-111111111111.mobileprovision -t CircleCI-Sample
36 | EOF
37 | }
38 |
39 | print_error()
40 | {
41 | echo "$SCRIPT_NAME: $*" 1>&2
42 | echo "Try \`-h' option for more information." 1>&2
43 | }
44 |
45 | main()
46 | {
47 | local output_path="$PWD/build"
48 | local developer_name=''
49 | local appname=''
50 | local provisioning_file=''
51 | local provisioning_file_dir="$HOME/Library/MobileDevice/Provisioning Profiles"
52 | local xcode_scheme=''
53 | local xcode_workspace=''
54 | local xcode_target=''
55 | local configuration='Release'
56 |
57 | local option
58 | local OPTARG
59 | local OPTIND
60 | while getopts ':o:c:d:a:p:m:s:w:t:h' option; do
61 | case $option in
62 | o)
63 | output_path=$OPTARG
64 | ;;
65 | c)
66 | configuration=$OPTARG
67 | ;;
68 | d)
69 | developer_name=$OPTARG
70 | ;;
71 | a)
72 | appname=$OPTARG
73 | ;;
74 | p)
75 | provisioning_file=$OPTARG
76 | ;;
77 | m)
78 | provisioning_file_dir=$OPTARG
79 | ;;
80 | s)
81 | xcode_scheme=$OPTARG
82 | ;;
83 | w)
84 | xcode_workspace=$OPTARG
85 | ;;
86 | t)
87 | xcode_target=$OPTARG
88 | ;;
89 | h)
90 | print_usage
91 | return 0
92 | ;;
93 | :) #オプション引数欠如
94 | print_error "option requires an argument -- $OPTARG"
95 | return 1
96 | ;;
97 | *) #不明なオプション
98 | print_error "invalid option -- $OPTARG"
99 | return 1
100 | ;;
101 | esac
102 | done
103 | shift $((OPTIND - 1))
104 |
105 | if [ -z "$output_path" ]; then
106 | print_error 'you must specify output_path'
107 | return 1
108 | fi
109 |
110 | if [ -z "$configuration" ]; then
111 | print_error 'you must specify configuration'
112 | return 1
113 | fi
114 |
115 | if [ -z "$developer_name" ]; then
116 | print_error 'you must specify developer_name'
117 | return 1
118 | fi
119 |
120 | if [ -z "$appname" ]; then
121 | print_error 'you must specify appname'
122 | return 1
123 | fi
124 |
125 | if [ -z "$provisioning_file" ]; then
126 | print_error 'you must specify provisioning_file'
127 | return 1
128 | fi
129 |
130 | if [ -z "$provisioning_file_dir" ]; then
131 | print_error 'you must specify provisioning_file_dir'
132 | return 1
133 | fi
134 |
135 | # 1st formの場合、xcode_schemeは空でない、xcode_workspaceは空でない、xcode_targetは空
136 | # 2nd formの場合、xcode_schemeは空、xcode_workspaceは空、xcode_targetは空でない
137 | if [ -n "$xcode_target" ]; then
138 | # 2nd formの場合
139 | # if [ -n "$xcode_target" ]; then
140 | if [ -n "$xcode_scheme" ]; then
141 | print_error "you don't need to specify both xcode_target and xcode_scheme"
142 | return 1
143 | fi
144 |
145 | if [ -n "$xcode_workspace" ]; then
146 | print_error "you don't need to specify both xcode_target xcode_workspace"
147 | return 1
148 | fi
149 | else
150 | # 1st formの場合
151 | if [ -z "$xcode_scheme" ]; then
152 | print_error 'you must specify xcode_scheme or xcode_target'
153 | return 1
154 | fi
155 |
156 | if [ -z "$xcode_workspace" ]; then
157 | print_error 'you must specify xcode_workspace or xcode_target'
158 | return 1
159 | fi
160 | fi
161 |
162 | # 末尾の/を取り除きます
163 | # ただし、"/"である場合はそのままとします
164 | if [ "$provisioning_file_dir" != "/" ]; then
165 | provisioning_file_dir="${provisioning_file_dir%/}"
166 | fi
167 |
168 | local provisioning_profile_path="${provisioning_file_dir}/$provisioning_file"
169 |
170 | # Archive
171 | if [ -n "$xcode_target" ]; then
172 | # workspace指定なしの場合
173 | xcodebuild \
174 | -target "$xcode_target" \
175 | -configuration "$configuration" \
176 | clean build \
177 | CODE_SIGN_IDENTITY="$developer_name" \
178 | CONFIGURATION_BUILD_DIR="$output_path"
179 | else
180 | # workspace指定ありの場合
181 | xcodebuild \
182 | -scheme "$xcode_scheme" \
183 | -workspace "$xcode_workspace" \
184 | -configuration "$configuration" \
185 | clean build \
186 | CODE_SIGN_IDENTITY="$developer_name" \
187 | CONFIGURATION_BUILD_DIR="$output_path"
188 | fi
189 |
190 | if [ "$?" -ne 0 ]; then
191 | print_error 'fail to archive'
192 | return 1
193 | fi
194 |
195 | # Signing
196 | xcrun -log -sdk iphoneos PackageApplication \
197 | "${output_path}/${appname}.app" \
198 | -o "${output_path}/${appname}.ipa" \
199 | -sign "$developer_name" \
200 | -embed "$provisioning_profile_path"
201 |
202 | # 作成したipaファイルのパス = ${output_path}/${appname}.ipa
203 | }
204 |
205 | main "$@"
206 |
207 |
--------------------------------------------------------------------------------
/scripts/deploy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | configuration_list=("Release")
4 |
5 | release_date=$(TZ=JST-9 date '+%Y-%m-%d %H:%M:%S')
6 | message="Build: ${CIRCLE_BUILD_NUM}, Uploaded: $release_date"
7 |
8 | for config in "${configuration_list[@]}"; do
9 | output_path="$PWD/build/${config}"
10 |
11 | ./scripts/build-ipa.sh \
12 | -d "$DEVELOPER_NAME" -a "$APPNAME" \
13 | -p "$PROFILE_NAME" \
14 | -t "$XCODE_TARGET" \
15 | -c "$config" \
16 | -o "$output_path"
17 |
18 | ./scripts/upload-ipa-to-deploygate.sh \
19 | -u "$DEPLOYGATE_USER_NAME" -t "$DEPLOYGATE_API_TOKEN" -m "$message" \
20 | "${output_path}/${APPNAME}.ipa"
21 | done
22 |
23 |
--------------------------------------------------------------------------------
/scripts/remove-key.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | security delete-keychain ios-build.keychain
4 | rm -f ~/Library/MobileDevice/Provisioning\ Profiles/*
5 |
--------------------------------------------------------------------------------
/scripts/upload-ipa-to-deploygate.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | #
4 | # deploygate.comにipaファイルをアップロードする
5 | #
6 |
7 | declare -r SCRIPT_NAME=${0##*/}
8 |
9 | print_usage()
10 | {
11 | cat << EOF
12 | Usage: $SCRIPT_NAME -u USER_NAME -t TOKEN [-m MESSAGE] IPA_PATH
13 | Upload ipa file to deploygate.com
14 |
15 | -u USER_NAME deploygate user name
16 | -t TOKEN deploygate API token
17 | -h display this help and exit
18 | EOF
19 | }
20 |
21 | print_error()
22 | {
23 | echo "$SCRIPT_NAME: $*" 1>&2
24 | echo "Try \`-h' option for more information." 1>&2
25 | }
26 |
27 | main()
28 | {
29 | local user_name=''
30 | local api_token=''
31 | local file_path=''
32 | local message=''
33 |
34 | local option
35 | local OPTARG
36 | local OPTIND
37 | while getopts ':u:t:m:h' option; do
38 | case $option in
39 | u)
40 | user_name=$OPTARG
41 | ;;
42 | t)
43 | api_token=$OPTARG
44 | ;;
45 | m)
46 | message=$OPTARG
47 | ;;
48 | h)
49 | print_usage
50 | return 0
51 | ;;
52 | :) #オプション引数欠如
53 | print_error "option requires an argument -- $OPTARG"
54 | return 1
55 | ;;
56 | *) #不明なオプション
57 | print_error "invalid option -- $OPTARG"
58 | return 1
59 | ;;
60 | esac
61 | done
62 | shift $((OPTIND - 1))
63 |
64 | file_path=$1
65 |
66 | if [ -z "$user_name" ]; then
67 | print_error 'you must specify user name'
68 | return 1
69 | fi
70 |
71 | if [ -z "$api_token" ]; then
72 | print_error 'you must specify api token'
73 | return 1
74 | fi
75 |
76 | if [ -z "$file_path" ]; then
77 | print_error 'you must specify file path'
78 | return 1
79 | fi
80 |
81 | curl \
82 | -F file="@${file_path}" \
83 | -F "token=${api_token}" \
84 | -F message="${message}" \
85 | -F disable_notify=yes \
86 | "https://deploygate.com/api/users/${user_name}/apps"
87 | }
88 |
89 | main "$@"
90 |
91 |
--------------------------------------------------------------------------------