随着苹果手持设备用户的不断增加,ios应用也增长迅速,同时随着iphone被越狱越来越多的app 的渠道也不断增多,为各个渠道打包成了一件费时费力的工作,本文提供一种比较智能的打包方式来减少其带来的各种不便。
自动化打包背景介绍
1、背景
2、ios程序包格式、渠道包格式
3、传统的ios打包方式
4、传统的打包带来的问题
自动化打包具体实现
C/C++ Code
复制内容到剪贴板
- xcodebuild[-project][-activetarget][-alltargets][-target]...[-parallelizeTargets][-activeconfiguration][-configuration][-sdk |][=]...[]...
- xcodebuild[-version[-sdk |]]
- xcodebuild[-showsdks]
- xcodebuild[-find ][-sdk |]
- xcodebuild[-list]
1、xcodebuild 介绍:
2、xcrun 介绍:
3、具体方案
一些问题
总结:
附录
利用xcode环境一次生成所有包的shell 脚本代码:
C/C++ Code
复制内容到剪贴板
- #!/bin/sh
- xcodebuild clean -configuration Distribution //clean项目
- distDir="/Users/xxxx/dist"
- releaseDir="build/Distribution-iphoneos"
- version="1_0_0"
- rm -rdf "$distDir"
- mkdir "$distDir"
- for line in $(cat data.dat) //读取所有渠道号data.dat文件
- do
- ipafilename=`echo $line|cut -f1 -d':'` //渠道名
- sourceid=`echo $line|cut -f2 -d':'` //渠道号
- echo "ipafilename=$ipaname"
- echo "sourceid=$sourceid"
- targetName="youtargename" //项目名称(xcode左边列表中显示的项目名称)
- echo "sourceid=$sourceid"
- echo "ipafilename=$ipafilename"
- echo "$sourceid" > sourceid.dat
- echo "sourceid.dat: "
- cat sourceid.dat
- rm -rdf "$releaseDir"
- ipapath="${distDir}/${targetName}_${version}_from_${sourceid}.ipa"
- echo "***开始build app文件***"
- xcodebuild -target "$targetName" -configuration Distribution -sdk iphoneos build
- appfile="${releaseDir}/${targetName}.app"
- if [ $sourceid == "appstore" ]
- then
- cd $releaseDir
- zip -r "${targetName}_${ipafilename}_${version}.zip" "${targetName}.app"
- mv "${targetName}_${ipafilename}.zip" $distDir 2> /dev/null
- cd ../..
- else
- echo "***开始打ipa渠道包****"
- /usr/bin/xcrun -sdk iphoneos PackageApplication -v "$appfile" -o "$ipapath" --sign "iPhone Distribution:xxxxxx"
- fi
- done
从ipa格式的母包生成其它渠道包的shell脚本实例:
复制内容到剪贴板
- #!/bin/sh
- sourceipaname="母包名.ipa"
- appname=”app文件名.app” //加压后Pauload目录项.app文件名需要根据自己的项目修改
- distDir="/Users/lxxx/Qa" //打包后文件存储目录
- version="1.0.0"
- rm -rdf "$distDir "
- mkdir "$distDir" unzip $sourceipaname //解压母包文件
- for line in $(cat data.dat) //读取渠道号文件并进行循环
- do
- ipafilename=`echo $line|cut -f1 -d':'`
- sourceid=`echo $line|cut -f2 -d':'`
- echo "ipafilename=$ipaname"
- echo "sourceid=$sourceid"
- targetName="ipa包名"
- echo "sourceid=$sourceid"
- echo "ipafilename=$ipafilename"
- cd Payload
- cd $appname
- echo "replace sourceid.dat before: "
- cat sourceid.dat
- echo "$sourceid" > sourceid.dat
- echo "replace sourceid.dat after: "
- cat sourceid.dat
- if [ $sourceid == "appstroe" ]
- then
- cd ..
- zip -r "${targetName}_${version}_from_${sourceid}.zip" $appname //appstore二进制文件
- mv "${targetName}_${version}_from_${sourceid}.zip" $distDir
- cd ..
- else
- cd ../..
- zip -r "${targetName}_${version}_from_${sourceid}.ipa" Payload //打成其他渠道的包
- mv "${targetName}_${version}_from_${sourceid}.ipa" $distDir
- fi
- done rm -rdf Payload
IOS build脚本
#!/usr/bin/python
from
optparse
import
OptionParser
import
shutil
import
fileinput
import
os
import
sys
import
glob
import
subprocess
import
plistlib
import
urlparse
import
string
import
fnmatch
parser
=
OptionParser
()
parser
.
add_option
(
'-f'
,
'--app-bundle'
,
action
=
'store'
,
dest
=
'app_bundle'
,
help
=
'Path to app bundle'
)
parser
.
add_option
(
'-a'
,
'--archive-name'
,
action
=
'store'
,
dest
=
'archive_name'
,
help
=
'Legacy archive filename'
)
parser
.
add_option
(
'-d'
,
'--deployment-address'
,
action
=
'store'
,
dest
=
'deployment_address'
,
help
=
'Remote deployment path, where the app will eventually be hosted'
)
parser
.
add_option
(
'-c'
,
'--changes-page-url'
,
action
=
'store'
,
dest
=
'changes_page_url'
,
help
=
'URL describing the changes that went into this build'
)
(
options
,
args
)
=
parser
.
parse_args
()
if
options
.
app_bundle
==
None
:
parser
.
error
(
"Please specify the file path to the app bundle."
)
elif
options
.
deployment_address
==
None
:
parser
.
error
(
"Please specify the deployment address."
)
elif
options
.
archive_name
==
None
:
parser
.
error
(
"Please specify the filename of the legacy archive."
)
elif
options
.
changes_page_url
==
None
:
parser
.
error
(
"Please specify a URL to a page listing the changes in this build."
)
class
IPAGenerator
(
object
):
"Generate index.html"
def
generate_html
(
self
,
app_name
):
HTML_FILENAME
=
'index.html'
index_file
=
open
(
HTML_FILENAME
,
'w'
)
index_file
.
write
(
self
.
template
(
app_name
))
return
HTML_FILENAME
"Locates the app's Info.plist"
def
info_plist_filename
(
self
):
filename
=
'Info.plist'
for
file
in
os
.
listdir
(
options
.
app_bundle
):
if
fnmatch
.
fnmatch
(
file
,
'*Info.plist'
):
filename
=
file
break
return
filename
"Generate manifest by parsing values from the app's Info.plist"
def
generate_manifest
(
self
,
app_name
):
filename
=
self
.
info_plist_filename
()
info_plist_filepath
=
os
.
path
.
join
(
options
.
app_bundle
,
filename
)
info_plist_xml_filename
=
'info_plist.xml'
# Use plutil to ensure that we are dealing with XML rather than the binary format
subprocess
.
Popen
(
'plutil -convert xml1 -o '
+
info_plist_xml_filename
+
' '
+
"'"
+
info_plist_filepath
+
"'"
,
shell
=
True
)
.
wait
()
info_plist_xml_file
=
open
(
info_plist_xml_filename
,
'r'
)
app_plist
=
plistlib
.
readPlist
(
info_plist_xml_file
)
os
.
remove
(
info_plist_xml_filename
)
MANIFEST_FILENAME
=
'manifest.plist'
manifest_plist
=
{
'items'
:
[
{
'assets'
:
[
{
'kind'
:
'software-package'
,
'url'
:
urlparse
.
urljoin
(
options
.
deployment_address
,
app_name
+
'.ipa'
),
}
],
'metadata'
:
{
'bundle-identifier'
:
app_plist
[
'CFBundleIdentifier'
],
'bundle-version'
:
app_plist
[
'CFBundleVersion'
],
'kind'
:
'software'
,
'title'
:
app_plist
[
'CFBundleName'
],
}
}
]
}
plistlib
.
writePlist
(
manifest_plist
,
MANIFEST_FILENAME
)
return
MANIFEST_FILENAME
"Template from http://github.com/HunterHillegas/iOS-BetaBuilder"
def
template
(
self
,
app_name
):
template_html
=
"""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>[BETA_NAME] - Beta Release</title>
<style type="text/css">
body {background:#fff;margin:0;padding:0;font-family:arial,helvetica,sans-serif;text-align:center;padding:10px;color:#333;font-size:16px;}
#container {width:300px;margin:0 auto;}
h1 {margin:0;padding:0;font-size:14px;}
p {font-size:13px;}
.link {background:#ecf5ff;border-top:1px solid #fff;border:1px solid #dfebf8;margin-top:.5em;padding:.3em;}
.link a {text-decoration:none;font-size:15px;display:block;color:#069;}
</style>
</head>
<body>
<div id="container">
<h1>iOS 4.0 Users:</h1>
<div class="link"><a href="itms-services://?action=download-manifest&url=[DEPLOYMENT_PATH]">Tap here to install<br />[BETA_NAME]<br />On Your Device</a></div>
<p><strong><em><a href="[BUILD_CHANGES_URL]">Tap here to view changes in this build</a></em></strong><br /></p>
<p><strong>Link didn't work?</strong><br />
Make sure you're visiting this page on your device, not your computer.</p>
<p><strong>On a version of iOS before 4.0?</strong><br />
Reload this page in your computer browser and download a zipped archive and provisioning profile here:
</p>
<div class="link"><a href="[BETA_ARCHIVE_FILENAME]">[BETA_NAME]<br />Archive w/ Provisioning Profile</a></div>
</div>
</body>
</html>
"""
TEMPLATE_PLACEHOLDER_NAME
=
'[BETA_NAME]'
TEMPLATE_PLACEHOLDER_DEPLOYMENT_PATH
=
'[DEPLOYMENT_PATH]'
TEMPLATE_PLACEHOLDER_ARCHIVE_FILENAME
=
'[BETA_ARCHIVE_FILENAME]'
TEMPLATE_PLACEHOLDER_BUILD_CHANGES_URL
=
'[BUILD_CHANGES_URL]'
template_html
=
string
.
replace
(
template_html
,
TEMPLATE_PLACEHOLDER_NAME
,
app_name
)
template_html
=
string
.
replace
(
template_html
,
TEMPLATE_PLACEHOLDER_DEPLOYMENT_PATH
,
options
.
deployment_address
)
template_html
=
string
.
replace
(
template_html
,
TEMPLATE_PLACEHOLDER_ARCHIVE_FILENAME
,
options
.
archive_name
)
template_html
=
string
.
replace
(
template_html
,
TEMPLATE_PLACEHOLDER_BUILD_CHANGES_URL
,
options
.
changes_page_url
)
return
template_html
generator
=
IPAGenerator
()
app_name
=
os
.
path
.
splitext
(
options
.
app_bundle
)[
0
]
html_filename
=
generator
.
generate_html
(
app_name
)
manifest_filename
=
generator
.
generate_manifest
(
app_name
)
#!/bin/bash
# Below are required environment variables with some example content:
# XCODE_BUILD_COMMAND='xcodebuild -sdk iphoneos4.1 -alltargets -configuration "Ad Hoc" clean build'
# XCODE_BUILD_CONFIGURATION='Ad Hoc'
# DISTRIBUTION_CERTIFICATE='iPhone Distribution: Your Company Pty Ltd'
# PROVISIONING_PROFILE_PATH='/Users/tomcat/Library/MobileDevice/Provisioning Profiles/Your_Company_Ad_Hoc.mobileprovision'
# GIT_BINARY='/usr/local/git/bin/git'
# REMOTE_HOST='your.remote.host.com'
# REMOTE_PARENT_PATH='/www/docs/ios_builds'
# MANIFEST_SCRIPT_LOCATION='http://github.com/baz/ios-build-scripts/raw/master/generate_manifest.py'
# ROOT_DEPLOYMENT_ADDRESS='http://your.remote.host.com/ios_builds'
# ARCHIVE_FILENAME='beta_archive.zip'
# KEYCHAIN_LOCATION='/Users/tomcat/Library/Keychains/Your Company.keychain'
# KEYCHAIN_PASSWORD='Password'
# Build project
security default-keychain -s
"$KEYCHAIN_LOCATION"
security unlock-keychain -p
$KEYCHAIN_PASSWORD
"$KEYCHAIN_LOCATION"
eval
$XCODE_BUILD_COMMAND
GIT_HASH
=
"$($GIT_BINARY log --pretty=format:'' | wc -l)-$($GIT_BINARY rev-parse --short HEAD)"
GIT_HASH
=
${
GIT_HASH
//[[:
space
:]]
}
BUILD_DIRECTORY
=
"$(pwd)/build/${XCODE_BUILD_CONFIGURATION}-iphoneos"
cd
"$BUILD_DIRECTORY"
|| die
"Build directory does not exist."
MANIFEST_SCRIPT
=
$(curl -fsS
$MANIFEST_SCRIPT_LOCATION
)
MANIFEST_OUTPUT_HTML_FILENAME
=
'index.html'
MANIFEST_OUTPUT_MANIFEST_FILENAME
=
'manifest.plist'
for APP_FILENAME in *.app;
do
APP_NAME
=
$(
echo
"$APP_FILENAME" | sed -e
's/.app//'
)
IPA_FILENAME
=
"$APP_NAME.ipa"
DSYM_FILEPATH
=
"$APP_FILENAME.dSYM"
/usr/bin/xcrun -sdk iphoneos PackageApplication -v
"$APP_FILENAME" -o
"$BUILD_DIRECTORY/$IPA_FILENAME" --sign
"$DISTRIBUTION_CERTIFICATE" --embed
"$PROVISIONING_PROFILE_PATH"
# Create legacy archive for pre iOS4.0 users
cp
"$PROVISIONING_PROFILE_PATH" .
PROVISIONING_PROFILE_FILENAME
=
$(basename
"$PROVISIONING_PROFILE_PATH"
)
zip
"$ARCHIVE_FILENAME"
"$IPA_FILENAME"
"$PROVISIONING_PROFILE_FILENAME"
rm
"$PROVISIONING_PROFILE_FILENAME"
# Output of this is index.html and manifest.plist
python -c
"$MANIFEST_SCRIPT" -f
"$APP_FILENAME" -d
"$ROOT_DEPLOYMENT_ADDRESS/$APP_NAME/$GIT_HASH/$MANIFEST_OUTPUT_MANIFEST_FILENAME" -a
"$ARCHIVE_FILENAME" -c
"$JOB_URL/$BUILD_NUMBER"
# Create tarball with .ipa, dSYM directory, legacy build and generated manifest files and scp them all across
PAYLOAD_FILENAME
=
'payload.tar'
tar -cf
$PAYLOAD_FILENAME
"$IPA_FILENAME"
"$DSYM_FILEPATH"
"$ARCHIVE_FILENAME"
"$MANIFEST_OUTPUT_HTML_FILENAME"
"$MANIFEST_OUTPUT_MANIFEST_FILENAME"
QUOTE
=
'"'
ssh
$REMOTE_HOST
"cd $REMOTE_PARENT_PATH; rm -rf ${QUOTE}$APP_NAME${QUOTE}/$GIT_HASH; mkdir -p ${QUOTE}$APP_NAME${QUOTE}/$GIT_HASH;"
scp
"$PAYLOAD_FILENAME"
"$REMOTE_HOST:$REMOTE_PARENT_PATH/${QUOTE}$APP_NAME${QUOTE}/$GIT_HASH"
ssh
$REMOTE_HOST
"cd $REMOTE_PARENT_PATH/${QUOTE}$APP_NAME${QUOTE}/$GIT_HASH; tar -xf $PAYLOAD_FILENAME; rm $PAYLOAD_FILENAME"
# Clean up
rm
"$IPA_FILENAME"
rm
"$ARCHIVE_FILENAME"
rm
"$MANIFEST_OUTPUT_HTML_FILENAME"
rm
"$MANIFEST_OUTPUT_MANIFEST_FILENAME"
rm
"$PAYLOAD_FILENAME"
done
80行脚本全自动批量编译打包iphone app
复制代码
|
复制代码