Python的iOS自动化打包实例代码

??????? 这段时间刚刚学习了一段时间的Python,加上自己是做iOS开发的,就想着用Python来做一个自动化打包,可以自动完成打包,上传到蒲公英,并且发送邮箱给测试人员,一是可以减少打包功夫,二来可以练练手,结合自己的工作来输出一点东西.废话不多说,直接上代码...


原理:就是使用xcodebuild来控制Xcode进行一系列的操作,从而完成打包的操作.

思路:找到对应的项目->clean项目->archive项目->export IPA->上传蒲公英->发送邮件->收工。

运行环境:Python, Xcode 这些需要大家直接去搭建好环境...

准备工作:下载安装pycharm(这只是我开发Python的工具而已,大家可以根据自己喜欢的来选择)->注册并认证蒲公英(不认证的话,是不能上传的)

->邮箱开启POP3/SMTP服务(我使用的是QQ邮箱),记录下16位授权码->一个ExportOptions.plist文件, 这个下面会解释为什么需要还有怎么生成!->

一份iOS项目代码→_→


完整代码

#参考文章https://juejin.im/post/5bed3657518825604e0e4289
#引入requests会报错https://blog.csdn.net/dongdong9223/article/details/81517182
import os
import webbrowser
import subprocess
import time
import smtplib
import requests

from email.mime.text import MIMEText
from email import encoders
from email.header import Header
from email.utils import parseaddr, formataddr

# 项目名称
project_name = 'JDReader'

# 项目路径
archive_workspace_path = "/Users/liping5/Desktop/JDReader"

#输出的文件夹
export_directory = "archive"

#蒲公英的APP地址
ipa_download_url = "https://www.pgyer.com/5PJl"

#蒲公英账号USER_KEY,
USER_KEY = '0ee08c7c0f56e0e3888a68892f41a745'

#蒲公英账号API_KEY
API_KEY = '0e4505a4b02ae0e26c615dc5173be43c'


# 发送人的地址
#from_address = '1169440180@qq.com'
from_address = '774428436@qq.com'

# 邮箱密码换成他提供的16位授权码,qq邮箱获取方法:https://jingyan.baidu.com/article/fedf0737af2b4035ac8977ea.html
#password = 'lclhontgpudyigih'
password = 'axpdicnmogmcbbeg'

# 收件人地址,可以是多个的
to_address = '1169440180@qq.com;liping5@jd.com;zhangxiliang@jd.com;mengzhaohe@jd.com;wuge@jd.com'

# 因为我是使用QQ邮箱..
smtp_server = 'smtp.qq.com'



class AutoArchive(object):
??? """自动打包并上传到蒲公英,发邮件通知"""

??? def __init__(self):
??????? pass

??? def clean(self):
??????? print("\n\n===========开始clean操作===========")
??????? start = time.time()
??????? clean_command = 'xcodebuild clean -workspace %s/%s.xcworkspace -scheme %s -configuration Release' % (
??????????? archive_workspace_path, project_name, project_name)
??????? clean_command_run = subprocess.Popen(clean_command, shell=True)
??????? clean_command_run.wait()
??????? end = time.time()
??????? # Code码
??????? clean_result_code = clean_command_run.returncode
??????? if clean_result_code != 0:
??????????? print("=======clean失败,用时:%.2f秒=======" % (end - start))
??????? else:
??????????? print("=======clean成功,用时:%.2f秒=======" % (end - start))
??????????? self.archive()


??? def archive(self):
??????? print("\n\n===========开始archive操作===========")

??????? # 删除之前的文件
??????? subprocess.call(['rm', '-rf', '%s/%s' % (archive_workspace_path, export_directory)])
??????? time.sleep(1)
??????? # 创建文件夹存放打包文件
??????? subprocess.call(['mkdir', '-p', '%s/%s' % (archive_workspace_path, export_directory)])
??????? time.sleep(1)

??????? start = time.time()
??????? archive_command = 'xcodebuild archive -workspace %s/%s.xcworkspace -scheme %s -configuration Release -archivePath %s/%s' % (
??????????? archive_workspace_path, project_name, project_name, archive_workspace_path, export_directory)
??????? archive_command_run = subprocess.Popen(archive_command, shell=True)
??????? archive_command_run.wait()
??????? end = time.time()
??????? # Code码
??????? archive_result_code = archive_command_run.returncode
??????? if archive_result_code != 0:
??????????? print("=======archive失败,用时:%.2f秒=======" % (end - start))
??????? else:
??????????? print("=======archive成功,用时:%.2f秒=======" % (end - start))
??????????? # 导出IPA
??????????? self.export()


??? def export(self):
??????? print("\n\n===========开始export操作===========")
??????? print("\n\n==========请你耐心等待一会~===========")
??????? start = time.time()
??????? # export_command = 'xcodebuild -exportArchive -archivePath /Users/liangk/Desktop/TestArchive/myArchivePath.xcarchive -exportPath /Users/liangk/Desktop/TestArchive/out -exportOptionsPlist /Users/liangk/Desktop/TestArchive/ExportOptions.plist'
??????? export_command = 'xcodebuild -exportArchive -archivePath %s/%s.xcarchive -exportPath %s/%s -exportOptionsPlist %s/ExportOptions.plist' % (
??????????? archive_workspace_path, export_directory, archive_workspace_path, export_directory, archive_workspace_path)
??????? export_command_run = subprocess.Popen(export_command, shell=True)
??????? export_command_run.wait()
??????? end = time.time()
??????? # Code码
??????? export_result_code = export_command_run.returncode
??????? if export_result_code != 0:
??????????? print("=======导出IPA失败,用时:%.2f秒=======" % (end - start))
??????? else:
??????????? print("=======导出IPA成功,用时:%.2f秒=======" % (end - start))
??????????? # 删除archive.xcarchive文件
??????????? subprocess.call(['rm', '-rf', '%s/%s.xcarchive' % (archive_workspace_path, export_directory)])
??????????? self.upload('%s/%s/%s.ipa' % (archive_workspace_path, export_directory, project_name))


??? def upload(self, ipa_path):
??????? print("\n\n===========开始上传蒲公英操作===========")
??????? if ipa_path:
??????????? # https://www.pgyer.com/doc/api 具体参数大家可以进去里面查看,
??????????? url = 'http://www.pgyer.com/apiv1/app/upload'
??????????? data = {
??????????????? 'uKey': USER_KEY,
??????????????? '_api_key': API_KEY,
??????????????? 'installType': '1',
??????????????? 'updateDescription': description
??????????? }
??????????? files = {'file': open(ipa_path, 'rb')}
??????????? r = requests.post(url, data=data, files=files)
??????????? if r.status_code == 200:
??????????????? # 是否需要打开浏览器
??????????????? # self.open_browser(self)
??????????????? self.send_email()
??????? else:
??????????? print("\n\n===========没有找到对应的ipa===========")
??????? return

??? @staticmethod
??? def open_browser(self):
??????? webbrowser.open(ipa_download_url, new=1, autoraise=True)

??? @staticmethod
??? def _format_address(self, s):
??????? name, address = parseaddr(s)
??????? return formataddr((Header(name, 'utf-8').encode(), address))


??? def send_email(self):
??????? # https://www.pgyer.com/XXX app地址
??????? # 只是单纯的发了一个文本邮箱,具体的发附件和图片大家可以自己去补充
??????? msg = MIMEText('<html><body><h1>Hello</h1>' +
?????????????????? '<p>╮(╯_╰)╭<a href='+ipa_download_url+'>京东读书版本已更新,请下载测试</a>╮(╯_╰)╭</p>' +
?????????????????? '<p>蒲公英的更新会有延迟,具体版本时间以邮件时间为准</p>' +
?????????????????? '</body></html>', 'html', 'utf-8')
??????? msg['From'] = self._format_address(self, 'iOS开发团队 <%s>' % from_address)
??????? msg['Subject'] = Header('来自iOS开发团队的问候……', 'utf-8').encode()
??????? server = smtplib.SMTP(smtp_server, 25)? # SMTP协议默认端口是25
??????? server.set_debuglevel(1)
??????? server.login(from_address, password)
??????? server.sendmail(from_address, to_address.split(';'), msg.as_string())
??????? server.quit()
??????? print("===========邮件发送成功===========")


if __name__ == '__main__':
??? description = input("请输入内容:")
??? archive = AutoArchive()
??? archive.clean()


关于ExportOptions.plist文件:因为 Xcode 9+ 默认不允许访问钥匙串的内容,必须要设置 allowProvisioningUpdates 才会允许,Python的Xcode插件目前无法支持此项完成打包流程。

解决步骤如下:

1、手动Xcode10打包,导出ExportOptions.plist文件;

2、编辑ExportOptions.plist文件,配置?provisioningProfiles 对应填入Bundle identifier及证书关联配置文件(打包时自动匹配或手动填入证书,provisioningProfiles需配置的必填信息可自动生成);

3、提供ExportOptions.plist文件路径供Python脚本调用(详请参看Python脚本代码)。


<?xmlversion="1.0"encoding="UTF-8"?>

http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plistversion="1.0">

<dict>

<key>compileBitcode</key>//是否编译bitcode

<true/>

<key>method</key>

<string>ad-hoc</string>/

<key>provisioningProfiles</key>

<dict>

<key>文件bundle id</key>

<string>Adhoc_ID</string>

</dict>

<key>signingCertificate</key>//证书签名

<string>这里填证书签名</string>

<key>signingStyle</key>

<string>manual</string>

<key>stripSwiftSymbols</key>

<true/>

<key>teamID</key>

<string>AANCCUK4M3</string>//TeamID

<key>thinning</key>

<string><none></string>

</dict>

</plist>


4、分析 xcodebuild archive -workspace XXX.xcworkspace -scheme XXX -configuration

Release -archivePath XXX CONFIGURATION_BUILD_DIR ./dir

ODE_SIGN_IDENTITY=证书 PROVISIONING_PROFILE=描述文件UUID

总结:以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352