pindo 5.13.1 → 5.13.3
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 +4 -4
- data/lib/pindo/base/git_handler.rb +692 -0
- data/lib/pindo/command/android/autobuild.rb +2 -2
- data/lib/pindo/command/appstore/adhocbuild.rb +256 -311
- data/lib/pindo/command/appstore/autobuild.rb +203 -0
- data/lib/pindo/command/appstore/autoresign.rb +35 -17
- data/lib/pindo/command/appstore/bundleid.rb +120 -0
- data/lib/pindo/command/appstore/cert.rb +212 -0
- data/lib/pindo/command/appstore/configproj.rb +81 -0
- data/lib/pindo/command/{deploy → appstore}/getitcinfo.rb +76 -91
- data/lib/pindo/command/appstore/iap.rb +788 -24
- data/lib/pindo/command/appstore/initconfig.rb +105 -0
- data/lib/pindo/command/appstore/itcapp.rb +95 -13
- data/lib/pindo/command/{deploy → appstore}/itcinfo.rb +90 -118
- data/lib/pindo/command/appstore/pem.rb +136 -0
- data/lib/pindo/command/appstore/pullconfig.rb +99 -0
- data/lib/pindo/command/appstore/quswark.rb +87 -0
- data/lib/pindo/command/appstore/quswauth.rb +67 -0
- data/lib/pindo/command/appstore/tag.rb +77 -0
- data/lib/pindo/command/appstore.rb +13 -1
- data/lib/pindo/command/env/quarkenv.rb +11 -13
- data/lib/pindo/command/env/swarkenv.rb +11 -16
- data/lib/pindo/command/ios/applovin.rb +24 -182
- data/lib/pindo/command/ios/autobuild.rb +64 -43
- data/lib/pindo/command/ios/autoresign.rb +34 -19
- data/lib/pindo/command/ios/build.rb +9 -6
- data/lib/pindo/command/ios/cert.rb +27 -20
- data/lib/pindo/command/ios/podupdate.rb +6 -37
- data/lib/pindo/command/jps/upload.rb +3 -3
- data/lib/pindo/command/unity/autobuild.rb +2 -2
- data/lib/pindo/command/utils/clearcert.rb +2 -17
- data/lib/pindo/command/{deploy → utils}/fabric.rb +13 -13
- data/lib/pindo/command/utils/renewcert.rb +62 -38
- data/lib/pindo/command/utils/renewproj.rb +0 -3
- data/lib/pindo/command/{deploy → utils}/updateconfig.rb +6 -7
- data/lib/pindo/command/utils.rb +2 -0
- data/lib/pindo/command/web/autobuild.rb +2 -2
- data/lib/pindo/command.rb +30 -3
- data/lib/pindo/config/build_info_manager.rb +176 -0
- data/lib/pindo/config/ios_config_parser.rb +404 -0
- data/lib/pindo/module/android/android_config_helper.rb +9 -5
- data/lib/pindo/module/appstore/bundleid_helper.rb +349 -0
- data/lib/pindo/module/appstore/itcapp_helper.rb +228 -0
- data/lib/pindo/module/build/build_helper.rb +12 -0
- data/lib/pindo/module/build/swark_helper.rb +116 -77
- data/lib/pindo/module/cert/cert_helper.rb +74 -0
- data/lib/pindo/module/cert/pem_helper.rb +72 -0
- data/lib/pindo/module/cert/{xcodecerthelper.rb → xcode_cert_helper.rb} +211 -6
- data/lib/pindo/module/pgyer/pgyerhelper.rb +13 -5
- data/lib/pindo/module/task/model/appstore/appstore_task.rb +18 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_ipa_task.rb +151 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_metadata_task.rb +250 -0
- data/lib/pindo/module/task/model/appstore/appstore_upload_screenshot_task.rb +276 -0
- data/lib/pindo/module/task/model/build/android_build_adhoc_task.rb +210 -0
- data/lib/pindo/module/task/model/build/{android_dev_build_task.rb → android_build_dev_task.rb} +2 -2
- data/lib/pindo/module/task/model/build/android_build_gplay_task.rb +210 -0
- data/lib/pindo/module/task/model/build/android_build_task.rb +13 -0
- data/lib/pindo/module/task/model/build/ios_build_adhoc_task.rb +342 -0
- data/lib/pindo/module/task/model/build/ios_build_appstore_task.rb +341 -0
- data/lib/pindo/module/task/model/build/{ios_dev_build_task.rb → ios_build_dev_task.rb} +40 -59
- data/lib/pindo/module/task/model/build/ios_build_task.rb +23 -0
- data/lib/pindo/module/task/model/build/{web_dev_build_task.rb → web_build_dev_task.rb} +1 -1
- data/lib/pindo/module/task/model/build_task.rb +15 -12
- data/lib/pindo/module/task/model/jps_resign_task.rb +185 -0
- data/lib/pindo/module/task/model/{upload_task.rb → jps_upload_task.rb} +3 -3
- data/lib/pindo/module/task/model/unity_export_task.rb +3 -1
- data/lib/pindo/module/unity/unity_helper.rb +2 -1
- data/lib/pindo/module/xcode/applovin_xcode_helper.rb +271 -0
- data/lib/pindo/module/xcode/cocoapods_helper.rb +153 -0
- data/lib/pindo/module/xcode/ipa_resign_helper.rb +210 -0
- data/lib/pindo/module/xcode/{xcodeappconfig.rb → xcode_app_config.rb} +79 -0
- data/lib/pindo/module/xcode/xcode_build_config.rb +152 -17
- data/lib/pindo/module/xcode/xcode_build_helper.rb +151 -1
- data/lib/pindo/module/xcode/xcode_swark_helper.rb +341 -0
- data/lib/pindo/options/core/global_options_state.rb +268 -0
- data/lib/pindo/options/core/option_configuration.rb +206 -0
- data/lib/pindo/options/core/option_initializer.rb +51 -0
- data/lib/pindo/options/core/option_item.rb +144 -0
- data/lib/pindo/options/core/option_value_parser.rb +54 -0
- data/lib/pindo/options/groups/build_options.rb +60 -0
- data/lib/pindo/options/groups/jps_options.rb +70 -0
- data/lib/pindo/options/groups/option_group.rb +73 -0
- data/lib/pindo/options/helpers/bundleid_selector.rb +103 -0
- data/lib/pindo/options/options.rb +14 -0
- data/lib/pindo/version.rb +1 -1
- metadata +51 -40
- data/lib/pindo/command/appstore/import.rb +0 -259
- data/lib/pindo/command/deploy/build.rb +0 -250
- data/lib/pindo/command/deploy/bundleid.rb +0 -259
- data/lib/pindo/command/deploy/cert.rb +0 -202
- data/lib/pindo/command/deploy/check.rb +0 -93
- data/lib/pindo/command/deploy/configproj.rb +0 -120
- data/lib/pindo/command/deploy/confusecode.rb +0 -262
- data/lib/pindo/command/deploy/confuseproj.rb +0 -122
- data/lib/pindo/command/deploy/iap.rb +0 -826
- data/lib/pindo/command/deploy/initconfig.rb +0 -138
- data/lib/pindo/command/deploy/itcapp.rb +0 -146
- data/lib/pindo/command/deploy/pem.rb +0 -55
- data/lib/pindo/command/deploy/pullconfig.rb +0 -56
- data/lib/pindo/command/deploy/pushconfig.rb +0 -93
- data/lib/pindo/command/deploy/quswark.rb +0 -156
- data/lib/pindo/command/deploy/quswauth.rb +0 -76
- data/lib/pindo/command/deploy/reportbug.rb +0 -145
- data/lib/pindo/command/deploy/resign.rb +0 -300
- data/lib/pindo/command/deploy/tag.rb +0 -108
- data/lib/pindo/command/deploy/uploadipa.rb +0 -73
- data/lib/pindo/command/deploy.rb +0 -42
- data/lib/pindo/command/dev/autobuild.rb +0 -117
- data/lib/pindo/command/dev/build.rb +0 -94
- data/lib/pindo/command/dev/debug.rb +0 -112
- data/lib/pindo/module/task/model/build/android_release_build_task.rb +0 -29
- data/lib/pindo/module/task/model/build/ios_adhoc_build_task.rb +0 -53
- data/lib/pindo/module/task/model/build/ios_release_build_task.rb +0 -53
- data/lib/pindo/options/appconfigoptions.rb +0 -24
- data/lib/pindo/options/deployoptions.rb +0 -372
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'faraday'
|
|
4
|
+
require 'xcodeproj'
|
|
5
|
+
require 'pindo/base/git_handler'
|
|
6
|
+
require 'pindo/config/pindoconfig'
|
|
7
|
+
|
|
8
|
+
module Pindo
|
|
9
|
+
# Applovin Xcode 辅助类
|
|
10
|
+
# 封装 Applovin 相关的操作,包括:
|
|
11
|
+
# - 获取 SKAdNetwork IDs
|
|
12
|
+
# - 更新 Info.plist 文件
|
|
13
|
+
# - 运行 Applovin 安装脚本
|
|
14
|
+
class ApplovinXcodeHelper
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# 更新 Xcode 工程的 Applovin 配置
|
|
18
|
+
# @param project_dir [String] 项目目录,默认为当前目录
|
|
19
|
+
# @param appstore_mode [Boolean] 是否为 AppStore 模式
|
|
20
|
+
# @param install_script [Boolean] 是否运行安装脚本
|
|
21
|
+
# @param upload_config [Boolean] 是否保存配置到远程
|
|
22
|
+
# @return [Boolean] 是否成功
|
|
23
|
+
def update_applovin_config(project_dir: nil, appstore_mode: false, install_script: false, upload_config: false)
|
|
24
|
+
project_dir ||= Dir.pwd
|
|
25
|
+
|
|
26
|
+
# 1. 获取 SKAdNetwork IDs
|
|
27
|
+
skadnetwork_ids = fetch_skadnetwork_ids(upload_config: upload_config)
|
|
28
|
+
|
|
29
|
+
if skadnetwork_ids.nil? || skadnetwork_ids.empty?
|
|
30
|
+
puts "⚠ 未能获取 SKAdNetwork IDs"
|
|
31
|
+
return false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
puts "✓ 获取到 #{skadnetwork_ids.size} 条 SKAdNetwork IDs"
|
|
35
|
+
|
|
36
|
+
# 2. 更新 Info.plist
|
|
37
|
+
update_info_plist(project_dir: project_dir, skadnetwork_ids: skadnetwork_ids)
|
|
38
|
+
|
|
39
|
+
# 3. 运行安装脚本(可选)
|
|
40
|
+
if install_script
|
|
41
|
+
run_applovin_install_script(project_dir: project_dir, appstore_mode: appstore_mode)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
true
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# 获取 SKAdNetwork IDs
|
|
48
|
+
# @param upload_config [Boolean] 是否保存配置到远程
|
|
49
|
+
# @return [Array<String>] SKAdNetwork IDs 数组
|
|
50
|
+
def fetch_skadnetwork_ids(upload_config: false)
|
|
51
|
+
skadnetwork_ids = []
|
|
52
|
+
|
|
53
|
+
puts "正在请求 Applovin 数据..."
|
|
54
|
+
|
|
55
|
+
# 1. 请求 Applovin SKAdNetwork IDs
|
|
56
|
+
applovin_data = request_applovin_skadnetwork_ids
|
|
57
|
+
if applovin_data && applovin_data["skadnetwork_ids"]
|
|
58
|
+
applovin_data["skadnetwork_ids"].each do |network_id|
|
|
59
|
+
skadnetwork_ids << network_id["skadnetwork_id"]
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# 2. 请求 Applovin Mediation SKAdNetwork IDs
|
|
64
|
+
mediation_data = request_applovin_mediation_skadnetwork_ids
|
|
65
|
+
if mediation_data && mediation_data["mediationSKAdnetworkIdsSpecs"]
|
|
66
|
+
mediation_data["mediationSKAdnetworkIdsSpecs"].each do |media_item|
|
|
67
|
+
skadnetwork_ids += media_item["skAdnetworkIds"]
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# 3. 去重
|
|
72
|
+
skadnetwork_ids = skadnetwork_ids.uniq
|
|
73
|
+
|
|
74
|
+
puts "✓ 从网络获取到 #{skadnetwork_ids.size} 条数据"
|
|
75
|
+
|
|
76
|
+
# 4. 如果数据太少,从配置文件读取
|
|
77
|
+
if skadnetwork_ids.size <= 50
|
|
78
|
+
puts "网络数据太少,从缓存中获取..."
|
|
79
|
+
cached_ids = load_cached_skadnetwork_ids
|
|
80
|
+
skadnetwork_ids += cached_ids
|
|
81
|
+
skadnetwork_ids = skadnetwork_ids.uniq
|
|
82
|
+
puts "✓ 从缓存获取到 #{skadnetwork_ids.size} 条数据"
|
|
83
|
+
elsif upload_config
|
|
84
|
+
# 5. 保存到配置文件
|
|
85
|
+
save_skadnetwork_ids_to_config(skadnetwork_ids)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
skadnetwork_ids
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# 更新 Info.plist 文件
|
|
92
|
+
# @param project_dir [String] 项目目录
|
|
93
|
+
# @param skadnetwork_ids [Array<String>] SKAdNetwork IDs
|
|
94
|
+
def update_info_plist(project_dir:, skadnetwork_ids:)
|
|
95
|
+
puts "正在更新 Xcode Info.plist..."
|
|
96
|
+
|
|
97
|
+
# 1. 查找 Info.plist 文件
|
|
98
|
+
plist_file = find_info_plist(project_dir: project_dir)
|
|
99
|
+
|
|
100
|
+
unless File.exist?(plist_file)
|
|
101
|
+
puts "⚠ 未找到 Info.plist 文件: #{plist_file}"
|
|
102
|
+
return false
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# 2. 读取 Info.plist
|
|
106
|
+
info_plist_dict = Xcodeproj::Plist.read_from_path(plist_file)
|
|
107
|
+
|
|
108
|
+
# 3. 更新配置
|
|
109
|
+
info_plist_dict["NSAdvertisingAttributionReportEndpoint"] ||= "https://postbacks-app.com"
|
|
110
|
+
|
|
111
|
+
if !info_plist_dict.has_key?("NSAppTransportSecurity")
|
|
112
|
+
info_plist_dict["NSAppTransportSecurity"] = {}
|
|
113
|
+
info_plist_dict["NSAppTransportSecurity"]["NSAllowsArbitraryLoads"] = true
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# 4. 更新 SKAdNetworkItems
|
|
117
|
+
if skadnetwork_ids && skadnetwork_ids.size > 0
|
|
118
|
+
info_plist_dict["SKAdNetworkItems"] = []
|
|
119
|
+
skadnetwork_ids.each do |network_id|
|
|
120
|
+
item = { "SKAdNetworkIdentifier" => network_id }
|
|
121
|
+
info_plist_dict["SKAdNetworkItems"] << item
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# 5. 写回 Info.plist
|
|
126
|
+
Xcodeproj::Plist.write_to_path(info_plist_dict, plist_file)
|
|
127
|
+
|
|
128
|
+
puts "✓ Info.plist 更新完成"
|
|
129
|
+
true
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# 运行 Applovin 安装脚本
|
|
133
|
+
# @param project_dir [String] 项目目录
|
|
134
|
+
# @param appstore_mode [Boolean] 是否为 AppStore 模式
|
|
135
|
+
def run_applovin_install_script(project_dir:, appstore_mode: false)
|
|
136
|
+
xcodeproj_file = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by { |f| File.mtime(f) }
|
|
137
|
+
return unless xcodeproj_file && File.exist?(xcodeproj_file)
|
|
138
|
+
|
|
139
|
+
pindo_common_dir = Pindoconfig.instance.pindo_common_configdir
|
|
140
|
+
|
|
141
|
+
# 选择脚本文件
|
|
142
|
+
script_name = appstore_mode ? "AppLovinQualityServiceSetup-ios.rb" : "AppLovinQualityServiceSetup-ios-dev.rb"
|
|
143
|
+
source_script = File.join(pindo_common_dir, script_name)
|
|
144
|
+
|
|
145
|
+
return unless File.exist?(source_script)
|
|
146
|
+
|
|
147
|
+
# 复制脚本到项目目录
|
|
148
|
+
project_script = File.join(project_dir, "AppLovinQualityServiceSetup-ios.rb")
|
|
149
|
+
FileUtils.cp_r(source_script, project_script)
|
|
150
|
+
|
|
151
|
+
# 运行脚本
|
|
152
|
+
puts "正在运行 Applovin 安装脚本..."
|
|
153
|
+
system("ruby #{project_script}")
|
|
154
|
+
puts "✓ Applovin 安装脚本执行完成"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
private
|
|
158
|
+
|
|
159
|
+
# 请求 Applovin SKAdNetwork IDs
|
|
160
|
+
# @return [Hash, nil] JSON 数据
|
|
161
|
+
def request_applovin_skadnetwork_ids
|
|
162
|
+
begin
|
|
163
|
+
url = "https://dash.applovin.com/docs/v1/skadnetwork_ids.json"
|
|
164
|
+
conn = Faraday.new
|
|
165
|
+
response = conn.get do |req|
|
|
166
|
+
req.url url
|
|
167
|
+
req.headers['Content-Type'] = 'application/json'
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
JSON.parse(response.body)
|
|
171
|
+
rescue => e
|
|
172
|
+
puts "⚠ 请求 Applovin SKAdNetwork IDs 失败: #{e.message}"
|
|
173
|
+
nil
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# 请求 Applovin Mediation SKAdNetwork IDs
|
|
178
|
+
# @return [Hash, nil] JSON 数据
|
|
179
|
+
def request_applovin_mediation_skadnetwork_ids
|
|
180
|
+
begin
|
|
181
|
+
url = "https://dash.applovin.com/docs/v1/mediation_sk_adnetwork_ids"
|
|
182
|
+
conn = Faraday.new
|
|
183
|
+
response = conn.get do |req|
|
|
184
|
+
req.url url
|
|
185
|
+
req.headers['Content-Type'] = 'application/json'
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
JSON.parse(response.body)
|
|
189
|
+
rescue => e
|
|
190
|
+
puts "⚠ 请求 Applovin Mediation SKAdNetwork IDs 失败: #{e.message}"
|
|
191
|
+
nil
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
# 从配置文件加载缓存的 SKAdNetwork IDs
|
|
196
|
+
# @return [Array<String>] SKAdNetwork IDs
|
|
197
|
+
def load_cached_skadnetwork_ids
|
|
198
|
+
config_file = File.join(Pindoconfig.instance.pindo_common_configdir, "applovin_client_config.json")
|
|
199
|
+
return [] unless File.exist?(config_file)
|
|
200
|
+
|
|
201
|
+
begin
|
|
202
|
+
config_json = JSON.parse(File.read(config_file))
|
|
203
|
+
config_json["SKAdNetworkItems"] || []
|
|
204
|
+
rescue => e
|
|
205
|
+
puts "⚠ 读取缓存配置失败: #{e.message}"
|
|
206
|
+
[]
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# 保存 SKAdNetwork IDs 到配置文件
|
|
211
|
+
# @param skadnetwork_ids [Array<String>] SKAdNetwork IDs
|
|
212
|
+
def save_skadnetwork_ids_to_config(skadnetwork_ids)
|
|
213
|
+
config_dir = Pindoconfig.instance.pindo_common_configdir
|
|
214
|
+
config_file = File.join(config_dir, "applovin_client_config.json")
|
|
215
|
+
|
|
216
|
+
# 读取原有配置
|
|
217
|
+
origin_json = {}
|
|
218
|
+
if File.exist?(config_file)
|
|
219
|
+
origin_json = JSON.parse(File.read(config_file))
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# 更新配置
|
|
223
|
+
origin_json["SKAdNetworkItems"] = skadnetwork_ids
|
|
224
|
+
|
|
225
|
+
# 写入文件
|
|
226
|
+
File.write(config_file, JSON.pretty_generate(origin_json))
|
|
227
|
+
|
|
228
|
+
# 提交到 Git
|
|
229
|
+
begin
|
|
230
|
+
Pindo::GitHandler.git_addpush_repo(
|
|
231
|
+
path: config_dir,
|
|
232
|
+
message: "Applovin SKAdNetworkItems",
|
|
233
|
+
commit_file_params: ["applovin_client_config.json"]
|
|
234
|
+
)
|
|
235
|
+
puts "✓ 配置已保存到远程仓库"
|
|
236
|
+
rescue => e
|
|
237
|
+
puts "⚠ 提交配置到 Git 失败: #{e.message}"
|
|
238
|
+
end
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
# 查找 Info.plist 文件路径
|
|
242
|
+
# @param project_dir [String] 项目目录
|
|
243
|
+
# @return [String] Info.plist 文件路径
|
|
244
|
+
def find_info_plist(project_dir:)
|
|
245
|
+
# 默认路径
|
|
246
|
+
default_plist = File.join(project_dir, "AppEntry/Info.plist")
|
|
247
|
+
|
|
248
|
+
# 查找 .xcodeproj 文件
|
|
249
|
+
xcodeproj_file = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by { |f| File.mtime(f) }
|
|
250
|
+
return default_plist unless xcodeproj_file
|
|
251
|
+
|
|
252
|
+
# 从 Xcode 工程中查找 Info.plist
|
|
253
|
+
begin
|
|
254
|
+
proj_name = File.basename(xcodeproj_file, ".xcodeproj")
|
|
255
|
+
project_obj = Xcodeproj::Project.open(xcodeproj_file)
|
|
256
|
+
|
|
257
|
+
project_obj.targets.each do |target|
|
|
258
|
+
if target.product_type.to_s == "com.apple.product-type.application"
|
|
259
|
+
temp_info = target.build_configurations.first.build_settings['INFOPLIST_FILE']
|
|
260
|
+
return File.join(project_dir, temp_info) if temp_info
|
|
261
|
+
end
|
|
262
|
+
end
|
|
263
|
+
rescue => e
|
|
264
|
+
puts "⚠ 解析 Xcode 工程失败: #{e.message}"
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
default_plist
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require 'cocoapods'
|
|
2
|
+
require 'fileutils'
|
|
3
|
+
require 'pindo/base/git_handler'
|
|
4
|
+
require 'pindo/config/pindoconfig'
|
|
5
|
+
|
|
6
|
+
module Pindo
|
|
7
|
+
# CocoaPods 操作辅助类
|
|
8
|
+
# 封装 CocoaPods 相关的操作,包括:
|
|
9
|
+
# - 更新私有索引库
|
|
10
|
+
# - 同步 podspec
|
|
11
|
+
# - 执行 pod install
|
|
12
|
+
class CocoaPodsHelper
|
|
13
|
+
|
|
14
|
+
class << self
|
|
15
|
+
# 更新私有 Pod 索引库
|
|
16
|
+
# @param install [Boolean] 是否执行 pod install
|
|
17
|
+
# @param project_dir [String] 项目目录,默认为当前目录
|
|
18
|
+
# @return [Boolean] 是否成功
|
|
19
|
+
def update_pod_repo(install: false, project_dir: nil)
|
|
20
|
+
project_dir ||= Dir.pwd
|
|
21
|
+
|
|
22
|
+
# 获取私有 Pod 索引地址
|
|
23
|
+
pod_index_url = get_private_pod_index_url
|
|
24
|
+
raise "私有Pod索引地址未知!!" if pod_index_url.nil?
|
|
25
|
+
|
|
26
|
+
# 更新私有索引库
|
|
27
|
+
update_private_repo(pod_index_url)
|
|
28
|
+
|
|
29
|
+
# 如果需要,执行 pod install
|
|
30
|
+
if install
|
|
31
|
+
install_pods(project_dir)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# 执行 pod install
|
|
38
|
+
# @param project_dir [String] 项目目录
|
|
39
|
+
# @return [Boolean] 是否成功
|
|
40
|
+
def install_pods(project_dir)
|
|
41
|
+
podfile_path = File.join(project_dir, "Podfile")
|
|
42
|
+
return false unless File.exist?(podfile_path)
|
|
43
|
+
|
|
44
|
+
begin
|
|
45
|
+
puts "正在执行 pod install..."
|
|
46
|
+
Dir.chdir(project_dir) do
|
|
47
|
+
Pod::Command::Install.run(['--clean-install'])
|
|
48
|
+
end
|
|
49
|
+
true
|
|
50
|
+
rescue => e
|
|
51
|
+
puts "Pod install 失败: #{e.message}"
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# 清理并重新安装 CocoaPods
|
|
57
|
+
# @param project_dir [String] 项目目录
|
|
58
|
+
def deintegrate_and_install(project_dir)
|
|
59
|
+
return unless File.exist?(File.join(project_dir, "Podfile"))
|
|
60
|
+
|
|
61
|
+
Dir.chdir(project_dir) do
|
|
62
|
+
begin
|
|
63
|
+
# 清理现有 Pods
|
|
64
|
+
FileUtils.rm_rf("Podfile.lock") if File.exist?("Podfile.lock")
|
|
65
|
+
FileUtils.rm_rf("Pods") if File.exist?("Pods")
|
|
66
|
+
|
|
67
|
+
puts "正在执行 pod deintegrate..."
|
|
68
|
+
system 'pod deintegrate'
|
|
69
|
+
|
|
70
|
+
puts "正在执行 pod install..."
|
|
71
|
+
system 'pod install'
|
|
72
|
+
|
|
73
|
+
# 检查 pod install 是否成功
|
|
74
|
+
unless File.exist?("Podfile.lock")
|
|
75
|
+
raise "pod install 失败!!先 pod install 完成后再编译!"
|
|
76
|
+
end
|
|
77
|
+
rescue => error
|
|
78
|
+
puts error.to_s
|
|
79
|
+
raise "pod install 失败!!先 pod install 完成后再编译!"
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# 检查是否使用了特定的 Pod
|
|
85
|
+
# @param project_dir [String] 项目目录
|
|
86
|
+
# @param pod_names [Array<String>] Pod 名称列表
|
|
87
|
+
# @return [Boolean] 是否使用了任一指定的 Pod
|
|
88
|
+
def using_pods?(project_dir, pod_names)
|
|
89
|
+
pod_lock_file = File.join(project_dir, "Podfile.lock")
|
|
90
|
+
return false unless File.exist?(pod_lock_file)
|
|
91
|
+
|
|
92
|
+
begin
|
|
93
|
+
pod_lock_json = Pod::YAMLHelper.load_file(pod_lock_file)
|
|
94
|
+
pods_array = []
|
|
95
|
+
|
|
96
|
+
if !pod_lock_json["SPEC REPOS"].nil?
|
|
97
|
+
pod_lock_json["SPEC REPOS"].each do |source, pod_items|
|
|
98
|
+
pods_array += pod_items
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
pod_names.any? { |name| pods_array.include?(name) }
|
|
103
|
+
rescue => e
|
|
104
|
+
puts "检查 Podfile.lock 失败: #{e.message}"
|
|
105
|
+
false
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# 获取私有 Pod 索引地址
|
|
112
|
+
# @return [String, nil] 索引地址
|
|
113
|
+
def get_private_pod_index_url
|
|
114
|
+
config = Pindoconfig.instance
|
|
115
|
+
pod_array = config.pod_repo_dict
|
|
116
|
+
return nil if pod_array.nil?
|
|
117
|
+
|
|
118
|
+
pod_array['podindex']
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# 更新私有索引库
|
|
122
|
+
# @param pod_index_url [String] 索引库地址
|
|
123
|
+
def update_private_repo(pod_index_url)
|
|
124
|
+
sources = Pod::Config.instance.sources_manager.all
|
|
125
|
+
repos_path = File.expand_path("~/.cocoapods/repos")
|
|
126
|
+
|
|
127
|
+
puts "私有Pod地址: #{pod_index_url}"
|
|
128
|
+
puts "私有Pod目录: ~/.cocoapods"
|
|
129
|
+
|
|
130
|
+
# 查找已存在的私有源
|
|
131
|
+
private_source = sources.select { |s| s.git? && s.url.to_s.eql?(pod_index_url) }.first
|
|
132
|
+
|
|
133
|
+
if !private_source.nil?
|
|
134
|
+
# 更新已存在的私有源
|
|
135
|
+
repo_name = File.basename(private_source.repo)
|
|
136
|
+
Pindo::GitHandler.getcode_to_dir(
|
|
137
|
+
reponame: repo_name,
|
|
138
|
+
remote_url: pod_index_url,
|
|
139
|
+
path: repos_path
|
|
140
|
+
)
|
|
141
|
+
else
|
|
142
|
+
# 添加新的私有源
|
|
143
|
+
repository_name = pod_index_url.split("/").last.chomp(".git")
|
|
144
|
+
Pindo::GitHandler.getcode_to_dir(
|
|
145
|
+
reponame: repository_name,
|
|
146
|
+
remote_url: pod_index_url,
|
|
147
|
+
path: repos_path
|
|
148
|
+
)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'sigh'
|
|
3
|
+
require 'zip'
|
|
4
|
+
require 'pindo/config/pindoconfig'
|
|
5
|
+
|
|
6
|
+
module Pindo
|
|
7
|
+
class IpaResignHelper
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
# 重签名 IPA 文件的主入口方法
|
|
12
|
+
# @param ipa_file_path [String] IPA 文件路径(可选,如果为 nil 则自动查找当前目录下的 IPA)
|
|
13
|
+
# @param bundle_id [String] 新的 Bundle ID
|
|
14
|
+
# @return [String, nil] 重签名后的 IPA 文件路径,失败返回 nil
|
|
15
|
+
def resign_ipa(ipa_file_path: nil, bundle_id:)
|
|
16
|
+
ipa_path = find_ipa_file(ipa_file_path)
|
|
17
|
+
|
|
18
|
+
if ipa_path.nil? || ipa_path.empty?
|
|
19
|
+
puts "未找到 IPA 文件"
|
|
20
|
+
return nil
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# 准备重签名的 IPA(修改 Bundle ID)
|
|
24
|
+
resigned_ipa_path = prepare_resign_ipa(ipa_name: ipa_path, bundle_id: bundle_id)
|
|
25
|
+
|
|
26
|
+
if resigned_ipa_path.nil?
|
|
27
|
+
puts "准备重签名 IPA 失败"
|
|
28
|
+
return nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# 使用新证书签名
|
|
32
|
+
sign_ipa_with_new_cert(ipa_name: resigned_ipa_path, bundle_id: bundle_id)
|
|
33
|
+
|
|
34
|
+
resigned_ipa_path
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
# 查找 IPA 文件
|
|
40
|
+
# @param ipa_file_path [String, nil] 指定的 IPA 文件路径
|
|
41
|
+
# @return [String, nil] IPA 文件的完整路径
|
|
42
|
+
def find_ipa_file(ipa_file_path)
|
|
43
|
+
if ipa_file_path
|
|
44
|
+
return File.expand_path(ipa_file_path)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# 自动查找当前目录下的 IPA 文件
|
|
48
|
+
current_dir = Dir.pwd
|
|
49
|
+
Dir.foreach(current_dir) do |file|
|
|
50
|
+
if file =~ /(.*).ipa/
|
|
51
|
+
return File.join(current_dir, file)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# 准备重签名的 IPA(修改 Bundle ID)
|
|
59
|
+
# @param ipa_name [String] 原始 IPA 文件路径
|
|
60
|
+
# @param bundle_id [String] 新的 Bundle ID
|
|
61
|
+
# @return [String, nil] 准备好的 IPA 文件路径
|
|
62
|
+
def prepare_resign_ipa(ipa_name:, bundle_id:)
|
|
63
|
+
ipa_base_name = File.basename(ipa_name, ".ipa")
|
|
64
|
+
ipa_dir = File.dirname(ipa_name)
|
|
65
|
+
|
|
66
|
+
resign_ipa_name = ipa_base_name + "_resigned.ipa"
|
|
67
|
+
resign_ipa_full_name = File.join(ipa_dir, resign_ipa_name)
|
|
68
|
+
FileUtils.cp_r(ipa_name, resign_ipa_full_name)
|
|
69
|
+
puts resign_ipa_full_name
|
|
70
|
+
|
|
71
|
+
tmp_time = "tmp_" + Time.now.strftime('%y%m%d_%H%M%S')
|
|
72
|
+
tmp_dir = File.join(ipa_dir, tmp_time)
|
|
73
|
+
FileUtils.mkdir(tmp_dir) unless File.exist?(tmp_dir)
|
|
74
|
+
|
|
75
|
+
# 解压 IPA
|
|
76
|
+
command = "unzip -q \"#{resign_ipa_full_name}\" -d #{tmp_dir}"
|
|
77
|
+
puts command
|
|
78
|
+
system command
|
|
79
|
+
|
|
80
|
+
payload_path = File.join(tmp_dir, "Payload")
|
|
81
|
+
if File.exist?(payload_path)
|
|
82
|
+
FileUtils.rm_rf(resign_ipa_full_name)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# 查找 .app 目录
|
|
86
|
+
modify_content_path = ""
|
|
87
|
+
Dir.foreach(payload_path) do |file|
|
|
88
|
+
if file =~ /(.*).app/
|
|
89
|
+
modify_content_path = File.join(payload_path, file)
|
|
90
|
+
break
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# 修改 Info.plist 中的 Bundle ID
|
|
95
|
+
modify_ipa_info_plist(modify_content_path: modify_content_path, bundle_id: bundle_id)
|
|
96
|
+
|
|
97
|
+
# 重新打包 IPA
|
|
98
|
+
current_dir = Dir.pwd
|
|
99
|
+
if File.exist?(payload_path)
|
|
100
|
+
Dir.chdir(tmp_dir)
|
|
101
|
+
command = "zip -qry \"#{resign_ipa_full_name}\" * "
|
|
102
|
+
puts command
|
|
103
|
+
system command
|
|
104
|
+
Dir.chdir(current_dir)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# 清理临时目录
|
|
108
|
+
FileUtils.rm_rf(tmp_dir) if File.exist?(resign_ipa_full_name)
|
|
109
|
+
|
|
110
|
+
resign_ipa_full_name
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# 修改 IPA 中的 Info.plist 文件
|
|
114
|
+
# @param modify_content_path [String] .app 目录路径
|
|
115
|
+
# @param bundle_id [String] 新的 Bundle ID
|
|
116
|
+
def modify_ipa_info_plist(modify_content_path:, bundle_id:)
|
|
117
|
+
main_info_plist = File.join(modify_content_path, "Info.plist")
|
|
118
|
+
puts main_info_plist
|
|
119
|
+
|
|
120
|
+
# 确保 PlistBuddy 可用
|
|
121
|
+
unless File.exist?("/usr/local/bin/PlistBuddy")
|
|
122
|
+
command = 'ln -s /usr/libexec/PlistBuddy /usr/local/bin/PlistBuddy'
|
|
123
|
+
system command
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# 读取旧的 Bundle ID
|
|
127
|
+
old_bundle_id_command = '/usr/local/bin/PlistBuddy -c "Print :CFBundleIdentifier" ' + main_info_plist
|
|
128
|
+
puts old_bundle_id_command
|
|
129
|
+
old_bundle_id = ""
|
|
130
|
+
IO.popen(old_bundle_id_command) { |f| old_bundle_id = f.gets }
|
|
131
|
+
puts old_bundle_id
|
|
132
|
+
|
|
133
|
+
# 修改主应用的 Bundle ID
|
|
134
|
+
exchange_bundleid_command = '/usr/local/bin/PlistBuddy -c "Set :CFBundleIdentifier ' + bundle_id + '" ' + main_info_plist
|
|
135
|
+
puts exchange_bundleid_command
|
|
136
|
+
system exchange_bundleid_command
|
|
137
|
+
|
|
138
|
+
# 修改插件扩展的 Bundle ID
|
|
139
|
+
plugin_path = File.join(modify_content_path, "PlugIns")
|
|
140
|
+
if File.exist?(plugin_path)
|
|
141
|
+
Dir.foreach(plugin_path) do |file|
|
|
142
|
+
next unless file =~ /(.*).appex/
|
|
143
|
+
|
|
144
|
+
appex_path = File.join(plugin_path, file)
|
|
145
|
+
tmp_info_plist = File.join(appex_path, "Info.plist")
|
|
146
|
+
|
|
147
|
+
old_bundle_id_command = '/usr/local/bin/PlistBuddy -c "Print :CFBundleIdentifier" ' + tmp_info_plist
|
|
148
|
+
puts old_bundle_id_command
|
|
149
|
+
old_plugin_bundle_id = ""
|
|
150
|
+
IO.popen(old_bundle_id_command) { |f| old_plugin_bundle_id = f.gets }
|
|
151
|
+
puts "old_bundle_id = #{old_plugin_bundle_id}"
|
|
152
|
+
|
|
153
|
+
# 根据插件类型修改 Bundle ID
|
|
154
|
+
update_plugin_bundle_id(tmp_info_plist, old_plugin_bundle_id, bundle_id)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# 更新插件的 Bundle ID
|
|
160
|
+
# @param plist_path [String] 插件的 Info.plist 路径
|
|
161
|
+
# @param old_bundle_id [String] 旧的 Bundle ID
|
|
162
|
+
# @param new_base_bundle_id [String] 新的基础 Bundle ID
|
|
163
|
+
def update_plugin_bundle_id(plist_path, old_bundle_id, new_base_bundle_id)
|
|
164
|
+
plugin_types = [
|
|
165
|
+
".content", ".service", ".imessage", ".keyboard",
|
|
166
|
+
".siri", ".widget", ".siriui", ".extension",
|
|
167
|
+
".extensionad", ".extensionporn"
|
|
168
|
+
]
|
|
169
|
+
|
|
170
|
+
plugin_types.each do |suffix|
|
|
171
|
+
if old_bundle_id.include?(suffix)
|
|
172
|
+
new_plugin_bundle_id = new_base_bundle_id + suffix
|
|
173
|
+
exchange_bundleid_command = '/usr/local/bin/PlistBuddy -c "Set :CFBundleIdentifier ' + new_plugin_bundle_id + '" ' + plist_path
|
|
174
|
+
puts exchange_bundleid_command
|
|
175
|
+
system exchange_bundleid_command
|
|
176
|
+
break
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# 使用新证书签名 IPA
|
|
182
|
+
# @param ipa_name [String] IPA 文件路径
|
|
183
|
+
# @param bundle_id [String] Bundle ID
|
|
184
|
+
def sign_ipa_with_new_cert(ipa_name:, bundle_id:)
|
|
185
|
+
require 'pindo/config/pindoconfig'
|
|
186
|
+
|
|
187
|
+
profil_info_array = Pindo::PindoSingleConfig.instance.get_cert_info
|
|
188
|
+
bundle_id_signing_identity = profil_info_array.first['signing_identity']
|
|
189
|
+
|
|
190
|
+
profile_dict = build_resign_profile_dict(profil_info_array: profil_info_array)
|
|
191
|
+
|
|
192
|
+
# 调用 Sigh::Resign 进行重签名
|
|
193
|
+
# resign(ipa, signing_identity, provisioning_profiles, entitlements, version, display_name, short_version, bundle_version, new_bundle_id, use_app_entitlements, keychain_path)
|
|
194
|
+
Sigh::Resign.resign(ipa_name, bundle_id_signing_identity, profile_dict, nil, nil, nil, nil, nil, bundle_id, true, nil)
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
# 构建重签名用的 profile 字典
|
|
198
|
+
# @param profil_info_array [Array<Hash>] 证书信息数组
|
|
199
|
+
# @return [Hash] Bundle ID 到 profile 路径的映射
|
|
200
|
+
def build_resign_profile_dict(profil_info_array:)
|
|
201
|
+
resign_dict = {}
|
|
202
|
+
profil_info_array.each do |profil_info|
|
|
203
|
+
resign_dict[profil_info["bundle_id"]] = profil_info["profile_path"]
|
|
204
|
+
end
|
|
205
|
+
resign_dict
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|