escalator_ios 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +35 -0
- data/bin/escalator +10 -0
- data/escalator_ios.gemspec +27 -0
- data/lib/escalator/archive.rb +122 -0
- data/lib/escalator/combine.rb +116 -0
- data/lib/escalator/command/archive.rb +84 -0
- data/lib/escalator/command/combine.rb +116 -0
- data/lib/escalator/command/confuse.rb +86 -0
- data/lib/escalator/command/resign.rb +138 -0
- data/lib/escalator/command/setup.rb +91 -0
- data/lib/escalator/command/upload.rb +95 -0
- data/lib/escalator/command.rb +46 -0
- data/lib/escalator/confuse.rb +101 -0
- data/lib/escalator/group+.rb +13 -0
- data/lib/escalator/resign.rb +271 -0
- data/lib/escalator/setup.rb +79 -0
- data/lib/escalator/throw.rb +23 -0
- data/lib/escalator/upload.rb +57 -0
- data/lib/escalator.rb +25 -0
- data/resources/ExportOptions.plist +20 -0
- data/resources/IconInfo.plist +31 -0
- data/resources/zsh_plugin/escalator/_escalator +127 -0
- metadata +178 -0
@@ -0,0 +1,271 @@
|
|
1
|
+
module Escalator
|
2
|
+
|
3
|
+
class Resign
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def run command
|
8
|
+
@command = command
|
9
|
+
prepareContext
|
10
|
+
applyCertificates
|
11
|
+
command.ipaPaths.map { |path|
|
12
|
+
resignIPA handleIPA path
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
attr_accessor :command
|
19
|
+
|
20
|
+
attr_accessor :tmpdir
|
21
|
+
|
22
|
+
attr_accessor :keyInfo_path
|
23
|
+
|
24
|
+
attr_accessor :bundle_version
|
25
|
+
|
26
|
+
attr_accessor :assets_path
|
27
|
+
|
28
|
+
attr_accessor :iconInfo_path
|
29
|
+
|
30
|
+
attr_accessor :cerIdentifier
|
31
|
+
|
32
|
+
def prepareContext
|
33
|
+
Throw.note "Prepare resign context ..."
|
34
|
+
@tmpdir = ENV["TMPDIR"] + "escalator/resign"
|
35
|
+
if File.exist? tmpdir
|
36
|
+
FileUtils.rm_rf Dir["#{tmpdir}/*"]
|
37
|
+
else
|
38
|
+
FileUtils.mkdir_p tmpdir
|
39
|
+
end
|
40
|
+
@keyInfo_path = tmpdir + "/keyInfo.json"
|
41
|
+
keyInfo = Hash.new
|
42
|
+
keyInfo[:in_house] = false
|
43
|
+
keyInfo[:key_id] = command.key_id
|
44
|
+
keyInfo[:issuer_id] = command.issuer_id
|
45
|
+
keyInfo[:key_filepath] = command.keyfile_path
|
46
|
+
keyInfo[:key] = File.read command.keyfile_path
|
47
|
+
file = File.new keyInfo_path, "w"
|
48
|
+
file.write JSON.generate keyInfo
|
49
|
+
file.close
|
50
|
+
@bundle_version = command.bundle_version.to_i
|
51
|
+
@assets_path = tmpdir + "/assets"
|
52
|
+
FileUtils.mkdir_p assets_path
|
53
|
+
info_path = File.expand_path "../../../resources/IconInfo.plist", __FILE__
|
54
|
+
FileUtils.cp info_path, tmpdir
|
55
|
+
@iconInfo_path = tmpdir + "/IconInfo.plist"
|
56
|
+
end
|
57
|
+
|
58
|
+
def applyCertificates
|
59
|
+
Throw.note "begin apply certificates ..."
|
60
|
+
cmd = "fastlane cert create --api_key_path #{keyInfo_path}"
|
61
|
+
cmd += " --generate_apple_certs true -p #{command.user_password} -o #{tmpdir}"
|
62
|
+
system cmd
|
63
|
+
if !$?.success?
|
64
|
+
Throw.error "Apply .cer file faild!"
|
65
|
+
end
|
66
|
+
cer = File.read Dir.glob("#{tmpdir}/*.cer").first
|
67
|
+
@cerIdentifier = OpenSSL::Digest.hexdigest("SHA1", cer).upcase
|
68
|
+
cmd = "fastlane sigh renew --api_key_path #{keyInfo_path} -a #{command.bundle_identifier}"
|
69
|
+
cmd += " -q embedded.mobileprovision -o #{tmpdir}"
|
70
|
+
system cmd
|
71
|
+
if !$?.success?
|
72
|
+
Throw.error "Apply embedded.mobileprovision file faild!"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def handleIPA ipaPath
|
77
|
+
basePath = File.dirname(ipaPath)
|
78
|
+
coverInfoPath = basePath + "/CoverInfo.plist"
|
79
|
+
coverData = Hash.new
|
80
|
+
coverData["CFBundleVersion"] = ""
|
81
|
+
coverData["CFBundleName"] = ""
|
82
|
+
coverData["CFBundleExecutable"] = ""
|
83
|
+
coverData["CFBundleDisplayName"] = ""
|
84
|
+
if File.exist? coverInfoPath
|
85
|
+
coverPlist = CFPropertyList::List.new :file => coverInfoPath
|
86
|
+
CFPropertyList.native_types(coverPlist.value).each { |key, value|
|
87
|
+
coverData[key] = value
|
88
|
+
}
|
89
|
+
end
|
90
|
+
bundleVersion = coverData["CFBundleVersion"]
|
91
|
+
if bundleVersion.empty?
|
92
|
+
bundleVersion = bundle_version.to_s
|
93
|
+
@bundle_version += 1
|
94
|
+
end
|
95
|
+
displayName = coverData["CFBundleDisplayName"]
|
96
|
+
if displayName.empty?
|
97
|
+
displayName = command.display_name
|
98
|
+
end
|
99
|
+
bundleName = coverData["CFBundleName"]
|
100
|
+
if bundleName.empty?
|
101
|
+
bundleName = command.bundle_name
|
102
|
+
end
|
103
|
+
executableName = coverData["CFBundleExecutable"]
|
104
|
+
if executableName.empty?
|
105
|
+
executableName = command.executable_name
|
106
|
+
end
|
107
|
+
if (command.iconAssets_path.empty? &&
|
108
|
+
bundleName.empty? &&
|
109
|
+
executableName.empty?)
|
110
|
+
return OpenStruct.new(:path => ipaPath, :displayName => displayName)
|
111
|
+
end
|
112
|
+
Throw.note "begin handle #{File.basename ipaPath} ..."
|
113
|
+
content_path = tmpdir + "/content"
|
114
|
+
FileUtils.mkdir_p content_path
|
115
|
+
system "unzip -o -q #{ipaPath} -d #{content_path}"
|
116
|
+
if !$?.success?
|
117
|
+
Throw.error "Unzip ipa faild!"
|
118
|
+
end
|
119
|
+
appPath = Dir.glob("#{content_path}/**/*.app").first
|
120
|
+
if !command.iconAssets_path.empty?
|
121
|
+
handleAssets appPath, basePath
|
122
|
+
end
|
123
|
+
pluginsProvisions = []
|
124
|
+
pluginsPath = "#{appPath}/PlugIns"
|
125
|
+
if File.exist? pluginsPath
|
126
|
+
pluginsProvisions = handlePlugins pluginsPath
|
127
|
+
end
|
128
|
+
if !(bundleName.empty? && executableName.empty?)
|
129
|
+
handleBundle appPath, bundleName, executableName
|
130
|
+
end
|
131
|
+
FileUtils.rm_rf ipaPath
|
132
|
+
newIpaPath = ipaPath
|
133
|
+
if !bundleName.empty?
|
134
|
+
newIpaPath = File.expand_path "../#{bundleName}.ipa", ipaPath
|
135
|
+
end
|
136
|
+
system "cd #{content_path} && zip -q -r -D #{newIpaPath} ./*"
|
137
|
+
if !$?.success?
|
138
|
+
Throw.error "Zip payload faild!"
|
139
|
+
end
|
140
|
+
FileUtils.rm_rf content_path
|
141
|
+
OpenStruct.new(
|
142
|
+
:path => newIpaPath,
|
143
|
+
:bundleVersion => bundleVersion,
|
144
|
+
:displayName => displayName,
|
145
|
+
:pluginsProvisions => pluginsProvisions
|
146
|
+
)
|
147
|
+
end
|
148
|
+
|
149
|
+
def handleAssets appPath, assetsPath
|
150
|
+
Throw.note "begin handle assets ..."
|
151
|
+
cmd = "actool --compile #{assets_path} --minimum-deployment-target 11.0 --platform iphoneos"
|
152
|
+
cmd += " --app-icon AppIcon --output-partial-info-plist #{iconInfo_path}"
|
153
|
+
cmd += " --compress-pngs #{command.iconAssets_path}"
|
154
|
+
Dir.glob("#{assetsPath}/*.xcassets") { |file|
|
155
|
+
cmd += " #{file}"
|
156
|
+
icon_path = "#{file}/AppIcon.appiconset"
|
157
|
+
if File.exist? icon_path
|
158
|
+
FileUtils.rm_rf icon_path
|
159
|
+
end
|
160
|
+
}
|
161
|
+
system cmd
|
162
|
+
if !$?.success?
|
163
|
+
Throw.error "Generate new Assets.car faild!"
|
164
|
+
end
|
165
|
+
FileUtils.mv Dir["#{assets_path}/*"], appPath, force: true
|
166
|
+
end
|
167
|
+
|
168
|
+
def handlePlugins path
|
169
|
+
appleIdField = command.apple_id.empty? ? "" : "-u #{command.apple_id}"
|
170
|
+
parts = (command.bundle_identifier.split ".").sort_by { |p| p.length }
|
171
|
+
groupName = parts.last
|
172
|
+
groupIdentifier = "group.#{command.bundle_identifier}"
|
173
|
+
system "fastlane produce group #{appleIdField} -g #{groupIdentifier} -n '#{groupName} App Group'"
|
174
|
+
if !$?.success?
|
175
|
+
Throw.error "Create #{groupName} app group faild!"
|
176
|
+
end
|
177
|
+
infos = Dir.glob("#{path}/*.appex/Info.plist").map { |infoPath|
|
178
|
+
plist = CFPropertyList::List.new :file => infoPath
|
179
|
+
CFPropertyList.native_types plist.value
|
180
|
+
}
|
181
|
+
enableNetworkExtension = false
|
182
|
+
infos.each { |info|
|
183
|
+
enableNetworkExtension |= info["NSExtension"]["NSExtensionPointIdentifier"].include? "com.apple.networkextension"
|
184
|
+
}
|
185
|
+
networkExtensionField = enableNetworkExtension ? "--network-extension" : ""
|
186
|
+
system "fastlane produce enable_services #{appleIdField} --app-group #{networkExtensionField} -j ios -a #{command.bundle_identifier}"
|
187
|
+
if !$?.success?
|
188
|
+
Throw.error "#{command.bundle_identifier} enable services faild!"
|
189
|
+
end
|
190
|
+
system "fastlane produce associate_group #{appleIdField} #{groupIdentifier} -a #{command.bundle_identifier}"
|
191
|
+
if !$?.success?
|
192
|
+
Throw.error "#{command.bundle_identifier} associate group faild!"
|
193
|
+
end
|
194
|
+
system "fastlane sigh renew --api_key_path #{keyInfo_path} -f -a #{command.bundle_identifier} -q embedded.mobileprovision -o #{tmpdir}"
|
195
|
+
if !$?.success?
|
196
|
+
Throw.error "Apply embedded.mobileprovision file faild!"
|
197
|
+
end
|
198
|
+
infos.map { |info|
|
199
|
+
originalIdentifier = info["CFBundleIdentifier"]
|
200
|
+
name = info["CFBundleExecutable"]
|
201
|
+
provisionName = "#{name}.mobileprovision"
|
202
|
+
identifier = "#{command.bundle_identifier}.#{name}"
|
203
|
+
system "fastlane produce create #{appleIdField} -i -j ios -a #{identifier} -q #{name}"
|
204
|
+
if !$?.success?
|
205
|
+
Throw.error "Create #{identifier} faild!"
|
206
|
+
end
|
207
|
+
system "fastlane produce enable_services #{appleIdField} --app-group #{networkExtensionField} -j ios -a #{identifier}"
|
208
|
+
if !$?.success?
|
209
|
+
Throw.error "#{identifier} enable services faild!"
|
210
|
+
end
|
211
|
+
system "fastlane produce associate_group #{appleIdField} #{groupIdentifier} -a #{identifier}"
|
212
|
+
if !$?.success?
|
213
|
+
Throw.error "#{identifier} associate group faild!"
|
214
|
+
end
|
215
|
+
system "fastlane sigh renew --api_key_path #{keyInfo_path} -a #{identifier} -q #{provisionName} -o #{tmpdir}"
|
216
|
+
if !$?.success?
|
217
|
+
Throw.error "Apply #{provisionName} file faild!"
|
218
|
+
end
|
219
|
+
"#{originalIdentifier}=#{tmpdir}/#{provisionName}"
|
220
|
+
}
|
221
|
+
end
|
222
|
+
|
223
|
+
def handleBundle appPath, newBundleName, newExecutableName
|
224
|
+
Throw.note "begin handle bundle ..."
|
225
|
+
plistPath = appPath + "/Info.plist"
|
226
|
+
plist = CFPropertyList::List.new :file => plistPath
|
227
|
+
data = CFPropertyList.native_types plist.value
|
228
|
+
if !newExecutableName.empty?
|
229
|
+
executableName = data["CFBundleExecutable"]
|
230
|
+
FileUtils.mv "#{appPath}/#{executableName}", "#{appPath}/#{newExecutableName}", force: true
|
231
|
+
data["CFBundleExecutable"] = newExecutableName
|
232
|
+
end
|
233
|
+
if !newBundleName.empty?
|
234
|
+
data["CFBundleName"] = newBundleName
|
235
|
+
end
|
236
|
+
plist.value = CFPropertyList::guess data
|
237
|
+
plist.save plistPath
|
238
|
+
if !newBundleName.empty?
|
239
|
+
newAppPath = File.dirname(appPath) + "/#{newBundleName}.app"
|
240
|
+
FileUtils.mv appPath, newAppPath, force: true
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def resignIPA ipaInfo
|
245
|
+
path = File.dirname ipaInfo.path
|
246
|
+
ipaName = File.basename ipaInfo.path
|
247
|
+
Throw.note "begin resign #{ipaName} ..."
|
248
|
+
cmd = "fastlane sigh resign --short_version #{command.short_version}"
|
249
|
+
cmd += " --bundle_version #{ipaInfo.bundleVersion}"
|
250
|
+
if !ipaInfo.displayName.empty?
|
251
|
+
cmd += " -d #{ipaInfo.displayName}"
|
252
|
+
end
|
253
|
+
cmd += " --use_app_entitlements -p #{tmpdir}/embedded.mobileprovision"
|
254
|
+
ipaInfo.pluginsProvisions.each { |provision|
|
255
|
+
cmd += " -p #{provision}"
|
256
|
+
}
|
257
|
+
cmd += " -i #{cerIdentifier} #{ipaInfo.path}"
|
258
|
+
system cmd
|
259
|
+
if !$?.success?
|
260
|
+
Throw.error "Resign ipa faild!"
|
261
|
+
end
|
262
|
+
newPath = path + "_build_#{ipaInfo.bundleVersion}"
|
263
|
+
FileUtils.mv path, newPath, force: true
|
264
|
+
"#{newPath}/#{ipaName}"
|
265
|
+
end
|
266
|
+
|
267
|
+
end
|
268
|
+
|
269
|
+
end
|
270
|
+
|
271
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module Escalator
|
2
|
+
|
3
|
+
class Setup
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def run command
|
8
|
+
@command = command
|
9
|
+
if command.set_zshcompletion
|
10
|
+
pluginPath = File.expand_path "../../../resources/zsh_plugin/escalator", __FILE__
|
11
|
+
FileUtils.cp_r pluginPath, command.custom_plugins
|
12
|
+
return
|
13
|
+
end
|
14
|
+
prepareContext
|
15
|
+
exportPlist
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
attr_accessor :command
|
21
|
+
|
22
|
+
attr_accessor :config_data
|
23
|
+
|
24
|
+
attr_accessor :cover_data
|
25
|
+
|
26
|
+
def prepareContext
|
27
|
+
@config_data = Hash.new
|
28
|
+
@cover_data = Hash.new
|
29
|
+
if command.commands.include? "confuse"
|
30
|
+
config_data["keywords"] = ["混淆词1", "混淆词2"]
|
31
|
+
end
|
32
|
+
if command.commands.include? "archive"
|
33
|
+
config_data["method"] = "app-store 或者 ad-hoc"
|
34
|
+
end
|
35
|
+
if command.commands.include? "resign"
|
36
|
+
config_data["key_id"] = "AppStore Connect 拷贝"
|
37
|
+
config_data["issuer_id"] = "AppStore Connect 拷贝"
|
38
|
+
config_data["keyfile_path"] = "AppStore Connect 下载的 .p8 文件的绝对路径"
|
39
|
+
config_data["user_password"] = "当前电脑用户密码"
|
40
|
+
config_data["CFBundleIdentifier"] = "新的唯一标识符"
|
41
|
+
config_data["CFBundleShortVersionString"] = "版本号"
|
42
|
+
config_data["CFBundleVersion"] = "初始 Build 号"
|
43
|
+
config_data["apple_id"] = "可缺省: 对应的苹果开发者账户, 如果含有 APP GROUP 推荐添加此字段"
|
44
|
+
config_data["CFBundleName"] = "可缺省: 新包名"
|
45
|
+
config_data["CFBundleExecutable"] = "可缺省: 新的二进制名"
|
46
|
+
config_data["CFBundleDisplayName"] = "可缺省: 新的 APP 名称"
|
47
|
+
config_data["iconAssets_path"] = "可缺省: 包含新 AppIcon 的 .xcassets 文件的绝对路径"
|
48
|
+
|
49
|
+
cover_data["CFBundleVersion"] = "可缺省: 覆盖全局配置中的 Build 号规则"
|
50
|
+
cover_data["CFBundleName"] = "可缺省: 覆盖全局配置中的 新包名"
|
51
|
+
cover_data["CFBundleExecutable"] = "可缺省: 覆盖全局配置中的 新的二进制名"
|
52
|
+
cover_data["CFBundleDisplayName"] = "可缺省: 覆盖全局配置中的 新的 APP 名称"
|
53
|
+
end
|
54
|
+
if command.commands.include? "upload"
|
55
|
+
config_data["key_id"] = "AppStore Connect 拷贝"
|
56
|
+
config_data["issuer_id"] = "AppStore Connect 拷贝"
|
57
|
+
config_data["keyfile_path"] = "AppStore Connect 下载的 .p8 文件的绝对路径"
|
58
|
+
config_data["CFBundleIdentifier"] = "新的唯一标识符"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def exportPlist
|
63
|
+
configPlist = CFPropertyList::List.new
|
64
|
+
configPlist.format = CFPropertyList::List::FORMAT_XML
|
65
|
+
configPlist.value = CFPropertyList.guess config_data
|
66
|
+
configPlist.save command.output_path + "/ConfigInfo.plist"
|
67
|
+
if command.commands.include? "resign"
|
68
|
+
coverPlist = CFPropertyList::List.new
|
69
|
+
coverPlist.format = CFPropertyList::List::FORMAT_XML
|
70
|
+
coverPlist.value = CFPropertyList.guess cover_data
|
71
|
+
coverPlist.save command.output_path + "/CoverInfo.plist"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Escalator
|
2
|
+
|
3
|
+
class Upload
|
4
|
+
|
5
|
+
class << self
|
6
|
+
|
7
|
+
def run command
|
8
|
+
@command = command
|
9
|
+
prepareContext
|
10
|
+
command.ipaPaths.each { |path|
|
11
|
+
uploadIPA path
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :command
|
18
|
+
|
19
|
+
attr_accessor :tmpdir
|
20
|
+
|
21
|
+
attr_accessor :keyInfo_path
|
22
|
+
|
23
|
+
def prepareContext
|
24
|
+
Throw.note "Prepare upload context ..."
|
25
|
+
@tmpdir = ENV["TMPDIR"] + "escalator/upload"
|
26
|
+
if File.exist? tmpdir
|
27
|
+
FileUtils.rm_rf Dir["#{tmpdir}/*"]
|
28
|
+
else
|
29
|
+
FileUtils.mkdir_p tmpdir
|
30
|
+
end
|
31
|
+
@keyInfo_path = tmpdir + "/keyInfo.json"
|
32
|
+
keyInfo = Hash.new
|
33
|
+
keyInfo[:in_house] = false
|
34
|
+
keyInfo[:key_id] = command.key_id
|
35
|
+
keyInfo[:issuer_id] = command.issuer_id
|
36
|
+
keyInfo[:key_filepath] = command.keyfile_path
|
37
|
+
keyInfo[:key] = File.read command.keyfile_path
|
38
|
+
file = File.new keyInfo_path, "w"
|
39
|
+
file.write JSON.generate keyInfo
|
40
|
+
file.close
|
41
|
+
end
|
42
|
+
|
43
|
+
def uploadIPA path
|
44
|
+
Throw.note "Begin upload #{path} ..."
|
45
|
+
cmd = "fastlane pilot upload --api_key_path #{keyInfo_path}"
|
46
|
+
cmd += " -i #{path} -a #{command.bundle_identifier} -z true"
|
47
|
+
system(cmd)
|
48
|
+
if !$?.success?
|
49
|
+
Throw.error "Upload ipa faild!"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/lib/escalator.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Escalator
|
2
|
+
|
3
|
+
VERSION = "1.2.0".freeze
|
4
|
+
|
5
|
+
require "json"
|
6
|
+
require "openssl"
|
7
|
+
require "ostruct"
|
8
|
+
require "fileutils"
|
9
|
+
require "cfpropertylist"
|
10
|
+
require "xcodeproj"
|
11
|
+
require "fastlane"
|
12
|
+
require "colored2"
|
13
|
+
require "claide"
|
14
|
+
|
15
|
+
require "escalator/group+"
|
16
|
+
require "escalator/throw"
|
17
|
+
require "escalator/command"
|
18
|
+
require "escalator/confuse"
|
19
|
+
require "escalator/archive"
|
20
|
+
require "escalator/resign"
|
21
|
+
require "escalator/upload"
|
22
|
+
require "escalator/combine"
|
23
|
+
require "escalator/setup"
|
24
|
+
|
25
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>destination</key>
|
6
|
+
<string>export</string>
|
7
|
+
<key>manageAppVersionAndBuildNumber</key>
|
8
|
+
<false/>
|
9
|
+
<key>method</key>
|
10
|
+
<string>app-store</string>
|
11
|
+
<key>signingStyle</key>
|
12
|
+
<string>automatic</string>
|
13
|
+
<key>stripSwiftSymbols</key>
|
14
|
+
<true/>
|
15
|
+
<key>uploadBitcode</key>
|
16
|
+
<false/>
|
17
|
+
<key>uploadSymbols</key>
|
18
|
+
<false/>
|
19
|
+
</dict>
|
20
|
+
</plist>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>CFBundleIcons</key>
|
6
|
+
<dict>
|
7
|
+
<key>CFBundlePrimaryIcon</key>
|
8
|
+
<dict>
|
9
|
+
<key>CFBundleIconFiles</key>
|
10
|
+
<array>
|
11
|
+
<string>AppIcon60x60</string>
|
12
|
+
</array>
|
13
|
+
<key>CFBundleIconName</key>
|
14
|
+
<string>AppIcon</string>
|
15
|
+
</dict>
|
16
|
+
</dict>
|
17
|
+
<key>CFBundleIcons~ipad</key>
|
18
|
+
<dict>
|
19
|
+
<key>CFBundlePrimaryIcon</key>
|
20
|
+
<dict>
|
21
|
+
<key>CFBundleIconFiles</key>
|
22
|
+
<array>
|
23
|
+
<string>AppIcon60x60</string>
|
24
|
+
<string>AppIcon76x76</string>
|
25
|
+
</array>
|
26
|
+
<key>CFBundleIconName</key>
|
27
|
+
<string>AppIcon</string>
|
28
|
+
</dict>
|
29
|
+
</dict>
|
30
|
+
</dict>
|
31
|
+
</plist>
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#compdef escalator
|
2
|
+
#autoload
|
3
|
+
|
4
|
+
local -a _subcommands
|
5
|
+
local -a _arguments
|
6
|
+
local -a _options
|
7
|
+
|
8
|
+
case "$words[2]" in
|
9
|
+
confuse )
|
10
|
+
_options=(
|
11
|
+
"--project-path=path:path 为 .xcodeproj 源路径"
|
12
|
+
"--output-path=path:path 为混淆工程存放路径"
|
13
|
+
"--show-output:文件管理中展示输出文件夹, 默认: 否"
|
14
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
15
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
16
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
17
|
+
)
|
18
|
+
_describe -t options "escalator confuse options" _options
|
19
|
+
;;
|
20
|
+
archive )
|
21
|
+
case "$words[3]" in
|
22
|
+
app-store | ad-hoc )
|
23
|
+
_options=(
|
24
|
+
"--project-path=path:path 为 .xcproject 源路径"
|
25
|
+
"--output-path=path:path 为 .ipa 以及部分重签资源的存放路径"
|
26
|
+
"--show-output:文件管理中展示输出文件夹, 默认: 否"
|
27
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
28
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
29
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
30
|
+
)
|
31
|
+
_describe -t options "escalator archive options" _options
|
32
|
+
;;
|
33
|
+
* )
|
34
|
+
_arguments=(
|
35
|
+
"app-store:发布商店类型"
|
36
|
+
"ad-hoc:发布测试类型"
|
37
|
+
)
|
38
|
+
_describe -t arguments "escalator archive arguments" _arguments
|
39
|
+
;;
|
40
|
+
esac
|
41
|
+
;;
|
42
|
+
resign )
|
43
|
+
_options=(
|
44
|
+
"--key-id=id:id 为 Appstore Connect 用户访问密钥的 keyId"
|
45
|
+
"--issuer-id=id:id 为 Appstore Connect 用户访问密钥的 issuerId"
|
46
|
+
"--keyfile-path=path:path 为 Appstore Connect 用户访问密钥的 .p8 文件保存路径"
|
47
|
+
"--user-password=password:password 为当前电脑用户的访问密码"
|
48
|
+
"--bundle-identifier=identifier:identifier 为新的唯一标识符"
|
49
|
+
"--short-version=version:version 为新的版本号"
|
50
|
+
"--bundle-version=version:version 为新的 BuildID, 同一账号下处理多 IPA, 会自动叠加"
|
51
|
+
"--apple-id=id:id 为对应的苹果开发者账户, 如果含有 APP GROUP 推荐添加此字段, 默认: 无"
|
52
|
+
"--bundle-name=name:name 为新的包名, 默认: 不变"
|
53
|
+
"--display-name=name:name 为新的 APP 名称, 默认: 不变"
|
54
|
+
"--executable-name=name:name 为新的二进制文件名, 默认: 不变"
|
55
|
+
"--iconAssets-path=path:path 为包含新 AppIcon 的 .xcassets 资源文件路径, 默认: 无"
|
56
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
57
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
58
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
59
|
+
)
|
60
|
+
_describe -t options "escalator resign options" _options
|
61
|
+
;;
|
62
|
+
upload )
|
63
|
+
_options=(
|
64
|
+
"--key-id=id:id 为 Appstore Connect 用户访问密钥的 keyId"
|
65
|
+
"--issuer-id=id:id 为 Appstore Connect 用户访问密钥的 issuerId"
|
66
|
+
"--keyfile-path=path:path 为 Appstore Connect 用户访问密钥的 .p8 文件保存路径"
|
67
|
+
"--bundle-identifier=identifier:identifier 为上传账户下对应唯一标识符"
|
68
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
69
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
70
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
71
|
+
)
|
72
|
+
_describe -t options "escalator upload options" _options
|
73
|
+
;;
|
74
|
+
setup )
|
75
|
+
_arguments=(
|
76
|
+
"confuse:混淆命令"
|
77
|
+
"archive:打包命令"
|
78
|
+
"resign:重签命令"
|
79
|
+
"upload:上传命令"
|
80
|
+
)
|
81
|
+
_describe -t arguments "escalator setup arguments" _arguments
|
82
|
+
_options=(
|
83
|
+
"--output-path=path:path 为参数模版导出路径"
|
84
|
+
"--set-zshcompletion:会忽略其他参数, 只设置 oh-my-zsh 的命令补全插件到 custom/plugins 中, zshrc 配置插件, 请自己手动更新, 默认: 否"
|
85
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
86
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
87
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
88
|
+
)
|
89
|
+
_describe -t options "escalator setup options" _options
|
90
|
+
;;
|
91
|
+
combine )
|
92
|
+
_arguments=(
|
93
|
+
"confuse:混淆命令"
|
94
|
+
"archive:打包命令"
|
95
|
+
"resign:重签命令"
|
96
|
+
"upload:上传命令"
|
97
|
+
)
|
98
|
+
_describe -t arguments "escalator setup arguments" _arguments
|
99
|
+
_options=(
|
100
|
+
"--config-path=path:path 为任务流需要的配置参数 ConfigInfo.plist 文件路径"
|
101
|
+
"--input-path=path:path 为初始命令需要的输入根目录, 会自动检测需要的输入文件"
|
102
|
+
"--work-path=path:path 为脚本工作的根目录"
|
103
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
104
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
105
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
106
|
+
)
|
107
|
+
_describe -t options "escalator combine options" _options
|
108
|
+
;;
|
109
|
+
*)
|
110
|
+
_subcommands=(
|
111
|
+
"confuse:混淆 Xcode 工程"
|
112
|
+
"archive:打包 Xcode 工程"
|
113
|
+
"resign:重签 IPA 安装包"
|
114
|
+
"upload:上传 IPA 安装包"
|
115
|
+
"setup:生成 组合命令执行需要的参数模版"
|
116
|
+
"combine:组合 命令: confuse archive resign upload"
|
117
|
+
)
|
118
|
+
_describe -t commands "escalator subcommands" _subcommands
|
119
|
+
_options=(
|
120
|
+
"--help:仅输出指定命令的帮助文档, 默认: 否"
|
121
|
+
"--version:仅输出工具版本号, 默认: 否"
|
122
|
+
"--verbose:输出更多调试信息, 默认: 否"
|
123
|
+
"--no-ansi:关闭高亮输出模式, 默认: 否"
|
124
|
+
)
|
125
|
+
_describe -t options "escalator options" _options
|
126
|
+
;;
|
127
|
+
esac
|