pindo 5.13.4 → 5.13.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b8f4e3397e7d22aee8dd0011d92a8eec9c7cfb8b51b3676a78e518b27c71b25
4
- data.tar.gz: e8eca26bbd129b1f561d09462f5dde5bedf5059172c711ec01da98427a19f446
3
+ metadata.gz: 6afa5bb728d863ac22047d3a4861d3fd093bf103f25e51495bfd4f74d42c5b08
4
+ data.tar.gz: '05999b51d89aea0c1c09407469bcf4d3e61a971303393a239e3fced117946f0b'
5
5
  SHA512:
6
- metadata.gz: 2b6e7699071cd70dff2f482105dd93dd3168a962a59b7b477ad4a359f191c0021612ae993d00a024dcf7f38dcd6875a39ef4670131a3c8948038d81d38dbc56c
7
- data.tar.gz: 20fa09db784a2894e3bc9119f9917a4431031e68fc365b3e77dff1e650b599bfcac8fc5b4914f2e3e87add02ffeec4319c815855fe9e0f77aa1da10288513e87
6
+ metadata.gz: da020921268583412cd1194b9b89234c0ca26db407632d867e8897ddfc2404bdef72f90023954df26f8a3c406f0c4ebf0232983d878b18bd505c41079fbab72a
7
+ data.tar.gz: 83bf6fed728974d527c96e13892e6f64489f92a7742583a4bfbb6905f01f0cafc9e1f58969c21853d3f5cd5083a66f1e8100fc23d3d74c3acf9eb8e0a9343885
@@ -20,23 +20,25 @@ module Pindo
20
20
  unless password
21
21
  puts "\e[33m[DEBUG] Keychain中未找到密码,需要用户输入: #{server_name}\e[0m" if ENV['PINDO_DEBUG']
22
22
  password = FastlaneCore::Helper.ask_password(message: "请输入证书仓库的加密密码: ", confirm: true)
23
- # 尝试添加密码到Keychain,如果已存在则先删除再添加
23
+
24
+ # 尝试添加密码到Keychain
24
25
  begin
25
- # 先检查是否已存在,如果存在则删除
26
- existing_item = Security::InternetPassword.find(server: server_name)
27
- if existing_item
28
- # 重定向stderr到/dev/null来隐藏Keychain的详细输出
29
- system("security delete-internet-password -s '#{server_name}' 2>/dev/null")
26
+ # 先尝试删除旧密码(如果存在)
27
+ begin
28
+ Security::InternetPassword.delete(server: server_name)
30
29
  puts "\e[33m[DEBUG] 删除Keychain中的旧密码项: #{server_name}\e[0m" if ENV['PINDO_DEBUG']
30
+ rescue => delete_error
31
+ # 如果不存在就忽略删除错误
32
+ puts "\e[33m[DEBUG] 旧密码项不存在或删除失败: #{delete_error.message}\e[0m" if ENV['PINDO_DEBUG']
31
33
  end
32
-
33
- # 添加新密码,重定向stderr到/dev/null来隐藏Keychain的详细输出
34
- system("security add-internet-password -s '#{server_name}' -w '#{password}' 2>/dev/null")
35
- puts "\e[32m[DEBUG] 密码已保存到Keychain: #{server_name}\e[0m" if ENV['PINDO_DEBUG']
34
+
35
+ # 添加新密码到Keychain
36
+ Security::InternetPassword.add(server_name, "", password)
37
+ puts "\e[32m 密码已保存到Keychain: #{server_name}\e[0m"
36
38
  rescue => e
37
- # 忽略Keychain错误,继续使用密码
38
- # 错误信息可能包含 "already exists" 等,但不影响功能
39
- puts "\e[31m[DEBUG] Keychain操作错误: #{e.message}\e[0m" if ENV['PINDO_DEBUG']
39
+ # 如果保存失败,警告用户但不影响继续使用
40
+ puts "\e[31m⚠ 密码保存到Keychain失败: #{e.message}\e[0m"
41
+ puts "\e[31m 下次使用时需要重新输入密码\e[0m"
40
42
  end
41
43
  else
42
44
  puts "\e[32m[DEBUG] 从Keychain获取密码成功: #{server_name}\e[0m" if ENV['PINDO_DEBUG']
@@ -287,6 +287,9 @@ module Pindo
287
287
  if File.exist?(config_file)
288
288
  puts " ✓ 加载配置文件: #{config_file}"
289
289
  Pindo::IosConfigParser.instance.load_config(config_file: config_file)
290
+
291
+ # 解析完成后删除 config.json,避免影响 git 仓库状态
292
+ FileUtils.rm_f(config_file)
290
293
  else
291
294
  raise Informative, "配置文件不存在: #{config_file}"
292
295
  end
@@ -297,6 +300,9 @@ module Pindo
297
300
  if File.exist?(config_file)
298
301
  puts "\n使用当前目录配置文件: #{config_file}"
299
302
  Pindo::IosConfigParser.instance.load_config(config_file: config_file)
303
+
304
+ # 解析完成后删除 config.json,避免影响 git 仓库状态
305
+ FileUtils.rm_f(config_file)
300
306
  else
301
307
  raise Informative, "当前目录未找到 config.json 文件,请使用 --bundleid 参数指定 Bundle ID"
302
308
  end
@@ -449,6 +449,9 @@ module Pindo
449
449
  if File.exist?(config_file)
450
450
  puts " ✓ 加载配置文件: #{config_file}"
451
451
  Pindo::IosConfigParser.instance.load_config(config_file: config_file)
452
+
453
+ # 解析完成后删除 config.json,避免影响 git 仓库状态
454
+ FileUtils.rm_f(config_file)
452
455
  else
453
456
  raise Informative, "配置文件不存在: #{config_file}"
454
457
  end
@@ -459,6 +462,9 @@ module Pindo
459
462
  if File.exist?(config_file)
460
463
  puts "\n使用当前目录配置文件: #{config_file}"
461
464
  Pindo::IosConfigParser.instance.load_config(config_file: config_file)
465
+
466
+ # 解析完成后删除 config.json,避免影响 git 仓库状态
467
+ FileUtils.rm_f(config_file)
462
468
  else
463
469
  raise Informative, "当前目录未找到 config.json 文件,请使用 --bundleid 参数指定 Bundle ID"
464
470
  end
@@ -1,6 +1,7 @@
1
1
  require 'singleton'
2
2
  require 'fileutils'
3
3
  require 'pindo/base/githelper'
4
+ require 'pindo/config/pindoconfig'
4
5
 
5
6
  module Pindo
6
7
 
@@ -9,6 +10,7 @@ module Pindo
9
10
  class BuildInfoManager
10
11
  include Singleton
11
12
  include Pindo::Githelper
13
+ include Pindo::Pindoconfig::Mixin
12
14
 
13
15
  class << self
14
16
  def share_instance
@@ -120,6 +122,36 @@ module Pindo
120
122
  end
121
123
  end
122
124
 
125
+ # 根据模块名称获取部署仓库名称
126
+ # @param module_name [String] 模块名称(来自 config.json 的 app_type)
127
+ # @return [String, nil] 返回对应的 git_repo_name,失败返回 nil
128
+ def get_deploy_repo_with_modul_name(module_name:)
129
+ return nil if module_name.nil? || module_name.empty?
130
+
131
+ # 读取 deploy_build_setting.json
132
+ setting_file = File.join(pindo_single_config.pindo_env_configdir, 'deploy_build_setting.json')
133
+ unless File.exist?(setting_file)
134
+ puts "⚠ deploy_build_setting.json 不存在: #{setting_file}"
135
+ return nil
136
+ end
137
+
138
+ begin
139
+ setting_json = JSON.parse(File.read(setting_file))
140
+ repo_name = setting_json.dig(module_name, 'git_repo_name')
141
+
142
+ if repo_name.nil? || repo_name.empty?
143
+ raise Informative, "config.json app_type is error!!!"
144
+ end
145
+
146
+ return repo_name
147
+ rescue JSON::ParserError => e
148
+ puts "⚠ 解析 deploy_build_setting.json 失败: #{e.message}"
149
+ return nil
150
+ rescue => e
151
+ raise Informative, "config.json app_type is error!!!"
152
+ end
153
+ end
154
+
123
155
  private
124
156
 
125
157
  # 修改仓库设置(测试环境)
@@ -21,13 +21,14 @@ module Pindo
21
21
  class IosConfigParser
22
22
  include Singleton
23
23
 
24
- attr_reader :config_file_path, :config_json
24
+ attr_reader :config_file_path, :config_json, :app_repo_name
25
25
 
26
26
  def initialize
27
27
  @config_file_path = nil
28
28
  @config_json = nil
29
29
  @config_data = {}
30
30
  @overrides = {}
31
+ @app_repo_name = nil # 保存原始 Bundle ID,用于配置仓库路径
31
32
  end
32
33
 
33
34
  # 加载配置文件
@@ -67,6 +68,7 @@ module Pindo
67
68
  @config_json = nil
68
69
  @config_data = {}
69
70
  @overrides = {}
71
+ @app_repo_name = nil
70
72
  end
71
73
 
72
74
  # ==================== 账号信息 ====================
@@ -292,6 +294,155 @@ module Pindo
292
294
  !@config_json.nil?
293
295
  end
294
296
 
297
+ # ==================== AdHoc 发布配置合并 ====================
298
+
299
+ # 合并 AdHoc 发布配置
300
+ # 1. 替换所有 Bundle ID 为 AdHoc 配置的 Bundle ID(确保使用 AdHoc 证书)
301
+ # 2. 合并第三方 SDK 配置(Facebook、AdMob、AppLovin)
302
+ # 3. 合并 app_setting(排除主机和 URL 配置)
303
+ # @param adhoc_config_dir [String] AdHoc 配置仓库目录
304
+ # @return [Boolean] 是否成功
305
+ def modify_config_with_adhoc(adhoc_config_dir:)
306
+ return false unless loaded?
307
+ return false if adhoc_config_dir.nil? || adhoc_config_dir.empty?
308
+
309
+ begin
310
+ # 1. 读取 AdHoc 配置
311
+ adhoc_config_file = File.join(adhoc_config_dir, "config.json")
312
+ unless File.exist?(adhoc_config_file)
313
+ puts "AdHoc 配置文件不存在: #{adhoc_config_file}"
314
+ return false
315
+ end
316
+
317
+ adhoc_config_json = JSON.parse(File.read(adhoc_config_file))
318
+
319
+ # 1.5 替换 Apple ID(使用 AdHoc 配置的 Apple ID)
320
+ if adhoc_config_json.dig('account_info', 'apple_acount_id')
321
+ original_apple_id = @config_json.dig('account_info', 'apple_acount_id')
322
+ adhoc_apple_id = adhoc_config_json['account_info']['apple_acount_id']
323
+
324
+ if original_apple_id && adhoc_apple_id && original_apple_id != adhoc_apple_id
325
+ @config_json['account_info']['apple_acount_id'] = adhoc_apple_id
326
+ puts " 替换 Apple ID:"
327
+ puts " 原始 Apple ID: #{original_apple_id}"
328
+ puts " AdHoc Apple ID: #{adhoc_apple_id}"
329
+ end
330
+
331
+ # 如果 AdHoc 配置包含 company_name,也一并替换
332
+ if adhoc_config_json.dig('account_info', 'acount_company_name')
333
+ @config_json['account_info']['acount_company_name'] = adhoc_config_json['account_info']['acount_company_name']
334
+ end
335
+ end
336
+
337
+ # 2. 替换所有 Bundle ID(使用 AdHoc 配置的 Bundle ID)
338
+ original_bundle_id = @config_json.dig('app_info', 'app_identifier')
339
+ adhoc_bundle_id = adhoc_config_json.dig('app_info', 'app_identifier')
340
+
341
+ if original_bundle_id && adhoc_bundle_id && original_bundle_id != adhoc_bundle_id
342
+ puts " 替换 Bundle ID 前缀:"
343
+ puts " 原始前缀: #{original_bundle_id}"
344
+ puts " AdHoc 前缀: #{adhoc_bundle_id}"
345
+
346
+ # Bundle ID 字段映射表
347
+ bundle_id_keys = [
348
+ 'app_identifier', # 主应用
349
+ 'app_identifier_pushcontent', # Push Content Extension
350
+ 'app_identifier_pushservice', # Push Service Extension
351
+ 'app_identifier_keyboard', # Keyboard Extension
352
+ 'app_identifier_imessage', # iMessage Extension
353
+ 'app_identifier_extension', # 通用 Extension
354
+ 'app_identifier_siri', # Siri Extension
355
+ 'app_identifier_siriui', # Siri UI Extension
356
+ 'app_identifier_widget', # Widget Extension
357
+ 'app_identifier_extensionad', # 广告 Extension
358
+ 'app_identifier_extensionporn',# Porn Extension
359
+ 'app_identifier_watchapp', # Watch App
360
+ 'app_identifier_watchapp_extension' # Watch App Extension
361
+ ]
362
+
363
+ # 遍历所有 Bundle ID 字段并替换前缀
364
+ bundle_id_keys.each do |key|
365
+ current_value = @config_json.dig('app_info', key)
366
+ next if current_value.nil? || current_value.empty?
367
+
368
+ # 如果当前值以原始主 Bundle ID 开头,替换为 AdHoc Bundle ID
369
+ if current_value.start_with?(original_bundle_id)
370
+ # 计算后缀部分(如 .extension、.keyboard 等)
371
+ suffix = current_value[original_bundle_id.length..-1]
372
+ new_value = adhoc_bundle_id + suffix
373
+
374
+ @config_json['app_info'][key] = new_value
375
+ puts " ✓ #{key}: #{current_value} → #{new_value}"
376
+ end
377
+ end
378
+ end
379
+
380
+ # 2.5 替换 App Group ID 和 iCloud Container ID
381
+ if original_bundle_id && adhoc_bundle_id && original_bundle_id != adhoc_bundle_id
382
+ # 处理 app_group_id (格式: group.com.example.app)
383
+ if @config_json.dig('app_setting', 'app_group_id')
384
+ current_group_id = @config_json['app_setting']['app_group_id']
385
+ if current_group_id.include?(original_bundle_id)
386
+ new_group_id = current_group_id.gsub(original_bundle_id, adhoc_bundle_id)
387
+ @config_json['app_setting']['app_group_id'] = new_group_id
388
+ puts " ✓ app_group_id: #{current_group_id} → #{new_group_id}"
389
+ end
390
+ end
391
+
392
+ # 处理 app_icloud_id (格式: iCloud.com.example.app)
393
+ if @config_json.dig('app_setting', 'app_icloud_id')
394
+ current_icloud_id = @config_json['app_setting']['app_icloud_id']
395
+ if current_icloud_id.include?(original_bundle_id)
396
+ new_icloud_id = current_icloud_id.gsub(original_bundle_id, adhoc_bundle_id)
397
+ @config_json['app_setting']['app_icloud_id'] = new_icloud_id
398
+ puts " ✓ app_icloud_id: #{current_icloud_id} → #{new_icloud_id}"
399
+ end
400
+ end
401
+ end
402
+
403
+ # 3. 合并第三方 SDK 配置
404
+ # Facebook 配置
405
+ if adhoc_config_json.dig('app_info', 'facebook_app_id')
406
+ @config_json['app_info']['facebook_app_id'] = adhoc_config_json['app_info']['facebook_app_id']
407
+ @config_json['app_info']['facebook_client_token'] = adhoc_config_json['app_info']['facebook_client_token']
408
+ end
409
+
410
+ # AdMob 配置
411
+ if @config_json.dig('app_info', 'admob_app_id') && adhoc_config_json.dig('app_info', 'admob_app_id')
412
+ @config_json['app_info']['admob_app_id'] = adhoc_config_json['app_info']['admob_app_id']
413
+ end
414
+
415
+ # AppLovin 配置
416
+ if @config_json.dig('app_info', 'applovin_app_id') && adhoc_config_json.dig('app_info', 'applovin_app_id')
417
+ @config_json['app_info']['applovin_app_id'] = adhoc_config_json['app_info']['applovin_app_id']
418
+ end
419
+
420
+ # 4. 合并 app_setting(排除主机和 URL 配置)
421
+ excluded_keys = ['kGUKeyAppClientHost', 'kGUKeyResBaseUrl', 'app_web_host', 'app_client_url']
422
+
423
+ if @config_json['app_setting'] && adhoc_config_json['app_setting']
424
+ @config_json['app_setting'].each_key do |key|
425
+ next if excluded_keys.include?(key)
426
+
427
+ if adhoc_config_json['app_setting'][key]
428
+ @config_json['app_setting'][key] = adhoc_config_json['app_setting'][key]
429
+ end
430
+ end
431
+ end
432
+
433
+ # 5. 重新解析配置数据,同步更新 @config_data
434
+ # 这样 bundle_id、bundle_id_pushcontent 等属性方法才能返回替换后的值
435
+ parse_config_data
436
+
437
+ puts "✅ 已替换 Apple ID、Bundle ID 并合并 AdHoc 配置(Facebook、AdMob、AppLovin)"
438
+ true
439
+ rescue => e
440
+ puts "合并发布配置失败: #{e.message}"
441
+ puts e.backtrace.join("\n")
442
+ false
443
+ end
444
+ end
445
+
295
446
  # ==================== 调试和信息 ====================
296
447
 
297
448
  # 打印所有配置信息(用于调试)
@@ -346,6 +497,17 @@ module Pindo
346
497
  if @config_json['app_info']
347
498
  app_info = @config_json['app_info']
348
499
  @config_data[:bundle_id] = app_info['app_identifier']
500
+
501
+ # 保存原始 Bundle ID 作为配置仓库名称(只在第一次设置,后续不覆盖)
502
+ if @app_repo_name.nil? && app_info['app_identifier']
503
+ repo_name = app_info['app_identifier']
504
+ # 如果是通配符 Bundle ID(以 .* 结尾),去除通配符后缀
505
+ if repo_name.end_with?('.*')
506
+ repo_name = repo_name[0...-2] # 去除最后的 .*
507
+ end
508
+ @app_repo_name = repo_name
509
+ end
510
+
349
511
  @config_data[:bundle_id_pushcontent] = app_info['app_identifier_pushcontent']
350
512
  @config_data[:bundle_id_pushservice] = app_info['app_identifier_pushservice']
351
513
  @config_data[:bundle_id_keyboard] = app_info['app_identifier_keyboard']
@@ -259,7 +259,7 @@ module Pindo
259
259
  provision_start_name = "Development"
260
260
  cert_sub_dir = cert_type.downcase
261
261
  elsif cert_type.downcase.include?("adhoc")
262
- provision_start_name = "Adhoc"
262
+ provision_start_name = "AdHoc"
263
263
  cert_sub_dir = "adhoc"
264
264
  else
265
265
  provision_start_name = "AppStore"
@@ -46,6 +46,38 @@ module Pindo
46
46
  # 1. 加载配置到 IosConfigParser 单例
47
47
  load_ios_config
48
48
 
49
+ # 1.5 获取 AdHoc 配置目录并合并配置
50
+ adhoc_config_dir = nil
51
+ begin
52
+ config_parser = Pindo::IosConfigParser.instance
53
+ config_json = config_parser.config_json
54
+
55
+ # 根据 app_type 获取 AdHoc 配置仓库
56
+ if config_json && config_json['project_info'] && config_json['project_info']['app_type']
57
+ require 'pindo/config/build_info_manager'
58
+
59
+ build_info_manager = Pindo::BuildInfoManager.share_instance
60
+ adhoc_repo_name = build_info_manager.get_deploy_repo_with_modul_name(
61
+ module_name: config_json['project_info']['app_type']
62
+ )
63
+
64
+ if adhoc_repo_name.nil? || adhoc_repo_name.empty?
65
+ raise Informative, "config.json app_type is error!!!"
66
+ end
67
+
68
+ # 克隆 AdHoc 配置仓库
69
+ adhoc_config_dir = build_info_manager.clong_buildconfig_repo(repo_name: adhoc_repo_name)
70
+
71
+ # 合并 AdHoc 配置
72
+ config_parser.modify_config_with_adhoc(adhoc_config_dir: adhoc_config_dir)
73
+ else
74
+ puts "配置中缺少 app_type,跳过 AdHoc 配置合并"
75
+ end
76
+ rescue => e
77
+ puts "获取 AdHoc 配置失败: #{e.message}"
78
+ adhoc_config_dir = nil
79
+ end
80
+
49
81
  # 2. 自动增加版本号
50
82
  auto_increase_buildnumber
51
83
 
@@ -55,6 +87,16 @@ module Pindo
55
87
  # 4. 配置 Xcode 项目
56
88
  configure_xcode_project
57
89
 
90
+ # 4.5 安装 Firebase 配置 - 使用 AdHoc 配置仓库目录
91
+ if adhoc_config_dir && File.directory?(adhoc_config_dir)
92
+ require 'pindo/module/xcode/xcode_build_helper'
93
+
94
+ Pindo::XcodeBuildHelper.install_google_plist(
95
+ project_dir: @project_path,
96
+ app_config_dir: adhoc_config_dir
97
+ )
98
+ end
99
+
58
100
  # 5. Quark/Swark 处理
59
101
  handle_quswark_processing
60
102
 
@@ -84,6 +126,58 @@ module Pindo
84
126
  end
85
127
  end
86
128
 
129
+ # 处理 CocoaPods 依赖(AdHoc 构建)
130
+ def handle_cocoapods
131
+ return unless File.exist?(File.join(@project_path, "Podfile"))
132
+
133
+ require 'pindo/module/xcode/cocoapods_helper'
134
+ require 'pindo/config/pindoconfig'
135
+
136
+ config_parser = Pindo::IosConfigParser.instance
137
+
138
+ # 使用原始 Bundle ID(app_repo_name)作为配置仓库名称
139
+ # 注意:config_parser.bundle_id 在 AdHoc 构建中已被替换为 AdHoc Bundle ID
140
+ # 而 app_repo_name 保留了原始值,用于定位正确的配置仓库
141
+ app_repo_name = config_parser.app_repo_name
142
+ app_version = config_parser.app_version || "unknown"
143
+
144
+ # 获取配置仓库目录(用于备份)
145
+ # 使用 clong_buildconfig_repo 确保仓库已克隆或更新
146
+ require 'pindo/base/git_handler'
147
+ app_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: app_repo_name)
148
+
149
+ # 1. 清理 Pods 和 Podfile.lock(强制清理)
150
+ puts "\n🧹 清理 Pods 和 Podfile.lock..."
151
+ pods_dir = File.join(@project_path, "Pods")
152
+ podfile_lock = File.join(@project_path, "Podfile.lock")
153
+ FileUtils.rm_rf(pods_dir) if File.exist?(pods_dir)
154
+ FileUtils.rm_rf(podfile_lock) if File.exist?(podfile_lock)
155
+
156
+ # 2. 更新私有索引库
157
+ Pindo::CocoaPodsHelper.update_pod_repo(
158
+ install: false,
159
+ project_dir: @project_path
160
+ )
161
+
162
+ # 3. 移除测试 Pod 模块
163
+ Pindo::CocoaPodsHelper.remove_test_pods(@project_path)
164
+
165
+ # 4. 清理并重新安装(删除 Podfile.lock)
166
+ Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path, clean_podfile_lock: true)
167
+
168
+ # 5. 备份 Podfile.lock 到配置仓库
169
+ unless app_config_dir && File.directory?(app_config_dir)
170
+ raise Informative, "配置仓库目录不存在或无法访问,无法备份 Podfile.lock: #{app_config_dir}"
171
+ end
172
+
173
+ puts "\n💾 备份 Podfile.lock 到配置仓库: #{app_config_dir}"
174
+ Pindo::CocoaPodsHelper.backup_podfile_lock(
175
+ @project_path,
176
+ app_config_dir,
177
+ app_version
178
+ )
179
+ end
180
+
87
181
  private
88
182
 
89
183
  # 加载 iOS 配置
@@ -291,21 +385,6 @@ module Pindo
291
385
  end
292
386
  end
293
387
 
294
-
295
- # 处理 CocoaPods
296
- def handle_cocoapods
297
- return unless File.exist?(File.join(@project_path, "Podfile"))
298
-
299
- # 1. 更新私有索引库
300
- Pindo::CocoaPodsHelper.update_pod_repo(
301
- install: false,
302
- project_dir: @project_path
303
- )
304
-
305
- # 2. 清理并重新安装
306
- Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path)
307
- end
308
-
309
388
  # 检测是否为 macOS 平台
310
389
  def detect_macos_platform
311
390
  project_fullname = Dir.glob(File.join(@project_path, "/*.xcodeproj")).max_by { |f| File.mtime(f) }
@@ -84,6 +84,47 @@ module Pindo
84
84
  end
85
85
  end
86
86
 
87
+ # 处理 CocoaPods 依赖(AppStore 构建)
88
+ def handle_cocoapods
89
+ return unless File.exist?(File.join(@project_path, "Podfile"))
90
+
91
+ require 'pindo/module/xcode/cocoapods_helper'
92
+ require 'pindo/config/pindoconfig'
93
+
94
+ config_parser = Pindo::IosConfigParser.instance
95
+
96
+ # 使用原始 Bundle ID(app_repo_name)作为配置仓库名称
97
+ app_repo_name = config_parser.app_repo_name
98
+
99
+ # 获取配置仓库目录
100
+ pindo_dir = File.expand_path(Pindo::Pindoconfig.instance.pindo_dir)
101
+ app_config_dir = File.join(pindo_dir, app_repo_name)
102
+
103
+ # 1. 清理 Pods 和 Podfile.lock(强制清理)
104
+ puts "\n🧹 清理 Pods 和 Podfile.lock..."
105
+ pods_dir = File.join(@project_path, "Pods")
106
+ podfile_lock = File.join(@project_path, "Podfile.lock")
107
+ FileUtils.rm_rf(pods_dir) if File.exist?(pods_dir)
108
+ FileUtils.rm_rf(podfile_lock) if File.exist?(podfile_lock)
109
+
110
+ # 2. 更新私有索引库
111
+ Pindo::CocoaPodsHelper.update_pod_repo(
112
+ install: false,
113
+ project_dir: @project_path
114
+ )
115
+
116
+ # 3. 移除测试 Pod 模块
117
+ Pindo::CocoaPodsHelper.remove_test_pods(@project_path)
118
+
119
+ # 4. 从配置仓库拷贝 Podfile.lock
120
+ if File.directory?(app_config_dir)
121
+ Pindo::CocoaPodsHelper.copy_podfile_lock_from_config(@project_path, app_config_dir)
122
+ end
123
+
124
+ # 5. 清理并重新安装(不删除 Podfile.lock)
125
+ Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path, clean_podfile_lock: false)
126
+ end
127
+
87
128
  private
88
129
 
89
130
  # 加载 iOS 配置
@@ -291,20 +332,6 @@ module Pindo
291
332
  end
292
333
  end
293
334
 
294
- # 处理 CocoaPods
295
- def handle_cocoapods
296
- return unless File.exist?(File.join(@project_path, "Podfile"))
297
-
298
- # 1. 更新私有索引库
299
- Pindo::CocoaPodsHelper.update_pod_repo(
300
- install: false,
301
- project_dir: @project_path
302
- )
303
-
304
- # 2. 清理并重新安装
305
- Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path)
306
- end
307
-
308
335
  # 检测是否为 macOS 平台
309
336
  def detect_macos_platform
310
337
  project_fullname = Dir.glob(File.join(@project_path, "/*.xcodeproj")).max_by { |f| File.mtime(f) }
@@ -70,6 +70,29 @@ module Pindo
70
70
  end
71
71
  end
72
72
 
73
+ # 处理 CocoaPods 依赖(Dev 构建)
74
+ def handle_cocoapods
75
+ return unless File.exist?(File.join(@project_path, "Podfile"))
76
+
77
+ require 'pindo/module/xcode/cocoapods_helper'
78
+
79
+ # 1. 清理 Pods 和 Podfile.lock(强制清理)
80
+ puts "\n🧹 清理 Pods 和 Podfile.lock..."
81
+ pods_dir = File.join(@project_path, "Pods")
82
+ podfile_lock = File.join(@project_path, "Podfile.lock")
83
+ FileUtils.rm_rf(pods_dir) if File.exist?(pods_dir)
84
+ FileUtils.rm_rf(podfile_lock) if File.exist?(podfile_lock)
85
+
86
+ # 2. 更新私有索引库
87
+ Pindo::CocoaPodsHelper.update_pod_repo(
88
+ install: false,
89
+ project_dir: @project_path
90
+ )
91
+
92
+ # 3. 清理并重新安装(删除 Podfile.lock)
93
+ Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path, clean_podfile_lock: true)
94
+ end
95
+
73
96
  private
74
97
 
75
98
  # Git 标签检查
@@ -158,20 +181,6 @@ module Pindo
158
181
  )
159
182
  end
160
183
 
161
- # 处理 CocoaPods
162
- def handle_cocoapods
163
- return unless File.exist?(File.join(@project_path, "Podfile"))
164
-
165
- # 1. 更新私有索引库
166
- Pindo::CocoaPodsHelper.update_pod_repo(
167
- install: false,
168
- project_dir: @project_path
169
- )
170
-
171
- # 2. 清理并重新安装
172
- Pindo::CocoaPodsHelper.deintegrate_and_install(@project_path)
173
- end
174
-
175
184
  # 配置证书
176
185
  def configure_certificate
177
186
  # 检查是否是 macOS 工程
@@ -1,5 +1,7 @@
1
1
  require 'cocoapods'
2
2
  require 'fileutils'
3
+ require 'digest'
4
+ require 'json'
3
5
  require 'pindo/base/git_handler'
4
6
  require 'pindo/config/pindoconfig'
5
7
 
@@ -55,14 +57,22 @@ module Pindo
55
57
 
56
58
  # 清理并重新安装 CocoaPods
57
59
  # @param project_dir [String] 项目目录
58
- def deintegrate_and_install(project_dir)
60
+ # @param clean_podfile_lock [Boolean] 是否在安装前删除 Podfile.lock,默认为 true
61
+ def deintegrate_and_install(project_dir, clean_podfile_lock: true)
59
62
  return unless File.exist?(File.join(project_dir, "Podfile"))
60
63
 
61
64
  Dir.chdir(project_dir) do
62
65
  begin
63
- # 清理现有 Pods
64
- FileUtils.rm_rf("Podfile.lock") if File.exist?("Podfile.lock")
65
- FileUtils.rm_rf("Pods") if File.exist?("Pods")
66
+ # 如果需要,删除 Podfile.lock
67
+ if clean_podfile_lock && File.exist?("Podfile.lock")
68
+ FileUtils.rm_rf("Podfile.lock")
69
+ puts "已删除 Podfile.lock"
70
+ end
71
+
72
+ # 删除 Pods 目录
73
+ if File.exist?("Pods")
74
+ FileUtils.rm_rf("Pods")
75
+ end
66
76
 
67
77
  puts "正在执行 pod deintegrate..."
68
78
  system 'pod deintegrate'
@@ -106,6 +116,119 @@ module Pindo
106
116
  end
107
117
  end
108
118
 
119
+ # 移除测试相关的 Pod 模块
120
+ # @param project_dir [String] 项目目录
121
+ # @return [Boolean] 是否成功
122
+ def remove_test_pods(project_dir)
123
+ pod_file = File.join(project_dir, "Podfile")
124
+ return false unless File.exist?(pod_file)
125
+
126
+ begin
127
+ # 测试插件列表
128
+ test_plugins = [
129
+ "FancySettingsPlugin",
130
+ "TYSettingsPlugin",
131
+ "CSSettingsPlugin",
132
+ "FunnySettingsPlugin"
133
+ ]
134
+
135
+ # 使用 sed 命令删除测试插件
136
+ test_plugins.each do |plugin_name|
137
+ command = "sed -i \"\" \"/.*#{plugin_name}.*/d\" #{pod_file}"
138
+ system command
139
+ end
140
+
141
+ puts "已移除测试 Pod 模块"
142
+ true
143
+ rescue => e
144
+ puts "移除测试 Pod 模块失败: #{e.message}"
145
+ false
146
+ end
147
+ end
148
+
149
+ # 从配置仓库拷贝 Podfile.lock 到项目目录
150
+ # @param project_dir [String] 项目目录
151
+ # @param app_config_dir [String] 应用配置目录
152
+ # @return [Boolean] 是否成功
153
+ def copy_podfile_lock_from_config(project_dir, app_config_dir)
154
+ begin
155
+ config_pod_file = File.join(app_config_dir, "Podfile.lock")
156
+ unless File.exist?(config_pod_file)
157
+ puts "配置仓库中不存在 Podfile.lock,跳过拷贝"
158
+ return false
159
+ end
160
+
161
+ # 拷贝 Podfile.lock 到项目目录
162
+ project_pod_file = File.join(project_dir, "Podfile.lock")
163
+ FileUtils.cp(config_pod_file, project_pod_file)
164
+
165
+ puts "✅ 已从配置仓库拷贝 Podfile.lock"
166
+ true
167
+ rescue => error
168
+ puts "拷贝 Podfile.lock 失败: #{error.message}"
169
+ false
170
+ end
171
+ end
172
+
173
+ # 备份 Podfile.lock 到配置仓库
174
+ # @param project_dir [String] 项目目录
175
+ # @param app_config_dir [String] 应用配置目录
176
+ # @param app_version [String] 应用版本号
177
+ # @return [Boolean] 是否成功
178
+ def backup_podfile_lock(project_dir, app_config_dir, app_version)
179
+ begin
180
+ proj_pod_file = File.join(project_dir, "Podfile.lock")
181
+ unless File.exist?(proj_pod_file)
182
+ puts "Podfile.lock 不存在,跳过备份"
183
+ return false
184
+ end
185
+
186
+ # 复制 Podfile.lock 到配置仓库
187
+ FileUtils.cp(proj_pod_file, File.join(app_config_dir, "Podfile.lock"))
188
+ Pindo::GitHandler.git_addpush_repo(
189
+ path: app_config_dir,
190
+ message: "#{app_version} backup podfile.lock",
191
+ commit_file_params: ["Podfile.lock"]
192
+ )
193
+
194
+ # 计算 Podfile.lock 的 MD5 checksum
195
+ bytes = File.binread(proj_pod_file)
196
+ checksum = Digest::MD5.hexdigest(bytes)
197
+
198
+ # 更新 build_verify.json
199
+ build_verify_file = File.join(app_config_dir, "build_verify.json")
200
+ build_verify_json = {}
201
+ if File.exist?(build_verify_file)
202
+ begin
203
+ build_verify_json = JSON.parse(File.read(build_verify_file))
204
+ rescue => error
205
+ # 忽略解析错误,使用空 hash
206
+ end
207
+ end
208
+
209
+ build_verify_json["output_code_commit"] = Pindo::GitHandler.git_latest_commit_id(local_repo_dir: project_dir)
210
+ build_verify_json["output_config_commit"] = Pindo::GitHandler.git_latest_commit_id(local_repo_dir: app_config_dir)
211
+ build_verify_json["output_podfile_checksum"] = checksum
212
+ build_verify_json["output_time"] = Time.now.strftime('%y/%m/%d %H:%M:%S')
213
+
214
+ File.open(build_verify_file, "w") do |file|
215
+ file.write(JSON.pretty_generate(build_verify_json))
216
+ file.close
217
+ end
218
+
219
+ Pindo::GitHandler.git_addpush_repo(
220
+ path: app_config_dir,
221
+ message: "backup #{app_version} output info",
222
+ commit_file_params: ["build_verify.json"]
223
+ )
224
+
225
+ puts "✅ 已备份 Podfile.lock 到配置仓库"
226
+ true
227
+ rescue => error
228
+ raise Informative, "保存 Podfile.lock 文件失败: #{error.message}"
229
+ end
230
+ end
231
+
109
232
  private
110
233
 
111
234
  # 获取私有 Pod 索引地址
@@ -207,19 +207,20 @@ module Pindo
207
207
 
208
208
  def install_launchimg(launchimg_pub_path:nil)
209
209
 
210
- xcodeproj_launchimg_path = get_xcodeproj_launchimg_path
211
210
  pub_launchimg_files = Dir.glob(File.join(launchimg_pub_path, "*.{png,jpg}"))
212
211
 
213
- if xcodeproj_launchimg_path.nil? || !File.exist?(xcodeproj_launchimg_path)
214
- if !pub_launchimg_files.nil? && pub_launchimg_files.size > 0
215
- raise Informative, "有需要替换的资源,但是未找到工程启动图目录,替换启动图失败!"
216
- end
212
+ # 如果配置仓库中没有启动图,直接跳过
213
+ if pub_launchimg_files.nil? || pub_launchimg_files.size == 0
217
214
  return
218
215
  end
219
216
 
220
- # if pub_launchimg_files.nil? || pub_launchimg_files.size == 0
221
- # raise Informative, "有需要替换的资源,但是配置中未放置替换的启动图!"
222
- # end
217
+ # 配置仓库中有启动图,需要进行替换
218
+ xcodeproj_launchimg_path = get_xcodeproj_launchimg_path
219
+
220
+ # 如果项目中没有启动图目录,报错中断
221
+ if xcodeproj_launchimg_path.nil? || !File.exist?(xcodeproj_launchimg_path)
222
+ raise Informative, "配置仓库中有 #{pub_launchimg_files.size} 个启动图资源需要替换,但项目中未找到 LaunchImage.launchimage 目录,替换启动图失败!"
223
+ end
223
224
 
224
225
  xcodeproj_launchimg_json_file = File.join(xcodeproj_launchimg_path, "Contents.json")
225
226
  if !File.exist?(xcodeproj_launchimg_json_file)
@@ -218,11 +218,19 @@ module Pindo
218
218
  def create_release_tag(project_dir:, config_json:, bundle_id:, delete_tag_name: nil)
219
219
  require 'pindo/base/git_handler'
220
220
  require 'pindo/config/pindoconfig'
221
+ require 'pindo/config/ios_config_parser'
221
222
  require_relative '../../base/funlog'
222
223
 
223
224
  begin
224
225
  pindo_dir = File.expand_path(Pindo::Pindoconfig.instance.pindo_dir)
225
- app_config_dir = File.join(pindo_dir, bundle_id)
226
+
227
+ # 使用原始 Bundle ID(app_repo_name)访问配置仓库
228
+ # 在 AdHoc/AppStore 构建中,bundle_id 参数可能已被替换
229
+ # 需要使用 app_repo_name(原始 Bundle ID)访问正确的配置仓库
230
+ config_parser = Pindo::IosConfigParser.instance
231
+ app_repo_name = config_parser.app_repo_name || bundle_id # 回退到参数 bundle_id 以兼容独立命令
232
+
233
+ app_config_dir = File.join(pindo_dir, app_repo_name)
226
234
 
227
235
  # 如果指定了要删除的 tag
228
236
  if !delete_tag_name.nil? && !delete_tag_name.empty?
@@ -517,6 +517,11 @@ module Pindo
517
517
  raise Informative, "无法从配置中获取 Bundle ID"
518
518
  end
519
519
 
520
+ # 获取原始 Bundle ID(用于配置仓库名称)
521
+ # 在 AdHoc 构建中,bundle_id 已被替换为 AdHoc Bundle ID
522
+ # 需要使用 app_repo_name(原始 Bundle ID)来访问正确的配置仓库
523
+ app_repo_name = config_parser.app_repo_name
524
+
520
525
  # 获取项目名称
521
526
  project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
522
527
  if project_fullname.nil? || !File.exist?(project_fullname)
@@ -526,7 +531,7 @@ module Pindo
526
531
 
527
532
  # 1. 安装 Google Plist
528
533
  Funlog.instance.fancyinfo_start("正在替换 google-info.plist...")
529
- google_info_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: bundle_id)
534
+ google_info_config_dir = Pindo::GitHandler.clong_buildconfig_repo(repo_name: app_repo_name)
530
535
  Pindo::XcodeBuildHelper.install_google_plist(
531
536
  project_dir: project_dir,
532
537
  app_config_dir: google_info_config_dir
@@ -620,7 +625,7 @@ module Pindo
620
625
  rescue StandardError => e
621
626
  Funlog.instance.fancyinfo_error("配置 Xcode 项目失败: #{e.message}")
622
627
  puts e.backtrace
623
- return false
628
+ raise Informative, "配置 Xcode 项目失败: #{e.message}"
624
629
  end
625
630
 
626
631
  end
@@ -286,12 +286,20 @@ module Pindo
286
286
  require_relative '../../base/funlog'
287
287
  require 'pindo/base/git_handler'
288
288
  require 'pindo/config/pindoconfig'
289
+ require 'pindo/config/ios_config_parser'
289
290
 
290
291
  begin
291
292
  Funlog.instance.fancyinfo_start("正在执行 Swark 授权...")
292
293
 
293
294
  pindo_dir = Pindo::Pindoconfig.instance.pindo_dir
294
- app_config_dir = File.join(File.expand_path(pindo_dir), bundle_id)
295
+
296
+ # 使用原始 Bundle ID(app_repo_name)访问配置仓库
297
+ # 在 AdHoc 构建中,bundle_id 参数已被替换为 AdHoc Bundle ID
298
+ # 需要使用 app_repo_name(原始 Bundle ID)访问正确的配置仓库
299
+ config_parser = Pindo::IosConfigParser.instance
300
+ app_repo_name = config_parser.app_repo_name || bundle_id # 回退到参数 bundle_id 以兼容独立命令
301
+
302
+ app_config_dir = File.join(File.expand_path(pindo_dir), app_repo_name)
295
303
  swark_authorize_file = File.join(app_config_dir, "swark_authorize.json")
296
304
 
297
305
  unless File.exist?(swark_authorize_file)
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.13.4"
9
+ VERSION = "5.13.5"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pindo
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.13.4
4
+ version: 5.13.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade