文章目录
  1. 1. Xcode控制台命令
  2. 2. 没有使用 cocoaPods 项目的编译
  3. 3. 使用了 cocoaPods 项目的编译
  4. 4. 打包ipa
  5. 5. python实现篇
    1. 5.1. clean、编译、打包
  6. 6. 上传Bugly
    1. 6.1. 运行脚本

本文介绍的是自动clean本地项目,编译 打包 上传Bugly。原理就是利用python执行控制台命令,对iOS项目进行打包,需要安装 Xcode、Python。

Xcode控制台命令

Xcode控制台命令基本都是以 xcodebuild 开头的介绍几个简单的命令,大家可以在命令行试试。

  • xcodebuild -version 查看xcode的版本号和build的版本号
  • xcodebuild -showsdks 显示当前系统的SDK、及其版本
  • xcodebuild -list 先 cd 到工程目录下执行此命令 显示 target Schemes

没有使用 cocoaPods 项目的编译

如果你的项目是普通的项目没有使用cocoaPods 那么 cd 到工程目录下直接执行 xcodebuild build ,就会自动编译了 参数都是默认 默认build Release。

你也可以指定 xcodebuild -configuration Debug build build的时候会在你工程目录下生成一个build文件夹,build/Debug-iphoneos/xx.app

就是一会打包成ipa需要的文件。 第一次build速度会比较慢,要把编译环境拉下来,不要删除build文件夹,以后build 速度就会变快。

使用了 cocoaPods 项目的编译

如果你使用了cocoaPods编译的时候就比较麻烦了 ,首先还是 cd 到项目目录 。

但是你要指定编译文件和 scheme 而且还要指定build后build文件夹的位置,如果位置找不到,后面怎么自动打包ipa?

我这里的命令大概是这样的:

1
xcodebuild -workspace xxx.xcworkspace -scheme 你的scheme -configuration Debug -derivedDataPath 指定路径 ONLY_ACTIVE_ARCH=NO

这样就能正常编译并把build指定到我们想要去的目录

打包ipa

打包ipa只要上面路径对了,打包指定从.app 文件的路径 , 打包到你指定地方就行了。

命令:xcrun -sdk iphoneos PackageApplication -v 这里填.app的路径 -o 指定存放ipa路径/文件名.ipa

python实现篇

上面只是说了下编译的原理,下面看下怎么通过python自动处理这些任务 。

clean、编译、打包

首先创建一个 autoipa.py 文件,然后把生成好的文件放到项目根目录下面 需要你懂点python 语法,不要改tab 。python的语法是严格按照tab区分的。

首先你需要引入一些外部依赖。设置编码为utf-8

1
2
3
4
5
6
7
8
9
10
# -*- coding: utf-8 -*-
import os
import sys
import time
import hashlib
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib

第一步 , 声明一些变量

1
2
3
4
5
6
7
8
9
10
11
12
# 项目TARGET名称
target_name = "xx"
# 编译时的配置 Debug、Release
build_config = "Release"
# 项目根目录
project_path = os.getcwd() ##获得当前的路径
# 编译成功后.app所在目录
app_path = project_path + "/build/" + build_config + "-iphoneos/" + target_name + ".app"
# 指定项目下编译目录
build_path = "build"
# 打包后ipa存储目录
targerIPA_parth = project_path + "/build/ipa"

第二步,clean,和创建一个文件夹,这里的示例是针对有使用cocoaPods的项目 , 如果没有使用 不用创建文件夹 ,命令自行简化

1
2
3
4
# 清理项目 创建build目录
def clean_project_mkdir_build():
os.system('cd %s;xcodebuild clean -configuration %s -alltargets' % (project_path,build_config)) # clean 项目
os.system('cd %s;mkdir build' % project_path)

%s 是py的占位符,字符串类型。后面是真正的填充。

第三步编译项目

1
2
3
4
5
def build_project():
print('build %s start' % (build_config))
os.system ('xcodebuild -list')
os.system ('cd %s;xcodebuild -configuration %s || exit' % (project_path,build_config))
# os.system ('cd %s;xcodebuild -workspace xx.xcworkspace -scheme xx -configuration %s -derivedDataPath %s ONLY_ACTIVE_ARCH=NO || exit' % (project_path,build_config,build_path))

不知道 scheme 是啥的 xcodebuild -list 自己查

第四步 打包

1
2
3
4
5
6
# 打包ipa 并且保存在build目录
def build_ipa():
global ipa_filename
ipa_filename = time.strftime(target_name+'_%m%d%H%M.ipa',time.localtime(time.time()))
os.system('mkdir %s' % targerIPA_parth)
os.system('xcrun -sdk iphoneos PackageApplication -v %s -o %s/%s'%(app_path,targerIPA_parth,ipa_filename))

然后你现在再编写个方法,按顺序调用就可以编译打包了 ,执行完会看到桌面的ipa

1
2
3
4
5
6
7
def main():
# 清理并创建build目录
clean_project_mkdir_build()
# 编译coocaPods项目文件并 执行编译目录
build_project()
# 打包ipa 并制定到桌面
build_ipa()

执行就在最下面直接调用就行了 main()

上传Bugly

我们是把代码上传到Bugly测试的,如果你们用的fir、蒲公英或者其他,请自行搜索。

需要先去Bugly官网拿到相应的API参数,然后再在变量区加上

1
2
3
4
5
6
7
8
9
10
11
# Bugly的相关信息
bugly_pid = "2"
bugly_app_id = "xxxxxx"
bugly_app_key = "xxxxxxxxxx"
# 如果不是发布新版本该变量设置为空字符串
bugly_app_title = ""
# 更新已上传版本的版本id,如果不清楚请在网站后台打开版本详情,然后在URL中versions节点后面找到exp_id
# 例:https://beta.bugly.qq.com/apps/900041236/versions/ce924c28-911f-4b51-a541-3754fbb3b7f8?pid=2
bugly_app_exp_id = "ce924c28-911f-4b51-a541-3754fbb3b7f8"

然后命令传入ipa目录就可以上传了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查询Bugly版本列表
def list_exp_bugly():
print('watting...')
os.system("curl --insecure 'https://api.bugly.qq.com/beta/apiv1/exp_list?app_id=%s&pid=%s&app_key=%s&start=0&limit=100'" % (bugly_app_id,bugly_pid,bugly_app_key))
# 上传新版本到Bugly
def upload_bugly():
if os.path.exists("%s/%s" % (targerIPA_parth,ipa_filename)):
print('watting for upload new version...')
# 使用系统自带工具 curl 上传文件
ret = os.system("curl --insecure -F 'file=@%s/%s' -F 'app_id=%s' -F 'pid=%s' -F 'title=%s' https://api.bugly.qq.com/beta/apiv1/exp?app_key=%s" % (targerIPA_parth,ipa_filename,bugly_app_id,bugly_pid,bugly_app_title,bugly_app_key))
else:
print("没有找到ipa文件!!!")
# 更新版本安装包
def update_bugly():
if os.path.exists("%s/%s" % (targerIPA_parth,ipa_filename)):
print('watting for update ipa file...')
# 使用系统自带工具 curl 上传文件
ret = os.system("curl --insecure -X 'PUT' -F 'file=@%s/%s' -F 'exp_id=%s' https://api.bugly.qq.com/beta/apiv1/exp?app_key=%s" % (targerIPA_parth,ipa_filename,bugly_app_exp_id,bugly_app_key))
else:
print("没有找到ipa文件!!!")

然后执行顺序是这样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def main():
# 清理并创建build目录
clean_project_mkdir_build()
# 编译coocaPods项目文件并 执行编译目录
build_project()
# 打包ipa 并制定到桌面
build_ipa()
if len(bugly_app_title):
# 上传新版本
upload_bugly()
else:
# 更新版本安装包
update_bugly()

运行脚本

  1. cd 项目根目录
  2. python autoipa.py

附上完整的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# -*- coding: utf-8 -*-
import os
import sys
import time
import hashlib
from email import encoders
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr, formataddr
import smtplib
import subprocess
import time
# 项目TARGET名称
target_name = "xx"
# 编译时的配置 Debug、Release
build_config = "Release"
# Bugly的相关信息
bugly_pid = "2"
bugly_app_id = "xxxxx"
bugly_app_key = "xxxxxxxxxx"
# 如果不是发布新版本该变量设置为空字符串
bugly_app_title = ""
# 更新已上传版本的版本id,如果不清楚请在网站后台打开版本详情,然后在URL中versions节点后面找到exp_id
# 例:https://beta.bugly.qq.com/apps/900041236/versions/ce924c28-911f-4b51-a541-3754fbb3b7f8?pid=2
bugly_app_exp_id = "ce924c28-911f-4b51-a541-3754fbb3b7f8"
#--------------------- 分界线:上面的变量是需要我们手动填写的 ---------------------
# 项目根目录
project_path = os.getcwd()
# 编译成功后.app所在目录
app_path = project_path + "/build/" + build_config + "-iphoneos/" + target_name + ".app"
# 指定项目下编译目录
build_path = "build"
# 打包后ipa存储目录
targerIPA_parth = project_path + "/build/ipa"
# 清理项目 创建build目录
def clean_project_mkdir_build():
os.system('cd %s;xcodebuild clean -configuration %s -alltargets' % (project_path,build_config)) # clean 项目
os.system('cd %s;mkdir build' % project_path)
# 恢复App的版本号(去除时间标记)
def recover_app_short_version():
app_version = subprocess.check_output("/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' %s/Info.plist" % (target_name), shell=True).strip('\n')
version_split = []
for item in app_version.split('.'):
if (len(item) < 8):
version_split.append(item)
app_version = '.'.join(version_split)
os.system("/usr/libexec/PlistBuddy -c 'Set :CFBundleShortVersionString %s' %s/Info.plist" % (app_version,target_name))
# 编辑App的版本号(加入时间标记)
def modify_app_short_version():
recover_app_short_version()
app_version = subprocess.check_output("/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' %s/Info.plist" % (target_name), shell=True).strip('\n')
datestr = time.strftime('%Y%m%d%H%M', time.localtime())
os.system("/usr/libexec/PlistBuddy -c 'Set :CFBundleShortVersionString %s.%s' %s/Info.plist" % (app_version,datestr,target_name))
def build_project():
print('build %s start' % (build_config))
os.system ('xcodebuild -list')
os.system ('cd %s;xcodebuild -configuration %s || exit' % (project_path,build_config))
# os.system ('cd %s;xcodebuild -workspace xx.xcworkspace -scheme xx -configuration %s -derivedDataPath %s ONLY_ACTIVE_ARCH=NO || exit' % (project_path,build_config,build_path))
# 打包ipa 并且保存在build目录
def build_ipa():
global ipa_filename
ipa_filename = time.strftime(target_name+'_%m%d%H%M.ipa',time.localtime(time.time()))
os.system('mkdir %s' % targerIPA_parth)
os.system('xcrun -sdk iphoneos PackageApplication -v %s -o %s/%s'%(app_path,targerIPA_parth,ipa_filename))
# 查询Bugly版本列表
def list_exp_bugly():
print('watting...')
os.system("curl --insecure 'https://api.bugly.qq.com/beta/apiv1/exp_list?app_id=%s&pid=%s&app_key=%s&start=0&limit=100'" % (bugly_app_id,bugly_pid,bugly_app_key))
# 上传新版本到Bugly
def upload_bugly():
if os.path.exists("%s/%s" % (targerIPA_parth,ipa_filename)):
print('watting for upload new version...')
# 使用系统自带工具 curl 上传文件
ret = os.system("curl --insecure -F 'file=@%s/%s' -F 'app_id=%s' -F 'pid=%s' -F 'title=%s' https://api.bugly.qq.com/beta/apiv1/exp?app_key=%s" % (targerIPA_parth,ipa_filename,bugly_app_id,bugly_pid,bugly_app_title,bugly_app_key))
else:
print("没有找到ipa文件!!!")
# 更新版本安装包
def update_bugly():
if os.path.exists("%s/%s" % (targerIPA_parth,ipa_filename)):
print('watting for update ipa file...')
# 使用系统自带工具 curl 上传文件
ret = os.system("curl --insecure -X 'PUT' -F 'file=@%s/%s' -F 'exp_id=%s' https://api.bugly.qq.com/beta/apiv1/exp?app_key=%s" % (targerIPA_parth,ipa_filename,bugly_app_exp_id,bugly_app_key))
else:
print("没有找到ipa文件!!!")
# def main():
# list_exp_bugly() ##查询版本列表
def main():
# 清理并创建build目录
clean_project_mkdir_build()
# 编辑App版本号(加入时间标记)
modify_app_short_version()
# 编译项目文件
build_project()
# 恢复App的版本号(去除时间标记)
recover_app_short_version()
# 打包ipa 并放到指定路径
build_ipa()
if len(bugly_app_title):
# 上传新版本
upload_bugly()
else:
# 更新版本安装包
update_bugly()
# 执行
main()

使用脚本打包上传到App Store可以参考这篇文章:详解Shell脚本实现iOS自动化编译打包提交