追风之影

何以追风,以影追风,风过之处,在此留痕。

iOS自动打包上传脚本

| 评论

自从将swift2.2升级到swift3.0, 每次使用Xcode8编译都很慢,很是不爽,于是有了研究下xcodebuild命令行打包的想法,起初不知道用shell,还是用python, 在网上大概搜了一下,关于python的比较多点,于是就先学习python的基础语法,然后再去看看大神的一些脚本,就开始专研命令行打包了。总之,过程很艰辛,结果很满意,以下便是我修改后的python自动打包脚本,命令行使用,打包完成会询问是否上传蒲公英平台,以及询问是否上传appstore,还有是否保留archive文件。
自动打包脚本下载地址

使用方法

1、下载完成后,将autobuild.py以及exportOptions.plist文件放到你的项目跟目录下(即与xx.xcworkspace或者xx.xcworkspace在同一个目录下)
2、打开autobuild.py,修改配置信息
3、打开命令终端,进入项目根目录
      a.如果你是xx.xcodeproj
   ./autobuild.py -p youproject.xcodeproj
      b.如果你是xx.xcworkspace
   ./autobuild.py -w youproject.xcworkspace

4、等待终端回应,依据终端提示进行相关操作
5、最终会在桌面生成带有时间戳的文件夹,含义ipa以及xcarchive文件

#!/usr/bin/env python
# -*- coding:utf-8 -*-

#./autobuild.py -p youproject.xcodeproj
#./autobuild.py -w youproject.xcworkspace

import argparse
import subprocess
import requests
import os
import datetime

#configuration for iOS build setting
CONFIGURATION = "Release"
EXPORT_OPTIONS_PLIST = "exportOptions.plist"

#发布版本号
VERSION = '1.0.0'
BUILD = '17021803'

#要打包的TARGET名字
TARGET = 'ULife'

#Info.plist路径
PLIST_PATH = "xxxxxx/Info.plist"

#存放路径以时间命令
DATE = datetime.datetime.now().strftime('%Y-%m-%d_%H.%M.%S')

#会在桌面创建输出ipa文件的目录
EXPORT_MAIN_DIRECTORY = "~/Desktop/" + TARGET + DATE

#xcarchive文件路径(含有dsym),后续查找BUG用途
ARCHIVEPATH = EXPORT_MAIN_DIRECTORY + "/%s%s.xcarchive" %(TARGET,VERSION)

#ipa路径
IPAPATH = EXPORT_MAIN_DIRECTORY + "/%s.ipa" %(TARGET)

#苹果开发者账号
APPLEID = 'xxxxxx'
APPLEPWD = 'xxxxx'

# configuration for pgyer
PGYER_UPLOAD_URL = "http://www.pgyer.com/apiv1/app/upload"
DOWNLOAD_BASE_URL = "http://www.pgyer.com"
USER_KEY = "xxxxxx"
API_KEY = "xxxxx"
#设置从蒲公英下载应用时的密码
PYGER_PASSWORD = "xxxxx"

def cleanArchiveFile():
    cleanCmd = "rm -r %s" %(ARCHIVEPATH)
    process = subprocess.Popen(cleanCmd, shell = True)
    process.wait()
    print "cleaned archiveFile: %s" %(ARCHIVEPATH)

def uploadIpaToAppStore():
    print "iPA上传中...."
    altoolPath = "/Applications/Xcode.app/Contents/Applications/Application\ Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/altool"

    exportCmd = "%s --validate-app -f %s -u %s -p %s -t ios --output-format xml" % (altoolPath, IPAPATH, APPLEID,APPLEPWD)
    process = subprocess.Popen(exportCmd, shell=True)
    (stdoutdata, stderrdata) = process.communicate()

    validateResult = process.returncode
    if validateResult == 0:
        print '~~~~~~~~~~~~~~~~iPA验证通过~~~~~~~~~~~~~~~~'
        exportCmd = "%s --upload-app -f %s -u %s -p %s -t ios --output-format normal" % (
        altoolPath, IPAPATH, APPLEID, APPLEPWD)
        process = subprocess.Popen(exportCmd, shell=True)
        (stdoutdata, stderrdata) = process.communicate()

        uploadresult = process.returncode
        if uploadresult == 0:
            print '~~~~~~~~~~~~~~~~iPA上传成功'
        else:
            print '~~~~~~~~~~~~~~~~iPA上传失败'
    else:
        print "~~~~~~~~~~~~~~~~iPA验证失败~~~~~~~~~~~~~~~~"

def parserUploadResult(jsonResult):
    resultCode = jsonResult['code']
    if resultCode == 0:
        downUrl = DOWNLOAD_BASE_URL +"/"+jsonResult['data']['appShortcutUrl']
        print "Upload Success"
        print "DownUrl is:" + downUrl
    else:
        print "Upload Fail!"
        print "Reason:"+jsonResult['message']

def uploadIpaToPgyer(ipaPath):
    print "ipaPath:"+ipaPath
    ipaPath = os.path.expanduser(ipaPath)
    ipaPath = unicode(ipaPath, "utf-8")
    files = {'file': open(ipaPath, 'rb')}
    headers = {'enctype':'multipart/form-data'}
    payload = {'uKey':USER_KEY,'_api_key':API_KEY,'publishRange':'2','isPublishToPublic':'2', 'password':PYGER_PASSWORD}
    print "uploading...."
    r = requests.post(PGYER_UPLOAD_URL, data = payload ,files=files,headers=headers)
    if r.status_code == requests.codes.ok:
        result = r.json()
        parserUploadResult(result)
    else:
        print 'HTTPError,Code:'+r.status_code

def exportArchive():
    exportCmd = "xcodebuild -exportArchive -archivePath %s -exportPath %s -exportOptionsPlist %s" %(ARCHIVEPATH, EXPORT_MAIN_DIRECTORY, EXPORT_OPTIONS_PLIST)
    process = subprocess.Popen(exportCmd, shell=True)
    (stdoutdata, stderrdata) = process.communicate()

    signReturnCode = process.returncode
    if signReturnCode != 0:
        print "export %s failed" %(TARGET)
        return ""
    else:
        return EXPORT_MAIN_DIRECTORY

def buildProject(project):
    archiveCmd = 'xcodebuild -project %s -scheme %s -configuration %s archive -archivePath %s -destination generic/platform=iOS' %(project, TARGET, CONFIGURATION, ARCHIVEPATH)
    process = subprocess.Popen(archiveCmd, shell=True)
    process.wait()

    archiveReturnCode = process.returncode
    if archiveReturnCode != 0:
        print "archive project %s failed" %(project)
        cleanArchiveFile()

def buildWorkspace(workspace):
    archiveCmd = 'xcodebuild -workspace %s -scheme %s -configuration %s archive -archivePath %s -destination generic/platform=iOS' %(workspace, TARGET, CONFIGURATION, ARCHIVEPATH)
    process = subprocess.Popen(archiveCmd, shell=True)
    process.wait()

    archiveReturnCode = process.returncode
    if archiveReturnCode != 0:
        print "archive workspace %s failed" %(workspace)
        cleanArchiveFile()

def xcbuild(options):
    project = options.project
    workspace = options.workspace

    if project is None and workspace is None:
        pass
    elif project is not None:
        buildProject(project)
    elif workspace is not None:
        buildWorkspace(workspace)

    #导出ipa文件
    exportarchive = exportArchive()
    print "~~~~~~~~~~~~~~~~是否上传到蒲公英~~~~~~~~~~~~~~~~"
    print "        1 不上传 (默认)"
    print "        2 上传 "
    isuploadpgyer = raw_input("您的决定:")
    if isuploadpgyer == "2" and exportarchive != "":
        uploadIpaToPgyer(IPAPATH)

    print "~~~~~~~~~~~~~~~~是否上传到AppStore~~~~~~~~~~~~~~~~"
    print "        1 不上传 (默认)"
    print "        2 上传 "
    isuploadappstore = raw_input("您的决定:")
    if isuploadappstore == '2':
        uploadIpaToAppStore()
    else:
        print "~~~~~~~~~~~~~~~~是否删除archive文件~~~~~~~~~~~~~~~~"
        print "        1 保留 (默认)"
        print "        2 删除 "
        iscleararchive = raw_input("您的决定:")
        if iscleararchive == "2":
            cleanArchiveFile()


def main():

    parser = argparse.ArgumentParser()
    parser.add_argument("-w", "--workspace", help="Build the workspace name.xcworkspace.", metavar="name.xcworkspace")
    parser.add_argument("-p", "--project", help="Build the project name.xcodeproj.", metavar="name.xcodeproj")

    options = parser.parse_args()

    print "options: %s" % (options)

    os.system('/usr/libexec/PlistBuddy -c "Set:CFBundleShortVersionString %s" %s' % (VERSION,PLIST_PATH))
    os.system('/usr/libexec/PlistBuddy -c "Set:CFBundleVersion %s" %s' % (BUILD, PLIST_PATH))

    xcbuild(options)

if __name__ == '__main__':
    main()


评论