我们的项目每次更新之后,需要打100多个企业包,这个企业包的数量是一直都在增加的,之前都是手动打,这么多的包,大概得打一天的时间。。。。
现在打100多个包只需要16分钟左右,我们的企业包的不同就在于每个企业包用户名和用户手机号不同,其他配置都是一样的,所以,思路是:在工程中创建一个plist,把所有的企业包的用户名和手机号都写在里面,在需要的时候,直接去里面取就行。打包的时候只生成一个.xcarchive包,然后修改项目的plist文件,重新签名然后打包输出。
打包的思想跟使用命令行打包的思想是一样的,可查看文章 XZ_iOS之使用终端命令行打包
打包功能的实现
下面是实现打包功能的主要代码:
# 编译命令 archivePath = outputPath + "/" + scheme + ".xcarchive" # 编译后app中的info.plist文件路径 infoPath = archivePath + "/Products/Applications/" + scheme + ".app/info.plist" # 执行编译命令 buildCommand = "xcodebuild archive -project " + projectpath + " -scheme " + scheme + " -archivePath " + archivePath output = os.system(buildCommand) # 修改plist文件 for n in idList: pl = readPlist(infoPath) # 修改对应的业务数据 pl["LocalUserID"] = n writePlist(pl, infoPath) codeSignPlistPath = outputPath + "/DistributionSummary.plist" appPath = archivePath + "/Products/Applications/" + scheme + ".app" codesignCommand = "codesign -f -s " + teamName + " --entitlements " + codeSignPlistPath + " " + appPath print("执行签名命令: " + codesignCommand) output = os.system(codesignCommand) if output == 0: print("====================项目 <<" + n + ">> 重新签名成功,正在打包中====================") # 导出ipa包需要的plist文件 exportPlistPath = outputPath + "/" + "ExportOptions.plist" exportPath = outputPath + "/" + n exportCommand = "xcodebuild -exportArchive -archivePath " + archivePath + " -exportPath " + exportPath + " -exportOptionsPlist " + exportPlistPath print("执行打包命令: " + exportCommand) result = os.system(exportCommand) if result == 0: print("====================项目 <<" + n + ">> 导出成功!!!====================") #将所有的ipa包重命名并移动到'所有的ipa包'文件夹 else: print("====================项目 <<" + n + ">> 重新签名失败,请检查DistributionSummary.plist文件====================")
ipa包的输出文件夹
使用者可以选择输出的文件夹,如果没有选择,就自动创建一个文件夹。如果用户没有自己选择文件夹,就创建打包输出的默认文件夹:
# 判断文件夹是否存在,如果存在就删除再创建 if os.path.exists(outputPath + "/所有的ipa包"): shutil.rmtree(outputPath + "/所有的ipa包") #删除文件夹和文件夹里面的内容 # 将所有的ipa包移动到统一的文件夹 os.makedirs(outputPath + "/所有的ipa包")
界面化打包界面的实现
用户可以选择工程路径、推荐人表格、推荐人包输出路径、需要替换的plist路径
# 推荐人excel表路径 label1 = tk.Label(root,text="推荐人excel表路径:").grid(row = 0, column = 0) tk.Entry(root, textvariable = excelFile).grid(row = 0, column = 1) button1 = tk.Button(root, text = "路径选择", command = selectExcelFile).grid(row = 0, column = 2, padx = 10, pady = 5) # 工程路径 tk.Label(root,text = "工程路径:").grid(row = 1, column = 0) tk.Entry(root, textvariable = projectFile).grid(row = 1, column = 1) tk.Button(root, text = "路径选择", command = selectProjectFile).grid(row = 1, column = 2, padx = 10, pady = 5) # ipa包输出路径 tk.Label(root,text = "ipa包输出路径:").grid(row = 2, column = 0) tk.Entry(root, textvariable = outputPath).grid(row = 2, column = 1) tk.Button(root, text = "路径选择", command = selectPath).grid(row = 2, column = 2, padx = 10, pady = 5) # info.plist路径 tk.Label(root, text = "registerPhone.plist路径:").grid(row = 3, column = 0) tk.Entry(root, textvariable = infoPlistPath).grid(row = 3, column = 1) tk.Button(root, text = "路径选择", command = selectInfoPlistPath).grid(row = 3, column = 2, padx = 10, pady = 5) # 修改推荐人列表的plist, 获取推荐人userid并打包 tk.Button(root, text = "开始打包", command = lambda:judgePath(excelFile.get(), projectFile.get(), outputPath.get(), infoPlistPath.get())).grid(row = 4, column = 0, pady = 10)
实现的界面效果如下:
用户在选择路径的时候,只是当前类型的文件是可选状态
比如,如果用户需要选择Excel,则其他的文件夹或者其他类型的文件是不可选的状态:
# 选择推荐人包的路径 def selectExcelFile(): filename = askopenfilename(filetypes=[('Excel', '*.xls *.xlsx'), ('All Files', '*')]) excelFile.set(filename) # 工程路径 def selectProjectFile(): filename = askopenfilename(filetypes = [('PROJECT', '*.xcodeproj .xcworkspace'), ('All Files', '*')]) projectFile.set(filename) # 选择推荐人包的路径 ==> 可以不选,如果不选择路径,默认在桌面生成一个"生成的ipa包"存放ipa包 def selectPath(): path_ = askdirectory() if path_ != '': outputPath.set(path_) else: outputPath.set("") # registerPhone.plist路径 def selectInfoPlistPath(): plistPath = askopenfilename(filetypes = [('INFOPLIST', '*.plist'), ('All Files', '*')]) infoPlistPath.set(plistPath)
自动读取Excel文件中的数据到plist文件中
用户选择路径Excel文件之后,将Excel文件中的数据自动读取到创建的plist文件中
# 获取推荐人 userid: excel路径,工程路径,输出路径 def packPkg(excelFile, projectFile, outputPath, infoPlistPath): print("推荐人excel地址是", excelFile) print("ipa包地址是", projectFile) print("IPA的输出地址是", outputPath) print("infoPlistPath的输出地址是", infoPlistPath) # 获取输出路径 outputPath = createPlist(outputPath) # 读取表格 excel_data = xlrd.open_workbook(excelFile) # 取出Excel的第一个sheet数据 table_one = excel_data.sheet_by_index(0) # 根据sheet索引获取sheet的内容 # 表格的总行数 lines = table_one.nrows cols = table_one.ncols print ("表格的总行数:",lines) print ("表格的总列数:",cols) last_output_dir = '' idList = [] infoPlist = [] for i in range(0,lines): # 获取excel表格一行的数据 row_values = table_one.row_values(i) tuijianren_id = str(int(row_values[0])) tuijianren_phone = str(int(row_values[1])) dict = {"fmuserid": tuijianren_id, "fmmobile": tuijianren_phone} idList.append(tuijianren_id) # 将Excel表格中的数据转成数组 infoPlist.append(dict) # 删除旧的plist数据,导入新的 plist = readPlist(infoPlistPath) print ("原plist是:", plist) writePlist(infoPlist, infoPlistPath) print ("===========创建的列表是:",idList) print ("读取的手机号列表是:", infoPlist) plist = readPlist(infoPlistPath) print ("修改之后的列表是:", plist) if len(idList) == lines: # 调用打包程序 beginToPackage(projectFile, outputPath, idList) else: print ("读取Excel失败")
修改ipa包的名字
将ipa包的名字修改成和上层文件夹的名字相同
def changeFileName(exportPath, outputPath): if not os.path.isdir(exportPath): return False if os.path.isdir(exportPath): fileName = os.path.basename(exportPath) pathOld = exportPath + "/rzjrapp.ipa" print ("获取文件名:",fileName) pathNew = exportPath + "/app" + fileName + ".ipa" os.rename(pathOld , pathNew) #将要移动的文件夹 pathMoved = outputPath + "/所有的ipa包" shutil.move(pathNew, pathMoved)