auto_upload.py 10.3 KB
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import requests
import webbrowser
import subprocess
import time
import smtplib
import argparse

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

project_name = 'CNLiveScioLive' # 项目名称
upload_version = '1.0.0' # 项目版本
archive_workspace_path = '/Users/cnlive-zxw/Desktop/ScioLive' # 项目路径
export_directory = 'Products' # 输出的文件夹
ipa_pgyer_download_url = 'https://www.pgyer.com/QgmN' #蒲公英的APP地址
ipa_fir_download_url = 'http://d.6short.com/zvk2' #fir的APP地址

# 苹果账号API_KEY、API_ISSUER
APPLE_API_KEY = 'SVDD8X9884'
APPLE_API_ISSUER = '69a6de70-6693-47e3-e053-5b8c7c11a4d1'

# 蒲公英账号USER_KEY、API_KEY
PGYER_USER_KEY = '6a9a62d9659d6821721cf34169358ddc'
PGYER_API_KEY = '102d5b282e595feb713f24ecf1763313'

# fir
FIR_TOKEN = '11d64fd25fb24f3e4c5da67a39541ee8'

# 发送邮件
from_address = '153993236@qq.com' # 发送人的地址
password = 'hqotqsilkkylcbac' # 邮箱密码换成他提供的16位授权码
to_address = '153993236@qq.com' # 收件人地址,可以是多个的
smtp_server = 'smtp.qq.com' # 因为我是使用QQ邮箱

# 1.自动打包并上传到AppStore
# 2.自动打包并上传到蒲公英,发邮件通知

class AutoUpload(object):
    def __init__(self, number):
        self.number = number

    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()

        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/%s.xcarchive' % (
        archive_workspace_path, project_name, project_name, archive_workspace_path, export_directory, project_name)
        archive_command_run = subprocess.Popen(archive_command, shell=True)
        archive_command_run.wait()
        end = time.time()

        archive_result_code = archive_command_run.returncode
        if archive_result_code != 0:
            print("=======Archive失败,用时:%.2f秒=======" % (end - start))
        else:
            print("=======Archive成功,用时:%.2f秒=======" % (end - start))
            self.export()

    def export(self):
        print("\n\n===========开始Export操作===========")
        print("\n\n==========请你耐心等待一会~===========")
        start = time.time()

        plist_name = 'exportAppstore'
        if self.number == 1:
            plist_name = 'exportAppstore'

        elif self.number == 2:
            plist_name = 'exportTest'
            
        export_command = 'xcodebuild -exportArchive -archivePath %s/%s/%s.xcarchive -exportPath %s/%s -exportOptionsPlist %s/%s.plist' % (
        archive_workspace_path, export_directory, project_name, archive_workspace_path, export_directory, archive_workspace_path, plist_name)
        export_command_run = subprocess.Popen(export_command, shell=True)
        export_command_run.wait()
        end = time.time()

        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/%s.xcarchive' % (archive_workspace_path, export_directory, project_name)])
            self.upload('%s/%s/%s.ipa' % (archive_workspace_path, export_directory, project_name))

    def upload(self, ipa_path):
        if ipa_path:
            if self.number == 1:
                print("\n\n===========开始上传AppStore操作===========")
                start = time.time()
                export_command = 'xcrun altool --upload-app -f %s -t ios --apiKey %s --apiIssuer %s --verbose' % (
                ipa_path, APPLE_API_KEY, APPLE_API_ISSUER)
                export_command_run = subprocess.Popen(export_command, shell=True)
                export_command_run.wait()
                end = time.time()

                export_result_code = export_command_run.returncode
                if export_result_code != 0:
                    print("=======上传AppStore失败,用时:%.2f秒=======" % (end - start))
                else:
                    print("=======上传AppStore成功,用时:%.2f秒=======" % (end - start))
            elif self.number == 2:
                print("\n\n===========开始上传蒲公英操作===========")
                start = time.time()
                # https://www.pgyer.com/doc/api 查看具体参数
                url = 'http://www.pgyer.com/apiv1/app/upload'
                data = {
                'uKey': PGYER_USER_KEY,
                '_api_key': PGYER_API_KEY,
                'installType': '1',
                'updateDescription': upload_version
                }
                files = {'file': open(ipa_path, 'rb')}
                r = requests.post(url, data=data, files=files)
                end = time.time()
                if r.status_code == 200:
                    print("=======上传蒲公英成功,用时:%.2f秒=======" % (end - start))
                    # 是否需要打开浏览器
                    self.open_browser(self, ipa_pgyer_download_url)
                    self.send_email(ipa_pgyer_download_url)
                else:
                    print("=======上传蒲公英失败,用时:%.2f秒=======" % (end - start))
            elif self.number == 3:
                print("\n\n===========开始上传Fir操作===========")
                loginCmd = 'fir login -T %s' % (FIR_TOKEN)
                process = subprocess.Popen(loginCmd, shell=True)
                process.wait()
                loginReturnCode = process.returncode
                if loginReturnCode != 0:
                    print("=======上传登录Fir失败")
                else:
                    print("=======上传登录Fir成功")
                    start = time.time()
                    publishCmd = 'fir publish %s -c %s'%(ipa_path, upload_version)
                    process = subprocess.Popen(publishCmd, shell=True)
                    process.wait()
                    publishReturnCode = process.returncode
                    end = time.time()
                    if publishReturnCode != 0:
                        print("=======上传Fir失败,用时:%.2f秒=======" % (end - start))
                    else:
                        print("=======上传Fir成功,用时:%.2f秒=======" % (end - start))
                        self.open_browser(self, ipa_fir_download_url)
                        self.send_email(ipa_fir_download_url)
        
        else:
            print("\n\n===========没有找到对应的ipa===========")

        return

    @staticmethod
    def open_browser(self, url):
        webbrowser.open(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, url):
        msg = MIMEText('<html><body><h1>Hello</h1>' +
        '<p>╮(╯_╰)╭<a href=\"'+url+'\" rel="external nofollow" >应用已更新,请下载测试</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], msg.as_string())
        server.quit()
        print("\n\n===========邮件发送成功===========")
        
# 获取命令行的参数
def command_line():
    # 构造缺省参数:
    defaults = {
        'store': 'app-store'
    }

    # 构造命令行参数:
    parser = argparse.ArgumentParser()
    parser.add_argument('-s', '--store')
    namespace = parser.parse_args()
    command_line_args = { k: v for k, v in vars(namespace).items() if v }

    # 组合成ChainMap:
    combined = ChainMap(command_line_args, os.environ, defaults)

    # 获取参数
    if combined['store'] == 'app-store':
        return 1
    elif combined['store'] == 'pgyer':
        return 2
    elif combined['store'] == 'fir':
        return 3
    else:
        return 0

# 程序入口
if __name__ == '__main__':

    # 1、先用命令行方式,获取number
    # python3 auto_upload.py 或者 python3 auto_upload.py -s app-store 或者 python3 auto_upload.py --store app-store
    # python3 auto_upload.py -s pgyer 或者 python3 auto_upload.py --store pgyer
    # python3 auto_upload.py -s fir 或者 python3 auto_upload.py --store fir

    number = command_line()
    if (number != 1 and number != 2 and number != 3):
    
        # 2、再用手动输入方式,获取number
        number = int(input("\n\nPlace enter the number you want to upload ? [ 1:app-store 2:蒲公英 3:fir ] "))
        while (number != 1 and number != 2 and number != 3):
            print("Error! Should enter 1 or 2 or 3")
            number = int(input("\n\nPlace enter the number you want to upload ? [ 1:app-store 2:蒲公英 3:fir ] "))

    # 3、根据number创建上传对象
    upload = AutoUpload(number)
    upload.clean()