您好,登錄后才能下訂單哦!
小編給大家分享一下Python中iOS自動(dòng)化打包的示例分析,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!
原理
就是使用xcodebuild來控制Xcode進(jìn)行一系列的操作,從而完成打包的操作.
為什么要做這個(gè)?
在我們?nèi)粘i_發(fā)的時(shí)候,特別是在內(nèi)部測(cè)試的時(shí)間,有可能需要頻繁的打包,打包的工作比較繁瑣,需要等待點(diǎn)擊下一步,選擇之類,影響了開發(fā)的節(jié)奏.(開玩笑,我能有啥節(jié)奏...), 為什么不能直接運(yùn)行,然后完成所有的操作呢?
思路:
從網(wǎng)上查找了一些關(guān)于xcodebuild來打包的資料,從而得到:
找到對(duì)應(yīng)的項(xiàng)目
clean項(xiàng)目
archive項(xiàng)目
export IPA
上傳蒲公英
發(fā)送郵件
收工
思路有了,動(dòng)手起來.
運(yùn)行環(huán)境
Python, Xcode
這些需要大家直接去搭建好環(huán)境...
準(zhǔn)備工作
下載安裝pycharm(這只是我開發(fā)Python的工具而已,大家可以根據(jù)自己喜歡的來選擇)
注冊(cè)并認(rèn)證蒲公英(不認(rèn)證的話,是不能上傳的)
郵箱開啟POP3/SMTP服務(wù)(我使用的是QQ郵箱),記錄下16位授權(quán)碼
一個(gè)ExportOptions.plist文件, 這個(gè)下面會(huì)解釋為什么需要還有怎么生成!
一份iOS項(xiàng)目代碼→_→
完整代碼
#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Time : 2018/11/14 11:04 AM # @Author : liangk # @Site : # @File : auto_archive_ios.py # @Software: PyCharm import os import requests import webbrowser import subprocess import time import smtplib from email.mime.text import MIMEText from email import encoders from email.header import Header from email.utils import parseaddr, formataddr project_name = 'TestArchive' # 項(xiàng)目名稱 archive_workspace_path = '/Users/用戶/Desktop/TestArchive' # 項(xiàng)目路徑 export_directory = 'archive' # 輸出的文件夾 ipa_download_url = 'https://www.pgyer.com/XXX' #蒲公英的APP地址 # 蒲公英賬號(hào)USER_KEY、API_KEY USER_KEY = 'XXXXXXXXXXXXXXXXXXXX' API_KEY = 'XXXXXXXXXXXXXXXXXXXX' from_address = 'XXXXXXXXXXXXXXXXXXXX@qq.com' # 發(fā)送人的地址 password = 'XXXXXXXXXXXXXXXXXXXX' # 郵箱密碼換成他提供的16位授權(quán)碼 to_address = 'XXXXXXXXXXXXXXXXXXXX@qq.com' # 收件人地址,可以是多個(gè)的 smtp_server = 'smtp.qq.com' # 因?yàn)槲沂鞘褂肣Q郵箱.. class AutoArchive(object): """自動(dòng)打包并上傳到蒲公英,發(fā)郵件通知""" 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失敗,用時(shí):%.2f秒=======" % (end - start)) else: print("=======clean成功,用時(shí):%.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) # 創(chuàng)建文件夾存放打包文件 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失敗,用時(shí):%.2f秒=======" % (end - start)) else: print("=======archive成功,用時(shí):%.2f秒=======" % (end - start)) # 導(dǎo)出IPA self.export() def export(self): print("\n\n===========開始export操作===========") print("\n\n==========請(qǐng)你耐心等待一會(huì)~===========") 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("=======導(dǎo)出IPA失敗,用時(shí):%.2f秒=======" % (end - start)) else: print("=======導(dǎo)出IPA成功,用時(shí):%.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 具體參數(shù)大家可以進(jìn)去里面查看, 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===========沒有找到對(duì)應(yīng)的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地址 # 只是單純的發(fā)了一個(gè)文本郵箱,具體的發(fā)附件和圖片大家可以自己去補(bǔ)充 msg = MIMEText('<html><body><h2>Hello</h2>' + '<p>╮(╯_╰)╭<a href="https://www.pgyer.com/XXX" rel="external nofollow" >應(yīng)用已更新,請(qǐng)下載測(cè)試</a>╮(╯_╰)╭</p>' + '<p>蒲公英的更新會(huì)有延遲,具體版本時(shí)間以郵件時(shí)間為準(zhǔn)</p>' + '</body></html>', 'html', 'utf-8') msg['From'] = self._format_address(self, 'iOS開發(fā)團(tuán)隊(duì) <%s>' % from_address) msg['Subject'] = Header('來自iOS開發(fā)團(tuán)隊(duì)的問候……', 'utf-8').encode() server = smtplib.SMTP(smtp_server, 25) # SMTP協(xié)議默認(rèn)端口是25 server.set_debuglevel(1) server.login(from_address, password) server.sendmail(from_address, [to_address], msg.as_string()) server.quit() print("===========郵件發(fā)送成功===========") if __name__ == '__main__': description = input("請(qǐng)輸入內(nèi)容:") archive = AutoArchive() archive.clean()
關(guān)于ExportOptions.plist文件
因?yàn)?Xcode 9+ 默認(rèn)不允許訪問鑰匙串的內(nèi)容,必須要設(shè)置 allowProvisioningUpdates 才會(huì)允許,Python的Xcode插件目前無(wú)法支持此項(xiàng)完成打包流程。
解決步驟如下:
1、手動(dòng)Xcode10打包,導(dǎo)出ExportOptions.plist文件;
2、編輯ExportOptions.plist文件,配置 provisioningProfiles 對(duì)應(yīng)填入Bundle identifier及證書關(guān)聯(lián)配置文件(打包時(shí)自動(dòng)匹配或手動(dòng)填入證書,provisioningProfiles需配置的必填信息可自動(dòng)生成);
3、提供ExportOptions.plist文件路徑供Python腳本調(diào)用(詳請(qǐng)參看Python腳本代碼)。
具體的內(nèi)容
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="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>
分析
xcodebuild archive -workspace XXX.xcworkspace -scheme XXX -configuration Release -archivePath XXX CONFIGURATION_BUILD_DIR ./dir ODE_SIGN_IDENTITY=證書 PROVISIONING_PROFILE=描述文件UUID
文件 | 說明 |
---|---|
-workspace XXX.xcworkspace | XXX.xcworkspace需要編譯工程的工作空間名稱,如果工程不是.xcworkspace的,可以不需要-workspace XXX.xcworkspace這段話 |
-scheme XXX | XXX是工程名稱,-scheme XXX是指定構(gòu)建工程的名稱 |
-configuration Release | 填入打包的方式是Debug或Release,就跟在Xcode中編譯前需要在Edit scheme的Build configuration中選擇打出來的包是Debug還是Release包一樣,-configuration就是配置編譯的Build configuration |
-archivePath XXX | 配置生成.xcarchive的路徑, |
ODE_SIGN_IDENTITY=證書 | 配置打包的指定證書,如果該工程的Xcode已經(jīng)配置好了證書,那么不加入這段話也可以,打包出來的證書就是Xcode中配置好的。 |
PROVISIONING_PROFILE=描述文件UUID | 配置打包的描述文件,同上,Xcode已經(jīng)配置好了就不用在填入這段話了 |
CONFIGURATION_BUILD_DIR | 配置編譯文件的輸出路徑,如果需要用到.xcarchive文件內(nèi)部的dSYM等文件,可以使用改字段指定輸出路徑。 |
問題一
配置一下compileBicode=NO
即可
以上是“Python中iOS自動(dòng)化打包的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。