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.
@@ -0,0 +1,138 @@
1
+ module Escalator
2
+
3
+ class Command
4
+
5
+ class Resign < Command
6
+
7
+ class Help < CLAide::Help
8
+
9
+ def message
10
+ [
11
+ formatted_error_message,
12
+ "请执行: escalator resign --help".ansi.green
13
+ ].compact.join("\n\n").insert 0, "\n"
14
+ end
15
+
16
+ end
17
+
18
+ attr_reader :ipaPaths
19
+
20
+ attr_reader :key_id
21
+
22
+ attr_reader :issuer_id
23
+
24
+ attr_reader :keyfile_path
25
+
26
+ attr_reader :apple_id
27
+
28
+ attr_reader :user_password
29
+
30
+ attr_reader :bundle_identifier
31
+
32
+ attr_reader :short_version
33
+
34
+ attr_reader :bundle_version
35
+
36
+ attr_reader :bundle_name
37
+
38
+ attr_reader :display_name
39
+
40
+ attr_reader :executable_name
41
+
42
+ attr_reader :iconAssets_path
43
+
44
+ self.command = "resign"
45
+
46
+ self.summary = "重签 IPA 安装包"
47
+
48
+ self.description = <<-DESC
49
+ 利用新的 #{"证书".ansi.yellow} 和 #{"配置".ansi.yellow} 对当前 IPA 安装包进行重签名并修改相应信息
50
+
51
+ Appstore Connect 用户访问密钥申请:
52
+
53
+ #{"https://appstoreconnect.apple.com => 登录 => 用户和访问 => 密钥".ansi.blue}
54
+
55
+ `IPAPATH` 要重签名的 IPA 路径, 支持同一账号处理多个 IPA
56
+
57
+ `--iconAssets-path=path` 参数若存在, 务必将 ipa 对应 Xcode 工程下所有被引用的 .xcassets 文件的拷贝到 IPA 所在的目录下, 若不提供 APP 将丢失所有老资源
58
+ DESC
59
+
60
+ self.arguments = [
61
+ CLAide::Argument.new('IPAPATH', true, false)
62
+ ]
63
+
64
+ def self.options
65
+ [
66
+ ["--key-id=id", "id 为 Appstore Connect 用户访问密钥的 keyId"],
67
+ ["--issuer-id=id", "id 为 Appstore Connect 用户访问密钥的 issuerId"],
68
+ ["--keyfile-path=path", "path 为 Appstore Connect 用户访问密钥的 .p8 文件保存路径"],
69
+ ["--user-password=password", "password 为当前电脑用户的访问密码"],
70
+ ["--bundle-identifier=identifier", "identifier 为新的唯一标识符"],
71
+ ["--short-version=version", "version 为新的版本号"],
72
+ ["--bundle-version=version", "version 为新的 BuildID, 同一账号下处理多 IPA, 会自动叠加"],
73
+ ["--apple-id=id", "id 为对应的苹果开发者账户, 如果含有 APP GROUP 推荐添加此字段, 默认: 无"],
74
+ ["--bundle-name=name", "name 为新的包名, 默认: 不变"],
75
+ ["--display-name=name", "name 为新的 APP 名称, 默认: 不变"],
76
+ ["--executable-name=name", "name 为新的二进制文件名, 默认: 不变"],
77
+ ["--iconAssets-path=path", "path 为包含新 AppIcon 的 .xcassets 资源文件路径, 默认: 无"]
78
+ ].concat super
79
+ end
80
+
81
+ def initialize argv
82
+ @ipaPaths = argv.arguments!.select{ |arg| !arg.empty? }
83
+ @key_id = argv.option "key-id", ""
84
+ @issuer_id = argv.option "issuer-id", ""
85
+ @keyfile_path = argv.option "keyfile-path", ""
86
+ @apple_id = argv.option "apple-id", ""
87
+ @user_password = argv.option "user-password", ""
88
+ @bundle_identifier = argv.option "bundle-identifier", ""
89
+ @short_version = argv.option "short-version", ""
90
+ @bundle_version = argv.option "bundle-version", ""
91
+ @bundle_name = argv.option "bundle-name", ""
92
+ @display_name = argv.option "display-name", ""
93
+ @executable_name = argv.option "executable-name", ""
94
+ @iconAssets_path = argv.option "iconAssets-path", ""
95
+ super
96
+ end
97
+
98
+ def validate!
99
+ super
100
+ if ipaPaths.empty?
101
+ help! "未检测到 IPAPATH 参数"
102
+ end
103
+ if key_id.empty?
104
+ help! "未检测到 --key-id 参数"
105
+ end
106
+ if issuer_id.empty?
107
+ help! "未检测到 --issuer-id 参数"
108
+ end
109
+ if keyfile_path.empty?
110
+ help! "未检测到 --keyfile-path 参数"
111
+ end
112
+ if user_password.empty?
113
+ help! "未检测到 --user-password 参数"
114
+ end
115
+ if bundle_identifier.empty?
116
+ help! "未检测到 --bundle-identifier 参数"
117
+ end
118
+ if short_version.empty?
119
+ help! "未检测到 --short-version 参数"
120
+ end
121
+ if bundle_version.empty?
122
+ help! "未检测到 --bundle-version 参数"
123
+ end
124
+ end
125
+
126
+ def help!(error_message = nil)
127
+ invoked_command_class.help!(error_message, Help)
128
+ end
129
+
130
+ def run
131
+ Escalator::Resign.run self
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,91 @@
1
+ module Escalator
2
+
3
+ class Command
4
+
5
+ class Setup < Command
6
+
7
+ class Help < CLAide::Help
8
+
9
+ def message
10
+ [
11
+ formatted_error_message,
12
+ "请执行: escalator setup --help".ansi.green
13
+ ].compact.join("\n\n").insert 0, "\n"
14
+ end
15
+
16
+ end
17
+
18
+ attr_reader :commands
19
+
20
+ attr_reader :output_path
21
+
22
+ attr_reader :set_zshcompletion
23
+
24
+ attr_reader :custom_plugins
25
+
26
+ self.command = "setup"
27
+
28
+ self.summary = "生成 组合命令执行需要的参数模版"
29
+
30
+ self.description = <<-DESC
31
+ 导出组合命令执行必须需的, 全局配置参数模版 和 独立配置参数模版
32
+
33
+ 独立参数模版, 在包含 #{"resign".ansi.green} 命令时才会导出
34
+
35
+ 独立参数模版, 需放置在对应输入项目的根路径下, 会覆盖全局配置中对应的参数
36
+
37
+ `COMMAND` 要组合的命令, 支持 #{"confuse archive resign upload".ansi.green} 命令
38
+ DESC
39
+
40
+ self.arguments = [
41
+ CLAide::Argument.new('COMMAND', true, true)
42
+ ]
43
+
44
+ def self.options
45
+ [
46
+ ["--output-path=path", "path 为参数模版导出路径"],
47
+ ["--set-zshcompletion", "会忽略其他参数, 只设置 oh-my-zsh 的命令补全插件到 custom/plugins 中, zshrc 配置插件, 请自己手动更新, 默认: 否"]
48
+ ].concat super
49
+ end
50
+
51
+ def initialize argv
52
+ @commands = argv.arguments!.uniq
53
+ @output_path = argv.option "output-path"
54
+ @set_zshcompletion = argv.flag? "set-zshcompletion", false
55
+ super
56
+ end
57
+
58
+ def validate!
59
+ super
60
+ if set_zshcompletion
61
+ if ENV["ZSH"].empty?
62
+ help! "未检测到 oh-my-zsh, 请先进行安装"
63
+ end
64
+ @custom_plugins = "#{ENV["ZSH"]}/custom/plugins/"
65
+ return
66
+ end
67
+ if commands.empty?
68
+ help! "未检测到 COMMAND 参数"
69
+ end
70
+ cmds = (commands - (%w(confuse archive resign upload) & commands))
71
+ if !cmds.empty?
72
+ help! "检测到 非法参数: #{cmds.join ", "}"
73
+ end
74
+ if !output_path
75
+ help! "未检测到 --output-path 参数"
76
+ end
77
+ end
78
+
79
+ def help!(error_message = nil)
80
+ invoked_command_class.help!(error_message, Help)
81
+ end
82
+
83
+ def run
84
+ Escalator::Setup.run self
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+
91
+ end
@@ -0,0 +1,95 @@
1
+ module Escalator
2
+
3
+ class Command
4
+
5
+ class Upload < Command
6
+
7
+ class Help < CLAide::Help
8
+
9
+ def message
10
+ [
11
+ formatted_error_message,
12
+ "请执行: escalator upload --help".ansi.green
13
+ ].compact.join("\n\n").insert 0, "\n"
14
+ end
15
+
16
+ end
17
+
18
+ attr_reader :ipaPaths
19
+
20
+ attr_reader :key_id
21
+
22
+ attr_reader :issuer_id
23
+
24
+ attr_reader :keyfile_path
25
+
26
+ attr_reader :bundle_identifier
27
+
28
+ self.command = "upload"
29
+
30
+ self.summary = "上传 IPA 安装包"
31
+
32
+ self.description = <<-DESC
33
+ 利用 Appstore Connect 用户访问密钥, 上传 ipa 安装包
34
+
35
+ Appstore Connect 用户访问密钥申请:
36
+
37
+ #{"https://appstoreconnect.apple.com => 登录 => 用户和访问 => 密钥".ansi.blue}
38
+
39
+ `IPAPATH` 要上传的 IPA 路径, 支持同一账号上传多个 IPA
40
+ DESC
41
+
42
+ self.arguments = [
43
+ CLAide::Argument.new('IPAPATH', true, true)
44
+ ]
45
+
46
+ def self.options
47
+ [
48
+ ["--key-id=id", "id 为 Appstore Connect 用户访问密钥的 keyId"],
49
+ ["--issuer-id=id", "id 为 Appstore Connect 用户访问密钥的 issuerId"],
50
+ ["--keyfile-path=path", "path 为 Appstore Connect 用户访问密钥的 .p8 文件保存路径"],
51
+ ["--bundle-identifier=identifier", "identifier 为上传账户下对应唯一标识符"]
52
+ ].concat super
53
+ end
54
+
55
+ def initialize argv
56
+ @ipaPaths = argv.arguments!.select { |arg| !arg.empty? }
57
+ @key_id = argv.option "key-id", ""
58
+ @issuer_id = argv.option "issuer-id", ""
59
+ @keyfile_path = argv.option "keyfile-path", ""
60
+ @bundle_identifier = argv.option "bundle-identifier", ""
61
+ super
62
+ end
63
+
64
+ def validate!
65
+ super
66
+ if ipaPaths.empty?
67
+ help! "未检测到 IPAPATH 参数"
68
+ end
69
+ if key_id.empty?
70
+ help! "未检测到 --key-id 参数"
71
+ end
72
+ if issuer_id.empty?
73
+ help! "未检测到 --issuer-id 参数"
74
+ end
75
+ if keyfile_path.empty?
76
+ help! "未检测到 --keyfile-path 参数"
77
+ end
78
+ if bundle_identifier.empty?
79
+ help! "未检测到 --bundle-identifier 参数"
80
+ end
81
+ end
82
+
83
+ def help!(error_message = nil)
84
+ invoked_command_class.help!(error_message, Help)
85
+ end
86
+
87
+ def run
88
+ Escalator::Upload.run self
89
+ end
90
+
91
+ end
92
+
93
+ end
94
+
95
+ end
@@ -0,0 +1,46 @@
1
+ module Escalator
2
+
3
+ class Command < CLAide::Command
4
+
5
+ require_relative "command/confuse"
6
+ require_relative "command/archive"
7
+ require_relative "command/resign"
8
+ require_relative "command/upload"
9
+ require_relative "command/combine"
10
+ require_relative "command/setup"
11
+
12
+ self.abstract_command = true
13
+
14
+ self.version = VERSION
15
+
16
+ self.command = "escalator"
17
+
18
+ self.description = <<-DESC
19
+ 本工具专为 testflight 上架多马甲包而生
20
+
21
+ 旨在取代马甲包代码频繁修改, 上传安装包繁杂的人工流程
22
+
23
+ 主要功能包含: 代码混淆, 项目打包, ipa重签名, ipa上传
24
+ DESC
25
+
26
+ DEFAULT_ROOT_OPTIONS = [
27
+ ['--version', '仅输出工具版本号, 默认: 否'],
28
+ ]
29
+
30
+ DEFAULT_OPTIONS = [
31
+ ['--verbose', '输出更多调试信息, 默认: 否'],
32
+ ['--no-ansi', '关闭高亮输出模式, 默认: 否'],
33
+ ['--help', '仅输出指定命令的帮助文档, 默认: 否'],
34
+ ]
35
+
36
+ def self.options
37
+ if root_command?
38
+ DEFAULT_ROOT_OPTIONS + DEFAULT_OPTIONS
39
+ else
40
+ DEFAULT_OPTIONS
41
+ end
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,101 @@
1
+ module Escalator
2
+
3
+ class Confuse
4
+
5
+ class << self
6
+
7
+ def run command
8
+ @command = command
9
+ Throw.note "Begin confuse #{File.basename File.dirname command.project_path} ..."
10
+ prepareContext
11
+ handleProject
12
+ project_path
13
+ end
14
+
15
+ private
16
+
17
+ EXTNAMES = ["h", "hpp", "pch", "c", "m", "mm", "cpp", "swift", "xib", "storyboard"]
18
+
19
+ attr_accessor :command
20
+
21
+ attr_accessor :keywords
22
+
23
+ attr_accessor :project_path
24
+
25
+ def prepareContext
26
+ Throw.note "Prepare confuse context ..."
27
+ @keywords = []
28
+ timestamp = Time.now.to_i.to_s
29
+ command.keywords.each { |keyword|
30
+ part1 = (Random.rand(25) + 65).chr
31
+ part2 = OpenSSL::Digest.hexdigest("SHA1", keyword + timestamp)[0,7].upcase
32
+ text1 = part1 + part2
33
+ text2 = text1.sub(/[A-Z]*[0-9a-z]/) { |match| match.downcase }
34
+ @keywords << OpenStruct.new(:first => text1,
35
+ :second => text2,
36
+ :value => keyword,
37
+ :regexp => Regexp.new(keyword, Regexp::IGNORECASE))
38
+ }
39
+ if command.verbose?
40
+ puts keywords.map { |keyword|
41
+ "#{keyword.value} ==> first: #{keyword.first} second: #{keyword.second}\n"
42
+ }
43
+ end
44
+ source_path = File.expand_path("../", command.project_path)
45
+ output_path = File.expand_path("./", command.output_path)
46
+ project_name = File.basename(command.project_path)
47
+ target_path = "#{output_path}/#{File.basename(source_path)}"
48
+ @project_path = "#{target_path}/#{project_name}"
49
+ FileUtils.mkdir_p output_path
50
+ if File.exist? target_path
51
+ FileUtils.rm_rf target_path
52
+ end
53
+ FileUtils.cp_r source_path, output_path
54
+ end
55
+
56
+ def handleProject
57
+ project = Xcodeproj::Project.open project_path
58
+ keywords.each { |keyword|
59
+ Throw.note "Begin Confuse #{keyword.value} ..."
60
+ handleGroup project.groups.first, keyword
61
+ }
62
+ project.save project_path
63
+ if command.show_output?
64
+ system "open #{command.output_path}"
65
+ end
66
+ Throw.note "Confuse Success!"
67
+ end
68
+
69
+ def handleGroup group, keyword
70
+ group.anyGroups.each { |subGroup|
71
+ handleGroup subGroup, keyword
72
+ }
73
+ group.files.each { |file|
74
+ if command.verbose?
75
+ puts "Confusing #{keyword.value} for #{file.path} ..."
76
+ end
77
+ if file.path.include? keyword.value
78
+ dir = File.dirname(file.real_path)
79
+ name = file.path.gsub keyword.regexp, keyword.first
80
+ FileUtils.mv file.real_path, "#{dir}/#{name}"
81
+ file.set_path name
82
+ end
83
+ handleFile file, keyword
84
+ }
85
+ end
86
+
87
+ def handleFile file, keyword
88
+ if EXTNAMES.include? file.path.split(".").last
89
+ content = File.read file.real_path
90
+ content = content.gsub(keyword.regexp) { |match|
91
+ match == keyword.value ? keyword.first : keyword.second
92
+ }
93
+ File.write file.real_path, content
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
101
+ end
@@ -0,0 +1,13 @@
1
+ module Escalator
2
+
3
+ class Xcodeproj::Project::Object::PBXGroup
4
+
5
+ def anyGroups
6
+ children.select { |child|
7
+ child.is_a?(Xcodeproj::Project::Object::PBXGroup)
8
+ }
9
+ end
10
+
11
+ end
12
+
13
+ end