ios 自动打包命令_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()
相关文章:

linux系统下添加新硬盘的方法详解
对于linux新手来说,在linux上添加新硬盘,是很有挑战性的一项工作。在Linux服务器上把硬盘接好,启动linux,以root登陆。 fdisk -l ## 这里是查看目前系统上有几块硬盘 Disk /dev/sda: 36.4 GB, 36401479680 bytes 255 heads, 63 s…

【CF EDU59 E】 Vasya and Binary String (DP)
题意 给一串01串,对该串进行若干次操作,直到串为空 操作为:选择一段连续的0或者1,删除它,拼接前后两部分成为新串,得到价值为a[删除的长度](a为给定的数组) 思路 一个非常规的DP 考虑题目所给的…

leetcode-21 合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例: 输入:1->2->4, 1->3->4 输出:1->1->2->3->4->4 总体思路是: 比较两个链表头节点,…

log4cxx第三篇----使用多个logger
使用多个logger时,所有logger的配置写在一个配置文件里面 两个例子: 1 一个继承的例子(http://logging.apache.org/log4cxx/) // file com/foo/bar.h #include "log4cxx/logger.h"namespace com {namespace foo {class…

authy不同账户间不同步_「第七期」shopify产品还能同步到微信小程序销售?看这里...
众所周知,微信坐拥12亿用户,已经是国民应用,而其中小程序依托于微信生态日活已经超过4亿,对于国内的一些商家来讲是不可错过的流量圣地,那么对于做跨境的朋友来讲怎么利用起来了?今天给大家介绍一款无缝对接…

Ubuntu环境变量
2019独角兽企业重金招聘Python工程师标准>>> Ubuntu 环境变量 环境变量配置文件 在Ubuntu中有如下几个文件可以设置环境变量 1、 /etc/profile:在登录时,操作系统定制用户环境时使用的第一个文件,此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执…

mysql 免安装
1. 解压得到如下目录 2. 配置环境变量 D:\Program Files\mysql-5.7.11-winx64\bin 3. 安装的根目录,新增 my.ini 文件 [mysqld] port 3306 character_set_serverutf8 basedir D:\Program Files\mysql-5.7.11-winx64 datadir D:\Program Files\mysql-5.7.…

leetcode-23 合并K个排序链表
合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。 示例: 输入: [ 1->4->5, 1->3->4, 2->6 ] 输出: 1->1->2->3->4->4->5->6 方法一: 使用vector数组存多个链表的所有节点,进行从小…

Access应用日志一
今天在确认实习生不能帮忙搭建数据库后,自己根据业务需求尝试搭了一个小型access数据库。 主要目的:储存历史月度数据,避免每次从公司数据库下载数据的麻烦,节省数据拉取时间。 搭建了以acct id为主键的两种数据。 1)客…

mongodb检查点_mongodb 监控命令mongostat
mongodb 监控命令mongostat2016/03/07 15:11 于 数据分析mongostat实用工具提供了mongoDB一个实例快速概述和当前运行的状态。mongostat功能类似于UNIX / Linux文件系统实用vmstat,mongostat只不过是提供 mongodb 的数据。监控包含的数据:服务器状态数据副本状态数据…

RunnableException与CheckedException
Checked Exception 编译时异常 编译的时候检查你的代码可能在运行的时候抛出异常,这通常在编译的时候要去处理的。 RunnableException 运行时异常,可以编译通过,但如果不处理运行时会导致崩溃,需要对其进行try....catch...处理。 …

Educational Codeforces Round 59 (Rated for Div. 2)
A.Digits Sequence Dividing 题意:给你一个1-9的数字字符串,把它划分成若干段(>2)段,使其大小递增。 错误:当长度为2的时候没考虑 #include<cstdio> #include<cmath> #include<cstring&g…

leetcode-225 队列实现栈
使用队列实现栈的下列操作: push(x) – 元素 x 入栈pop() – 移除栈顶元素top() – 获取栈顶元素empty() – 返回栈是否为空 队列的特点:先入先出 栈的特点:后入先出 即我们每次添加元素到队列时,想要达到栈的效果,…

详解Java Math类的toDegrees()方法:将参数从弧度转换为角度
Java Math 类的 toDegrees() 方法是将一个角度的弧度表示转换为其度表示,返回值为double类型,表示从弧度数转换而来的角度数。这就是Java Math 类的 toDegrees() 方法的攻略。我们已经了解了该方法的基本概念、语法、注意事项以及两个示例。希望这篇攻略对你有所帮助。

python语音合成 标贝_tacotronV2 + wavernn 实现中文语音合成(Tensorflow + pytorch)
TacotronV2 WaveRNN开源中文语音数据集标贝(女声)训练中文TacotronV2,实现中文到声学特征(Mel)转换的声学模型。在GTA模式下,利用训练好的TacotronV2合成标贝语音数据集中中文对应的Mel特征,作为声码器WaveRNN的训练数据。在合成阶段&#x…

SpringBoot接口防抖(防重复提交)的一些实现方案
作为一名老码农,在开发后端Java业务系统,包括各种管理后台和小程序等。在这些项目中,我设计过单/多租户体系系统,对接过许多开放平台,也搞过消息中心这类较为复杂的应用,但幸运的是,我至今还没有遇到过线上系统由于代码崩溃导致资损的情况。这其中的原因有三点:一是业务系统本身并不复杂;二是我一直遵循某大厂代码规约,在开发过程中尽可能按规约编写代码;三是经过多年的开发经验积累,我成为了一名熟练工,掌握了一些实用的技巧。啥是防抖所谓防抖,一是防用户手抖,二是防网络抖动。

OC语言基础笔记
OC方面的基础笔记:1.类的基本用法#import <Foundation/Foundation.h>// 大体上就是include, 用于包含头文件, 但是即使头文件中, 没有ifndef defined endif, 仍然能够踢除重复包含的头文件// ----interface section----// OC中声明和实现是分离的, 两个都必须有.interfac…

Docker 数据卷之进阶篇
Docker 数据卷之进阶篇 原文:Docker 数据卷之进阶篇笔者在《Docker 基础 : 数据管理》一文中介绍了 docker 数据卷(volume) 的基本用法。随着使用的深入,笔者对 docker 数据卷的理解与认识也在不断的增强。本文将在前文的基础上介绍 docker 数据卷的原理及一些高级用…

leetcode-232 用栈实现队列
使用栈实现队列的下列操作: push(x) – 将一个元素放入队列的尾部。pop() – 从队列首部移除元素。peek() – 返回队列首部的元素。empty() – 返回队列是否为空 栈的特点:后入先出 队列的特点:先入先出 使用一个数据栈,一个辅…

sparkcore分区_Spark学习:Spark源码和调优简介 Spark Core (二)
本文基于 Spark 2.4.4 版本的源码,试图分析其 Core 模块的部分实现原理,其中如有错误,请指正。为了简化论述,将部分细节放到了源码中作为注释,因此正文中是主要内容。第一部分内容见:Spark学习:…

Tips——IndexSearcher自动更新
情景描述 为了调高效率,创建全局变量IndexReader取代每次查询新建IndexReader所带来的效率问题。 当时每天会更新一边索引8.23号部署的Index服务,Search服务,结果index都更新到了8.25,查询结果还是8.23的 Tips分享 先来看一下Inde…

公司运作 - 利润率、周转率
公司一般由市场部、研发部、财务部、人力资源部及其他辅助部门组成。分成了几个层面,如下: 宏观层面:业务范围、业务定位、专业化、多元化部门层面:各部门绩效、部门职责主体层面:跨部门事务,如产品研发涉及…

测试用例设计方法基础理论知识
一、什么是测试用例 测试用例设计:将软件测试的行为活动,作为一个科学化的组织归纳。 测试用例:设计一个情况,软件程序在这种情况下,必须能够正常运行并且达到程序所设计的执行结果。 因为我们不可能进行穷举测试&…

leetcode-155 最小栈
设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。 push(x) – 将元素 x 推入栈中。pop() – 删除栈顶的元素。top() – 获取栈顶元素。getMin() – 检索栈中的最小元素。 示例: MinStack minStack new Mi…

legend位置 pyecharts_可视化入门 | pyecharts全局配置项详解
更多文章,请见:http://mp.weixin.qq.com/mp/homepage?__bizMzIxODczMDUwOA&hid2&sn7928727456d49032f08ef1fcf0ee719e&scene18#wechat_redirectmp.weixin.qq.com大家好,我是你们的机房老哥! 计算机绘图是老哥很早就…

查询Master下的系统表和系统视图获取数据库的信息和简单的渗透测试
在SQL中可以通过查询Master下的系统表(sys)和系统视图(information_schema)获取数据库的信息。SQL2000和SQL2005的结构略有不同。 系统表结构参考系统表详细说明。 系统信息结构图参考:http://dev.mysql.com/doc/refma…

cocos2d-x android 移植 问题
为什么80%的码农都做不了架构师?>>> 由于android系统目前没有将boost加入,这里面使用了大量的STL及C的一些语言特性,导致编译出现令人非常头痛的问题。 1、出现类似的异常函数错误 boost/exception/detail/exception_ptr.hpp:382…

python插入排序演示源码
工作闲暇时间,把写内容过程较好的内容段做个备份,下面的内容内容是关于python插入排序演示的内容,应该能对各朋友也有用处。 def insert_sort(t): for i in xrange(len(t)): key t[i] j i - 1 while j>-1 and t[j]>key:#如果当前值比…

leetcode-215 数组中的第K个最大元素
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k 2 输出: 5 该题比较简洁的解法,我们使用堆来完成 最小堆:即堆顶为所…

c++ double 只输出五位_c 语言第四章 在控制台上数据的输入和输出
1 数据输出我们之前已经使用过printf()函数来实现数据在控制台上输出#include<stdio.h> int main(){printf("hello world");return 0; }具体的用法是printf("数据模板",数据1,数据2,...)// 数据模板表示输出数据的形式,里面包含占位符,打印的时候使用…