IOS build腳本

generate_manifest.py

#!/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)


build_ipa.sh:

#!/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

轉帖分析:

build_ipa.sh稍微修改一下,將該sh文件以及py文件全部放到文件目錄下,直接在Terminal中運行./build_ipa.sh就能生成所需要的ipa文件和manifest.plist文件,將這兩個文件放入服務器,並在服務器的網頁地址中加入<a href="itms-services://?action=download-manifest&url=http://服務器地址目錄/manifest.plist">,這個時候你就可以通過手機客戶端進入服務器網址下載程序了。


參考資料:

https://github.com/baz/ios-build-scripts/blob/master/generate_manifest.py

https://github.com/baz/ios-build-scripts

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章