pindo 5.17.4 → 5.18.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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/lib/pindo/base/git_handler.rb +120 -38
  3. data/lib/pindo/command/android/autobuild.rb +92 -31
  4. data/lib/pindo/command/appstore/adhocbuild.rb +1 -1
  5. data/lib/pindo/command/appstore/autobuild.rb +1 -1
  6. data/lib/pindo/command/appstore/autoresign.rb +1 -1
  7. data/lib/pindo/command/appstore/updateid.rb +229 -0
  8. data/lib/pindo/command/appstore.rb +1 -0
  9. data/lib/pindo/command/ios/autobuild.rb +70 -33
  10. data/lib/pindo/command/ios/podpush.rb +1 -1
  11. data/lib/pindo/command/unity/autobuild.rb +38 -18
  12. data/lib/pindo/command/utils/allcopyconfig.rb +144 -0
  13. data/lib/pindo/command/utils/copyconfig.rb +207 -0
  14. data/lib/pindo/command/utils/icon.rb +2 -2
  15. data/lib/pindo/command/utils/renewbundleid.rb +199 -0
  16. data/lib/pindo/command/utils/renewcert.rb +56 -54
  17. data/lib/pindo/command/utils.rb +3 -0
  18. data/lib/pindo/command/web/autobuild.rb +10 -8
  19. data/lib/pindo/config/build_info_manager.rb +1 -3
  20. data/lib/pindo/module/android/android_build_helper.rb +198 -33
  21. data/lib/pindo/module/android/android_config_helper.rb +305 -88
  22. data/lib/pindo/module/android/android_project_helper.rb +124 -14
  23. data/lib/pindo/module/android/android_res_helper.rb +349 -51
  24. data/lib/pindo/module/android/keystore_helper.rb +611 -295
  25. data/lib/pindo/module/android/workflow_gradle_injector.rb +702 -0
  26. data/lib/pindo/module/appselect.rb +4 -4
  27. data/lib/pindo/module/appstore/bundleid_helper.rb +204 -14
  28. data/lib/pindo/module/build/build_helper.rb +76 -10
  29. data/lib/pindo/module/build/git_repo_helper.rb +4 -4
  30. data/lib/pindo/module/cert/mode/base_cert_operator.rb +12 -6
  31. data/lib/pindo/module/pgyer/pgyerhelper.rb +124 -39
  32. data/lib/pindo/module/task/model/build/android_build_dev_task.rb +64 -6
  33. data/lib/pindo/module/task/model/git/git_commit_task.rb +70 -54
  34. data/lib/pindo/module/task/model/git/git_tag_task.rb +13 -9
  35. data/lib/pindo/module/task/model/jps/jps_upload_task.rb +110 -3
  36. data/lib/pindo/module/task/model/unity/unity_export_task.rb +2 -1
  37. data/lib/pindo/module/task/model/unity/unity_update_task.rb +2 -1
  38. data/lib/pindo/module/task/model/unity/unity_yoo_asset_task.rb +2 -1
  39. data/lib/pindo/module/task/model/unity_task.rb +2 -1
  40. data/lib/pindo/module/unity/unity_helper.rb +13 -10
  41. data/lib/pindo/module/unity/unity_proc_helper.rb +27 -2
  42. data/lib/pindo/module/xcode/applovin_xcode_helper.rb +6 -2
  43. data/lib/pindo/module/xcode/res/xcode_res_constant.rb +72 -0
  44. data/lib/pindo/module/xcode/res/xcode_res_handler.rb +3 -3
  45. data/lib/pindo/module/xcode/xcode_build_config.rb +46 -17
  46. data/lib/pindo/module/xcode/xcode_build_helper.rb +186 -25
  47. data/lib/pindo/module/xcode/xcode_project_helper.rb +1 -1
  48. data/lib/pindo/module/xcode/xcode_res_helper.rb +32 -16
  49. data/lib/pindo/options/groups/build_options.rb +5 -5
  50. data/lib/pindo/options/groups/git_options.rb +7 -5
  51. data/lib/pindo/options/groups/unity_options.rb +11 -0
  52. data/lib/pindo/options/helpers/bundleid_selector.rb +25 -0
  53. data/lib/pindo/options/helpers/git_constants.rb +7 -6
  54. data/lib/pindo/version.rb +3 -3
  55. metadata +12 -7
@@ -166,8 +166,8 @@ module Pindo
166
166
  puts
167
167
  puts "选择的bundle id是: #{menu_choice}"
168
168
  puts
169
- if menu_choice.eql?("com.heroneverdie101.*")
170
- menu_choice = "com.heroneverdie101"
169
+ if menu_choice.include?("*")
170
+ menu_choice = menu_choice.gsub(".*", "")
171
171
  end
172
172
 
173
173
  # 保存选择到 GlobalOptionsState
@@ -239,7 +239,7 @@ module Pindo
239
239
  puts "选择的Bundle Name是: #{menu_choice}"
240
240
  puts
241
241
 
242
- # 去除通配符后缀(如 com.test.* -> com.test
242
+ # 去除通配符后缀(如 com.heroneverdie101.* -> com.heroneverdie101
243
243
  if menu_choice.end_with?(".*")
244
244
  menu_choice = menu_choice.sub(/\.\*$/, '')
245
245
  puts "去除通配符后的Bundle Name: #{menu_choice}"
@@ -277,7 +277,7 @@ module Pindo
277
277
  puts "选择的Bundle Name是: #{menu_choice}"
278
278
  puts
279
279
 
280
- # 去除通配符后缀(如 com.test.* -> com.test
280
+ # 去除通配符后缀(如 com.heroneverdie101.* -> com.heroneverdie101
281
281
  if menu_choice.end_with?(".*")
282
282
  menu_choice = menu_choice.sub(/\.\*$/, '')
283
283
  puts "去除通配符后的Bundle Name: #{menu_choice}"
@@ -1,11 +1,69 @@
1
1
  require 'spaceship'
2
2
  require 'json'
3
+ require 'app_store_dev_api'
3
4
 
4
5
  module Pindo
5
6
  # Bundle ID 管理辅助类
6
7
  # 负责在 Apple 开发者中心创建和配置 Bundle ID
7
8
  class BundleIdHelper
8
9
 
10
+ # 根据 Bundle ID 生成显示名称
11
+ # 规则:去掉前两段(如 com.heroneverdie101),剩余部分去掉点号拼接
12
+ # @param bundle_id [String] Bundle ID 字符串
13
+ # @return [String] 显示名称
14
+ #
15
+ # 示例:
16
+ # "com.heroneverdie101.fancyapptest" => "fancyapptest"
17
+ # "com.heroneverdie101.fancyapptest.content" => "fancyapptestcontent"
18
+ # "com.heroneverdie101.fancyapptest.service" => "fancyapptestservice"
19
+ # "com.heroneverdie101.*" => "wildcarddevelopmentid"
20
+ def self.generate_bundleid_name(bundle_id)
21
+ return "wildcarddevelopmentid" if bundle_id.nil? || bundle_id.include?("*")
22
+
23
+ parts = bundle_id.split('.')
24
+ # 去掉前两段(如 com.heroneverdie101),剩余部分拼接
25
+ parts[2..].join('')
26
+ end
27
+
28
+ # 通过 App Store Connect API 更新 Bundle ID 名称
29
+ # @param bundle_id [String] Bundle ID 字符串
30
+ # @param new_name [String] 新名称
31
+ def self.update_bundleid_name(bundle_id:, new_name:)
32
+ bundle_id_obj = Spaceship::ConnectAPI::BundleId.find(bundle_id)
33
+ return if bundle_id_obj.nil?
34
+
35
+ api_key_json = load_api_key_config
36
+ if api_key_json.nil?
37
+ puts "未配置 API Key,跳过名称更新"
38
+ return
39
+ end
40
+
41
+ client = AppStoreDevApi::Client.new(
42
+ issuer_id: api_key_json["issuer_id"],
43
+ key_id: api_key_json["key_id"],
44
+ private_key: api_key_json["private_key"]
45
+ )
46
+
47
+ client.update_bundle_id(id: bundle_id_obj.id, name: new_name)
48
+ end
49
+
50
+ # 加载 API Key 配置
51
+ # @return [Hash, nil] API Key 配置,包含 issuer_id、key_id、private_key
52
+ def self.load_api_key_config
53
+ pindo_dir = File.expand_path("~/.pindo")
54
+ api_key_file = File.join(pindo_dir, "api_key.json")
55
+ return nil unless File.exist?(api_key_file)
56
+
57
+ api_key_json = JSON.parse(File.read(api_key_file))
58
+ # 取第一个有效的 API Key 配置
59
+ api_key_json.each do |_apple_id, config|
60
+ if config.is_a?(Hash) && config["issuer_id"] && config["key_id"] && config["private_key"]
61
+ return config
62
+ end
63
+ end
64
+ nil
65
+ end
66
+
9
67
  # 从配置文件中提取所有必要的信息
10
68
  # @param config_json [Hash] 配置 JSON 对象
11
69
  # @return [Hash] 提取的配置信息
@@ -106,17 +164,33 @@ module Pindo
106
164
  app = Spaceship::Portal.app.find(bundle_id)
107
165
  puts
108
166
 
167
+ display_name = generate_bundleid_name(bundle_id)
109
168
  if app.nil?
110
- puts "Create bundle id #{bundle_id} in apple developer center..."
111
- app = Spaceship::Portal.app.create!(bundle_id: bundle_id, name: bundle_id.gsub('.', ''))
169
+ puts "Create bundle id #{bundle_id} (#{display_name}) in apple developer center..."
170
+ app = Spaceship::Portal.app.create!(bundle_id: bundle_id, name: display_name)
112
171
  else
113
172
  puts "Find bundle id #{bundle_id} in apple developer center..."
173
+ # 更新名称
174
+ if app.name != display_name
175
+ puts "Update bundle id name: #{app.name} -> #{display_name}"
176
+ begin
177
+ app.update_name!(display_name)
178
+ rescue => e
179
+ puts "Portal 更新名称失败: #{e.message},尝试通过 API Key 更新..."
180
+ begin
181
+ update_bundleid_name(bundle_id: bundle_id, new_name: display_name)
182
+ rescue => e2
183
+ puts "更新名称失败: #{e2.message}"
184
+ end
185
+ end
186
+ end
114
187
  end
115
188
 
116
189
  bundle_id_obj = Spaceship::ConnectAPI::BundleId.find(bundle_id)
117
190
 
118
- # 配置 Game Center
119
- if !bundle_id_obj.nil?
191
+ # 配置 Game Center(通配符 App ID 不支持 GAME_CENTER)
192
+ is_wildcard = bundle_id.include?("*")
193
+ if !bundle_id_obj.nil? && !is_wildcard
120
194
  if !setting_array.nil? && setting_array.to_s.include?("game_center")
121
195
  puts "Enable #{bundle_id} game_center on"
122
196
  bundle_id_obj.update_capability("GAME_CENTER", enabled: true)
@@ -124,6 +198,8 @@ module Pindo
124
198
  puts "Enable #{bundle_id} game_center off"
125
199
  bundle_id_obj.update_capability("GAME_CENTER", enabled: false)
126
200
  end
201
+ elsif is_wildcard
202
+ puts "Skip #{bundle_id} game_center (wildcard App ID not supported)"
127
203
  end
128
204
 
129
205
  return nil if setting_array.nil? || setting_array.length == 0
@@ -146,14 +222,18 @@ module Pindo
146
222
  puts "Enable #{bundle_id} siri off"
147
223
  end
148
224
 
149
- # 配置 Sign with Apple
150
- if !bundle_id_obj.nil? && setting_array.to_s.include?("apple_signin")
151
- puts "Enable #{bundle_id} Sign with Apple on"
152
- settings = build_settings_for(settings_key: "APPLE_ID_AUTH_APP_CONSENT", options_key: "PRIMARY_APP_CONSENT")
153
- bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: true, settings: settings)
154
- else
155
- puts "Enable #{bundle_id} Sign with Apple off"
156
- bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: false)
225
+ # 配置 Sign with Apple(通配符 App ID 不支持)
226
+ if !is_wildcard && !bundle_id_obj.nil?
227
+ if setting_array.to_s.include?("apple_signin")
228
+ puts "Enable #{bundle_id} Sign with Apple on"
229
+ settings = build_settings_for(settings_key: "APPLE_ID_AUTH_APP_CONSENT", options_key: "PRIMARY_APP_CONSENT")
230
+ bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: true, settings: settings)
231
+ else
232
+ puts "Enable #{bundle_id} Sign with Apple off"
233
+ bundle_id_obj.update_capability("APPLE_ID_AUTH", enabled: false)
234
+ end
235
+ elsif is_wildcard
236
+ puts "Skip #{bundle_id} Sign with Apple (wildcard App ID not supported)"
157
237
  end
158
238
 
159
239
  # 配置 App Group
@@ -190,7 +270,7 @@ module Pindo
190
270
 
191
271
  if app_group.nil?
192
272
  puts "Create group_id #{group_id} in apple developer center..."
193
- app_group = Spaceship::Portal.app_group.create!(group_id: group_id, name: group_id.gsub('.', ''))
273
+ app_group = Spaceship::Portal.app_group.create!(group_id: group_id, name: generate_bundleid_name(group_id))
194
274
  else
195
275
  puts "Group_id #{group_id} is existed in apple developer center !!!"
196
276
  end
@@ -209,7 +289,7 @@ module Pindo
209
289
 
210
290
  if app_icloud.nil?
211
291
  puts "Create icloud_id #{icloud_id} in apple developer center..."
212
- app_icloud = Spaceship::Portal.cloud_container.create!(identifier: icloud_id, name: icloud_id.gsub('.', ''))
292
+ app_icloud = Spaceship::Portal.cloud_container.create!(identifier: icloud_id, name: generate_bundleid_name(icloud_id))
213
293
  else
214
294
  puts "icloud_id #{icloud_id} is existed in apple developer center !!!"
215
295
  end
@@ -349,5 +429,115 @@ module Pindo
349
429
  end
350
430
  end
351
431
 
432
+ # 从 Apple Developer Portal 读取指定 Bundle ID 的 Capability 状态
433
+ # @param bundle_id [String] Bundle ID 字符串
434
+ # @return [Hash, nil] capabilities 对象,Bundle ID 不存在时返回 nil
435
+ def self.fetch_capabilities_from_portal(bundle_id:)
436
+ return nil if bundle_id.nil? || bundle_id.empty?
437
+
438
+ # 通过 Spaceship Portal 查找 Bundle ID
439
+ app = Spaceship::Portal.app.find(bundle_id)
440
+ if app.nil?
441
+ puts "Bundle ID #{bundle_id} 在 Apple Developer Portal 中未找到"
442
+ return nil
443
+ end
444
+
445
+ # 更新 Bundle ID 名称
446
+ expected_name = generate_bundleid_name(bundle_id)
447
+ if app.name != expected_name
448
+ puts "Update bundle id name: #{app.name} -> #{expected_name}"
449
+ begin
450
+ app.update_name!(expected_name)
451
+ rescue => e
452
+ puts "Portal 更新名称失败: #{e.message},尝试通过 API Key 更新..."
453
+ begin
454
+ update_bundleid_name(bundle_id: bundle_id, new_name: expected_name)
455
+ rescue => e2
456
+ puts "更新名称失败: #{e2.message}"
457
+ end
458
+ end
459
+ end
460
+
461
+ capabilities = {}
462
+
463
+ # --- Spaceship Portal 侧:读取 features/services ---
464
+ begin
465
+ app_details = app.details
466
+ features = app_details.features
467
+
468
+ # Push Notification
469
+ push_enabled = features["push"] == true || features["push"].to_s == "true"
470
+ capabilities["push_notification"] = push_enabled
471
+
472
+ # App Group
473
+ app_group_enabled = features["APG3427HIY"] == true || features["appGroup"] == true ||
474
+ features["APG3427HIY"].to_s == "true" || features["appGroup"].to_s == "true"
475
+ if app_group_enabled
476
+ groups = app_details.associated_groups rescue []
477
+ if groups && !groups.empty?
478
+ capabilities["app_group"] = groups.first.group_id
479
+ else
480
+ capabilities["app_group"] = true
481
+ end
482
+ else
483
+ capabilities["app_group"] = false
484
+ end
485
+
486
+ # iCloud
487
+ icloud_enabled = features["cloudKitVersion"] == 2 || features["iCloud"] == true ||
488
+ features["cloudKitVersion"].to_i > 0 || features["iCloud"].to_s == "true"
489
+ if icloud_enabled
490
+ containers = app_details.associated_cloud_containers rescue []
491
+ if containers && !containers.empty?
492
+ capabilities["icloud"] = containers.first.identifier
493
+ else
494
+ capabilities["icloud"] = true
495
+ end
496
+ else
497
+ capabilities["icloud"] = false
498
+ end
499
+
500
+ # Siri
501
+ siri_enabled = features["SI015DKUHP"] == true || features["siriKit"] == true ||
502
+ features["SI015DKUHP"].to_s == "true" || features["siriKit"].to_s == "true"
503
+ capabilities["siri"] = siri_enabled
504
+
505
+ # In-App Purchase
506
+ iap_enabled = features["inAppPurchase"] == true || features["inAppPurchase"].to_s == "true"
507
+ capabilities["in_app_purchase"] = iap_enabled
508
+
509
+ rescue => e
510
+ puts "读取 Portal features 失败: #{e.message},尝试通过 ConnectAPI 读取..."
511
+ end
512
+
513
+ # --- ConnectAPI 侧:补充 game_center 和 apple_signin ---
514
+ begin
515
+ bundle_id_obj = Spaceship::ConnectAPI::BundleId.find(bundle_id)
516
+ if bundle_id_obj
517
+ api_capabilities = bundle_id_obj.get_capabilities
518
+
519
+ capabilities["game_center"] = api_capabilities.any? { |c| c.is_type?("GAME_CENTER") } rescue false
520
+ capabilities["apple_signin"] = api_capabilities.any? { |c| c.is_type?("APPLE_ID_AUTH") } rescue false
521
+
522
+ # 如果 Portal 侧读取失败,用 ConnectAPI 补充
523
+ if !capabilities.key?("push_notification")
524
+ capabilities["push_notification"] = api_capabilities.any? { |c| c.is_type?("PUSH_NOTIFICATIONS") } rescue false
525
+ end
526
+ if !capabilities.key?("in_app_purchase")
527
+ capabilities["in_app_purchase"] = api_capabilities.any? { |c| c.is_type?("IN_APP_PURCHASE") } rescue false
528
+ end
529
+ if !capabilities.key?("siri")
530
+ capabilities["siri"] = api_capabilities.any? { |c| c.is_type?("SIRIKIT") } rescue false
531
+ end
532
+ end
533
+ rescue => e
534
+ puts "读取 ConnectAPI capabilities 失败: #{e.message}"
535
+ capabilities["game_center"] ||= false
536
+ capabilities["apple_signin"] ||= false
537
+ end
538
+
539
+ capabilities
540
+ end
541
+
352
542
  end
353
543
  end
@@ -191,28 +191,94 @@ module Pindo
191
191
  )
192
192
  end
193
193
 
194
- # 加载 JPSBuildConfig.json 并设置项目名称到 GlobalOptionsState
194
+ # 定位 JPSBuildConfig.json 文件路径
195
+ # 先找 git root,再判断是否 Unity 项目来确定配置文件位置
196
+ # @param working_dir [String] 当前工作目录
197
+ # @return [String] 配置文件绝对路径
198
+ def determine_jps_config_path(working_dir)
199
+ # 获取 Git 仓库根目录
200
+ repo_root_dir = nil
201
+ if Pindo::GitHandler.is_git_directory?(local_repo_dir: working_dir)
202
+ repo_root_dir = Pindo::GitHandler.git_root_directory(local_repo_dir: working_dir)
203
+ end
204
+ repo_root_dir ||= working_dir
205
+
206
+ # 判断工程类型
207
+ if File.directory?(File.join(repo_root_dir, 'ProjectSettings'))
208
+ File.join(repo_root_dir, 'ProjectSettings', 'JPSBuildConfig.json')
209
+ else
210
+ File.join(repo_root_dir, 'JPSBuildConfig.json')
211
+ end
212
+ end
213
+
214
+ # 加载 JPSBuildConfig.json,设置全局状态,缺失字段时通过 JPS 请求补全
195
215
  # @param project_dir [String] 项目目录
196
- # @return [String, nil] 项目名称(如果存在)
197
- def load_jps_build_config(project_dir)
198
- # 检测工程类型:Unity 工程配置在 ProjectSettings 目录
199
- config_file = if unity_project?(project_dir)
200
- File.join(project_dir, 'ProjectSettings', 'JPSBuildConfig.json')
216
+ # @param conf [String, nil] 显式指定的配置文件路径(优先于自动查找)
217
+ # @return [Hash, nil] JPSBuildConfig 的完整配置,文件不存在时返回 nil
218
+ def load_jps_build_config(project_dir, conf = nil, **_)
219
+ config_file = if conf && !conf.to_s.empty?
220
+ File.expand_path(conf)
201
221
  else
202
- File.join(project_dir, 'JPSBuildConfig.json')
222
+ determine_jps_config_path(project_dir)
203
223
  end
204
224
 
205
225
  return nil unless File.exist?(config_file)
206
226
 
207
227
  begin
208
228
  config = JSON.parse(File.read(config_file))
229
+ state = Pindo::Options::GlobalOptionsState.instance
230
+
209
231
  project_name = config['project_name']
210
232
  if project_name && !project_name.empty?
211
- # 设置到 GlobalOptionsState
212
- Pindo::Options::GlobalOptionsState.instance[:proj] = project_name
233
+ state[:proj] = project_name
213
234
  puts "使用 JPS 配置的项目名称: #{project_name}"
214
- return project_name
215
235
  end
236
+
237
+ # 检查 wildcard_bundle_group_name 和 bundle_group_name(兼容旧字段名)
238
+ wildcard_bundle_group_name = config['wildcard_bundle_group_name'] || config['wildcardBundleId']
239
+ bundle_group_name = config['bundle_group_name'] || config['bundleId']
240
+
241
+ # 如果缺失,通过 JPS 请求获取并回写
242
+ if (wildcard_bundle_group_name.nil? || wildcard_bundle_group_name.empty?) ||
243
+ (bundle_group_name.nil? || bundle_group_name.empty?)
244
+ project_id = config['project_id']
245
+ app_info_data = nil
246
+
247
+ if project_id && !project_id.to_s.empty?
248
+ app_info_data = PgyerHelper.share_instace.get_project_detail(project_id: project_id)
249
+ elsif project_name && !project_name.empty?
250
+ app_info_data = PgyerHelper.share_instace.find_app_info_with_obj_list(proj_name: project_name)
251
+ end
252
+
253
+ if app_info_data
254
+ wildcard_bundle_group_name = app_info_data["wildcardBundleId"]
255
+ bundle_group_name = app_info_data["bundleId"]
256
+
257
+ if wildcard_bundle_group_name && !wildcard_bundle_group_name.empty?
258
+ config['wildcard_bundle_group_name'] = wildcard_bundle_group_name
259
+ config['bundle_group_name'] = bundle_group_name
260
+ File.write(config_file, JSON.pretty_generate(config) + "\n")
261
+ puts "已从 JPS 获取并保存: wildcard_bundle_group_name=#{wildcard_bundle_group_name}, bundle_group_name=#{bundle_group_name}"
262
+ end
263
+ end
264
+ end
265
+
266
+ # 设置全局状态
267
+ if wildcard_bundle_group_name && !wildcard_bundle_group_name.empty?
268
+ state[:wildcard_bundle_group_name] = wildcard_bundle_group_name
269
+ state[:bundle_group_name] = bundle_group_name
270
+
271
+ # 通过映射表将 wildcard_bundle_group_name 解析为真实 bundle_id
272
+ require 'pindo/options/helpers/bundleid_selector'
273
+ resolved_bundle_id = Pindo::Options::BundleIdSelector.resolve_bundleid_by_group_name(wildcard_bundle_group_name)
274
+ if resolved_bundle_id && !resolved_bundle_id.empty?
275
+ state[:bundleid] = resolved_bundle_id # iOS 使用
276
+ state[:bundle_name] = resolved_bundle_id # Android 使用
277
+ puts "使用 JPSBuildConfig 的 Bundle Name: #{resolved_bundle_id} (#{wildcard_bundle_group_name})"
278
+ end
279
+ end
280
+
281
+ return config
216
282
  rescue => e
217
283
  puts "加载 JPSBuildConfig.json 失败: #{e.message}" if ENV['PINDO_VERBOSE'] == '1'
218
284
  end
@@ -347,7 +347,7 @@ module Pindo
347
347
  # 删除旧 tag(本地和远程)
348
348
  if Pindo::GitHandler.remote_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)
349
349
  Funlog.instance.fancyinfo_update("删除远程 Tag: #{tag_name}")
350
- Pindo::GitHandler.git!(%W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
350
+ Pindo::GitHandler.git_remote!(project_dir, %W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
351
351
  end
352
352
  if Pindo::GitHandler.local_tag_exists?(local_repo_dir: project_dir, tag_name: tag_name)
353
353
  Funlog.instance.fancyinfo_update("删除本地 Tag: #{tag_name}")
@@ -361,7 +361,7 @@ module Pindo
361
361
  if local_exists && Pindo::GitHandler.is_tag_at_head?(git_root_dir: project_dir, tag_name: tag_name)
362
362
  if !remote_exists
363
363
  # 本地存在且在 HEAD,但远程不存在,推送到远程
364
- Pindo::GitHandler.git!(%W(-C #{project_dir} push origin #{tag_name}))
364
+ Pindo::GitHandler.git_remote!(project_dir, %W(-C #{project_dir} push origin #{tag_name}))
365
365
  Funlog.instance.fancyinfo_success("推送 Tag 到远程: #{tag_name}")
366
366
  else
367
367
  Funlog.instance.fancyinfo_success("Tag 已存在且在 HEAD: #{tag_name}")
@@ -372,7 +372,7 @@ module Pindo
372
372
  # tag 不在 HEAD 上,需要删除后重新创建
373
373
  if remote_exists
374
374
  Funlog.instance.fancyinfo_update("删除远程 Tag: #{tag_name}")
375
- Pindo::GitHandler.git!(%W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
375
+ Pindo::GitHandler.git_remote!(project_dir, %W(-C #{project_dir} push origin :refs/tags/#{tag_name}))
376
376
  end
377
377
  if local_exists
378
378
  Funlog.instance.fancyinfo_update("删除本地 Tag: #{tag_name}")
@@ -383,7 +383,7 @@ module Pindo
383
383
 
384
384
  # 创建并推送 tag
385
385
  Pindo::GitHandler.git!(%W(-C #{project_dir} tag #{tag_name}))
386
- Pindo::GitHandler.git!(%W(-C #{project_dir} push origin #{tag_name}))
386
+ Pindo::GitHandler.git_remote!(project_dir, %W(-C #{project_dir} push origin #{tag_name}))
387
387
  Funlog.instance.fancyinfo_success("创建并推送 Tag: #{tag_name}")
388
388
  tag_name
389
389
  end
@@ -1,3 +1,5 @@
1
+ require 'pindo/module/xcode/xcode_build_helper'
2
+
1
3
  module Pindo
2
4
  module CertProcess
3
5
 
@@ -234,6 +236,8 @@ module Pindo
234
236
  project = Xcodeproj::Project.open(proj_fullname)
235
237
 
236
238
  project.targets.each do |target|
239
+ # 跳过非 native target(如 PBXAggregateTarget)
240
+ next unless target.respond_to?(:product_type)
237
241
  # 跳过 framework、library 等类型
238
242
  if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:framework]) ||
239
243
  target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:dynamic_library]) ||
@@ -286,6 +290,8 @@ module Pindo
286
290
  target_map = get_target_name_map
287
291
 
288
292
  project.targets.each do |target|
293
+ # 跳过非 native target(如 PBXAggregateTarget)
294
+ next unless target.respond_to?(:product_type)
289
295
  # 跳过 framework、library 等类型
290
296
  if target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:framework]) ||
291
297
  target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:dynamic_library]) ||
@@ -346,7 +352,7 @@ module Pindo
346
352
  end
347
353
 
348
354
  # 设置 Bundle ID(跳过通配符)
349
- unless provisioning_info["bundle_id"].eql?("com.heroneverdie101.*")
355
+ unless provisioning_info["bundle_id"].include?("*")
350
356
  config.build_settings['PRODUCT_BUNDLE_IDENTIFIER'] = provisioning_info["bundle_id"]
351
357
  end
352
358
  end
@@ -401,13 +407,13 @@ module Pindo
401
407
 
402
408
  # 配置 Info.plist 文件
403
409
  def configure_info_plist_file(target, project_dir, icloud_id)
404
- info_plist_file = target.build_configurations.first.build_settings['INFOPLIST_FILE']
405
- return if info_plist_file.nil? || info_plist_file.empty?
410
+ raw_path = target.build_configurations.first.build_settings['INFOPLIST_FILE']
411
+ return if raw_path.nil? || raw_path.empty?
406
412
 
407
- info_plist_path = File.join(project_dir, info_plist_file)
413
+ info_plist_path = Pindo::XcodeBuildHelper.resolve_info_plist_path(project_dir, raw_path, target: target)
408
414
 
409
- unless File.exist?(info_plist_path)
410
- raise Informative, "Missing Target #{target.name} Info.plist!!! #{info_plist_path}"
415
+ unless info_plist_path
416
+ raise Informative, "Missing Target #{target.name} Info.plist!!! #{raw_path}"
411
417
  end
412
418
 
413
419
  # 标准化 CFBundleIdentifier 为宏变量