IPATools.py 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import zipfile, sys, re, os, traceback
  4. from biplist import *
  5. from Common import Setting, Debug, PathConvert, StringFormat
  6. Setting.SetDefaultencodingUTF8()
  7. import shutil
  8. import datetime
  9. import random
  10. TEMP_OUT_PATH = r"\ipaTemp"
  11. VALID_CMD_ARGV = {"-help", "-resVer", "-checkInfo",
  12. "-resPath", "-outPath", "-inPath"}
  13. def PrintHelp():
  14. Debug.Log('')
  15. Debug.Log('')
  16. Debug.Log('命令参数说明')
  17. Debug.Log('')
  18. Debug.Log('-help 查看帮助')
  19. Debug.Log('')
  20. Debug.Log('')
  21. Debug.Log('-checkInfo 查看ipa里的信息')
  22. Debug.Log(' 使用该参数时必须要-inPath')
  23. Debug.Log(' 且不会生成新ipa')
  24. Debug.Log('')
  25. Debug.Log('')
  26. Debug.Log('-inPath 原始ipa路径')
  27. Debug.Log('-outPath 生成的新ipa路径')
  28. Debug.Log('-resVer 生成的新ipa的资源版本号')
  29. Debug.Log('-resPath 更新的资源文件路径')
  30. Debug.Log(' 原始资源在XCode项目中里XCodeProj/Data/Raw/ios目录下')
  31. Debug.Log(' 写入到ipa里Payload/*.app/Data/Raw/ios目录下')
  32. Debug.Log('')
  33. Debug.Log('')
  34. def CheckInfo(inputPath):
  35. if not os.path.exists(inputPath):
  36. Debug.LogError(inputPath + "不存在")
  37. return
  38. with zipfile.ZipFile(inputPath, 'r') as ipaFileIn:
  39. pattern = re.compile(r'Payload/[^/]*.app/Info.plist')
  40. for path in ipaFileIn.infolist():
  41. m = pattern.match(path.filename)
  42. if m is not None:
  43. plistfp = ipaFileIn.open(path.filename)
  44. plistData = plistfp.read()
  45. plist = readPlistFromString(plistData)
  46. for k in plist:
  47. Debug.Log(str(k) + " " + str(plist[k]))
  48. def ExecTools(inputPath, outPath, resVer, resPath):
  49. if not os.path.exists(inputPath):
  50. Debug.LogError(inputPath + "不存在")
  51. return
  52. if not outPath or outPath == "":
  53. Debug.LogError(outPath + "目标目录无效")
  54. return
  55. if not resVer or resVer == "":
  56. Debug.LogError(resVer + "资源版本号无效")
  57. return
  58. if not os.path.exists(resPath):
  59. Debug.LogError(resPath + "不存在")
  60. return
  61. resVer = int(resVer)
  62. dirOutPath = os.path.dirname(outPath)
  63. tempOutPath = dirOutPath + TEMP_OUT_PATH
  64. if os.path.exists(tempOutPath):
  65. Debug.LogError(tempOutPath + "临时解压目录已存在,请先删除")
  66. return
  67. appPath = None
  68. with zipfile.ZipFile(inputPath, 'r') as ipaFileIn:
  69. pattern = re.compile(r'Payload/[^/]*.app/Info.plist')
  70. for path in ipaFileIn.infolist():
  71. m = pattern.match(path.filename)
  72. if m is not None:
  73. appPath = path.filename[0:-10]
  74. break
  75. ipaFileIn.extractall(tempOutPath)
  76. plistPath = os.path.join(tempOutPath, appPath, 'Info.plist')
  77. plist = readPlist(plistPath)
  78. Debug.Log('')
  79. Debug.LogSuccess('修改前资源版本' + str(plist['LEBIAN_VERCODE']) + " -> " + str(resVer))
  80. Debug.Log('')
  81. Debug.Log('')
  82. plist['LEBIAN_VERCODE'] = resVer
  83. writePlist(plist, plistPath)
  84. lbTimestampPath = os.path.join(tempOutPath, appPath, 'LBTimestamp')
  85. with open(lbTimestampPath, 'w') as lbTimestampfp:
  86. content = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
  87. val1 = random.randint(97,122)
  88. val2 = random.randint(97,122)
  89. content = content + chr(val1) + chr(val2)
  90. Debug.LogSuccess('乐变唯一参数' + content)
  91. Debug.Log('')
  92. Debug.Log('')
  93. lbTimestampfp.write(content)
  94. tempResOutPath = os.path.join(tempOutPath, appPath, "Data", "Raw", "ios")
  95. for dirpath, dirnames, filenames in os.walk(resPath):
  96. fpath = dirpath.replace(resPath, '')
  97. fpath = fpath and fpath + os.sep or ''
  98. for filename in filenames:
  99. shutil.copy(os.path.join(dirpath, filename), os.path.join(tempResOutPath, fpath + filename))
  100. with zipfile.ZipFile(outPath, 'w') as ipaFileOut:
  101. for dirpath, dirnames, filenames in os.walk(tempOutPath):
  102. fpath = dirpath.replace(tempOutPath, '')
  103. if fpath and fpath != '':
  104. fpath = fpath + os.sep
  105. if len(filenames) == 0:
  106. if fpath[0] == '\\' or fpath[0] == '/':
  107. fpath = fpath[1:]
  108. ipaFileOut.writestr(fpath, '')
  109. else:
  110. for filename in filenames:
  111. ipaFileOut.write(os.path.join(dirpath, filename), fpath + filename, zipfile.ZIP_DEFLATED)
  112. shutil.rmtree(tempOutPath)
  113. Debug.LogSuccess('生成ipa成功 ' + StringFormat.FormatStdinString(outPath))
  114. Debug.Log('')
  115. Debug.Log('')
  116. def Main():
  117. args = sys.argv[1:]
  118. dic = {}
  119. num = len(args)
  120. for i in range(num):
  121. arg = args[i]
  122. if arg.startswith('-'):
  123. if not arg in VALID_CMD_ARGV:
  124. Debug.LogError(StringFormat.FormatStdinString(arg) + " 不是有效的参数")
  125. PrintHelp()
  126. return
  127. if i + 1 >= num:
  128. Debug.LogSuccess(StringFormat.FormatStdinString(arg))
  129. dic[arg] = ''
  130. else:
  131. if args[i + 1].startswith('-'):
  132. Debug.LogSuccess(arg)
  133. dic[arg] = ''
  134. else:
  135. Debug.LogSuccess(StringFormat.FormatStdinString(arg) + " " + StringFormat.FormatStdinString(args[i + 1]))
  136. dic[arg] = args[i + 1]
  137. if len(dic) <= 0:
  138. PrintHelp()
  139. return
  140. if ('-help' in dic):
  141. PrintHelp()
  142. return
  143. if not ('-inPath' in dic):
  144. Debug.Log('')
  145. Debug.Log('')
  146. Debug.LogError('-inPath 不能为空')
  147. Debug.Log('')
  148. Debug.Log('')
  149. return
  150. if ('-checkInfo' in dic):
  151. CheckInfo(dic['-inPath'])
  152. return
  153. if not ('-outPath' in dic):
  154. PrintHelp()
  155. Debug.Log('')
  156. Debug.Log('')
  157. Debug.LogError('-outPath 不能为空')
  158. Debug.Log('')
  159. Debug.Log('')
  160. return
  161. if not ('-resVer' in dic):
  162. PrintHelp()
  163. Debug.Log('')
  164. Debug.Log('')
  165. Debug.LogError('-resVer 不能为空')
  166. Debug.Log('')
  167. Debug.Log('')
  168. return
  169. if not ('-resPath' in dic):
  170. PrintHelp()
  171. Debug.Log('')
  172. Debug.Log('')
  173. Debug.LogError('-resPath 不能为空')
  174. Debug.Log('')
  175. Debug.Log('')
  176. return
  177. Debug.Log('')
  178. Debug.Log('')
  179. ExecTools(dic['-inPath'], dic['-outPath'], dic['-resVer'], dic['-resPath'])
  180. if __name__ == '__main__':
  181. try:
  182. Main()
  183. except Exception as e:
  184. Debug.LogError(e)
  185. Debug.LogError(traceback.format_exc(), True)
  186. sys.exit(1)