pindo 5.21.4 → 5.21.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: 9f3b56fbb1ab0c039204dd6a338a884ba5a6b0cc014d4abe0356a18bd92b9277
4
- data.tar.gz: 5f1c9874bfb6ed50da8c7f02d5dc2a8fc93a15bd59eb59a6be5e904222a0fe42
3
+ metadata.gz: a4ccbec1218f28dfa10b000e89759db3e8167c0ea598637a0f8436a557ab14bc
4
+ data.tar.gz: 737550673bf62315c4ab30652496a82bcda55001991af18c2c5da1b019b9cf83
5
5
  SHA512:
6
- metadata.gz: dc8a61f2d93aae23c9f6e2986d962cf15d25dfe3bf5d88c02035f36a08dd4b04d98d1ce2f911ada41b79361fa9f6ff8b19a4c46751dce5fcbb5d30b7c87d08a5
7
- data.tar.gz: b1f52d2f1e22c7c5b2d0d06ba51c57f65e240f2305dd8c4c72ad535708d27dd7f08e7dee84ea7f28a7a527930b55f20dd580ee20db69f732e9908771c595d371
6
+ metadata.gz: 52e831191efa0d0092fdd2333658ece13ff82f004255d5dfe55b5f75a295b5d46356fc56956323b8b526bd6dfdda5fa10b15e5e144e971fb70bd629bb5268e57
7
+ data.tar.gz: 6fa3ad96ffe7951bcec719e8c9a3ffad2540e807c4d451ba6a3dc16fbe59e85a2520f874d72ae589b72ebd47828df71c0482dfcedbdb310e58d6c99f49e24efb
@@ -1,4 +1,5 @@
1
1
  require 'fileutils'
2
+ require 'open3'
2
3
  require 'pindo/base/executable'
3
4
  require 'pindo/base/informative'
4
5
  require 'etc'
@@ -556,6 +557,16 @@ module Pindo
556
557
 
557
558
 
558
559
 
560
+ # 仓库是否已有提交(git init 后尚未首次提交的仓库没有 HEAD)
561
+ # @param git_root [String] Git 根目录
562
+ # @return [Boolean]
563
+ def head_commit_exists?(git_root:)
564
+ _stdout, _stderr, status = Open3.capture3('git', '-C', git_root, 'rev-parse', '--verify', '--quiet', 'HEAD')
565
+ status.success?
566
+ rescue SystemCallError
567
+ false
568
+ end
569
+
559
570
  # 获取未提交的文件列表
560
571
  # @param project_dir [String] 项目目录路径
561
572
  # @return [Array<String>, nil] 返回未提交的文件列表,如果没有则返回 nil
@@ -970,6 +981,15 @@ module Pindo
970
981
  # @param default_process_type [Symbol, nil] 非交互模式下的默认处理方式,默认为 nil
971
982
  # @return [Symbol] UncommittedFilesProcessType 枚举常量
972
983
  def get_uncommitted_files_process_type(project_dir:, interactive: true, default_process_type: nil)
984
+ # 0. 空仓库没有 HEAD,后续的暂存区重置、版本计算、分支同步和打 tag 都无法进行
985
+ git_root = git_root_directory(local_repo_dir: project_dir)
986
+ if git_root && !head_commit_exists?(git_root: git_root)
987
+ raise Informative, "当前 Git 仓库还没有任何提交,无法计算版本号和打 tag:#{git_root}\n" \
988
+ "请先完成首次提交后重新执行:\n" \
989
+ " git -C \"#{git_root}\" add -A\n" \
990
+ " git -C \"#{git_root}\" commit -m \"chore: 初始化工程\""
991
+ end
992
+
973
993
  # 1. 检查是否有未提交的文件
974
994
  uncommitted_files = get_uncommitted_files(project_dir: project_dir)
975
995
 
@@ -986,8 +1006,7 @@ module Pindo
986
1006
  return default_process_type
987
1007
  end
988
1008
 
989
- # 4. 获取 Git 根目录并获取当前分支名
990
- git_root = git_root_directory(local_repo_dir: project_dir)
1009
+ # 4. 获取当前分支名
991
1010
  unless git_root
992
1011
  Funlog.instance.fancyinfo_warning("当前目录不是Git仓库")
993
1012
  return Pindo::UncommittedFilesProcessType::SKIP_WITH_TAG
@@ -0,0 +1,42 @@
1
+ require 'xcodeproj'
2
+
3
+ module Pindo
4
+ # Xcode 26.4+/27 工程格式兼容补丁(xcodeproj 1.28.1 尚未支持,见 CocoaPods/Xcodeproj#1017)
5
+ #
6
+ # CocoaPods 与 fastlane gym 在 pindo 进程内运行,共用同一份补丁。
7
+ module XcodeprojCompat
8
+ # 新格式把 shellScript 存为按行拆分的数组,合并回字符串
9
+ module ShellScriptArray
10
+ def shell_script=(value)
11
+ super(value.is_a?(Array) ? value.join("\n") : value)
12
+ end
13
+ end
14
+
15
+ # 保存时保留 xcodeproj 不认识的字段(如 Copy Files 阶段的 dstSubfolder),
16
+ # 否则这些字段会被丢弃,导致扩展等产物的嵌入位置丢失
17
+ module UnknownAttributes
18
+ def configure_with_plist(objects_by_uuid_plist)
19
+ object_plist = objects_by_uuid_plist[uuid]
20
+ known_keys = self.class.attributes.map(&:plist_name) << 'isa'
21
+ @pindo_unknown_attributes = object_plist.reject { |key, _| known_keys.include?(key) }
22
+
23
+ # 暂时移除未知字段,避免 xcodeproj 对已保留的字段输出误导性警告
24
+ @pindo_unknown_attributes.each_key { |key| object_plist.delete(key) }
25
+ super
26
+ ensure
27
+ object_plist&.merge!(@pindo_unknown_attributes || {})
28
+ end
29
+
30
+ private
31
+
32
+ def to_hash_as(method = :to_hash)
33
+ plist = super
34
+ (@pindo_unknown_attributes || {}).each { |key, value| plist[key] = value unless plist.key?(key) }
35
+ plist
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ Xcodeproj::Project::Object::PBXShellScriptBuildPhase.prepend(Pindo::XcodeprojCompat::ShellScriptArray)
42
+ Xcodeproj::Project::Object::AbstractObject.prepend(Pindo::XcodeprojCompat::UnknownAttributes)
@@ -142,7 +142,8 @@ module Pindo
142
142
  project_dir: @project_path,
143
143
  workflow_packname: workflow_packname,
144
144
  project_id: project_id,
145
- bundle_id: @bundle_id
145
+ bundle_id: @bundle_id,
146
+ bundle_id_prefix: Pindo::XcodeBuildConfig.bundle_id_prefix_from(config_bundle_id)
146
147
  )
147
148
 
148
149
  # 下载并替换 Icon,优先使用 packageProjectIcon,为空则回退到 projectIcon
@@ -159,7 +160,7 @@ module Pindo
159
160
  )
160
161
 
161
162
  unless icon_replace_success
162
- raise Informative, "Icon 下载或替换失败,请检查 Icon URL 是否有效: #{icon_url}"
163
+ raise Informative, "Icon 下载或替换失败,具体原因见上方日志(Icon URL: #{icon_url})"
163
164
  end
164
165
  else
165
166
  Funlog.warning("未配置 Icon URL,跳过 Icon 替换")
@@ -196,8 +197,8 @@ module Pindo
196
197
  commit_short = commit_hash ? commit_hash[0..7] : "unknown"
197
198
  Funlog.instance.fancyinfo_success("自己计算版本号: #{build_version}, Build: #{build_number}, Commit: #{commit_short}")
198
199
  else
199
- # 不是 Git 仓库且没有从 GitCommitTask 获取到版本号,跳过版本更新
200
- Funlog.warning("非Git仓库且未从 GitCommitTask 获取到版本号,保持工程原有版本号")
200
+ # 不是 Git 仓库且没有从 GitCommitTask 获取到版本号:沿用工程版本号,但补齐为 JPS 要求的 major.minor.patch
201
+ normalize_project_version
201
202
  return
202
203
  end
203
204
  end
@@ -210,6 +211,35 @@ module Pindo
210
211
  )
211
212
  end
212
213
 
214
+ # 非 Git 仓库时沿用工程原有版本号,仅补齐格式(如 Xcode 模板默认的 1.0 => 1.0.0),否则 JPS 拒收
215
+ def normalize_project_version
216
+ version, build_number = Pindo::XcodeBuildConfig.current_app_version(project_dir: @project_path)
217
+ normalized = Pindo::XcodeBuildConfig.normalize_marketing_version(version)
218
+
219
+ if normalized.nil?
220
+ Funlog.warning("非Git仓库,保持工程原有版本号 #{version.inspect};JPS 要求 major.minor.patch 格式,上传可能失败")
221
+ return
222
+ end
223
+
224
+ if normalized == version.to_s.strip
225
+ Funlog.warning("非Git仓库且未从 GitCommitTask 获取到版本号,保持工程原有版本号 #{normalized}")
226
+ return
227
+ end
228
+
229
+ Funlog.warning("非Git仓库,工程版本号 #{version} 补齐为 #{normalized}")
230
+ Pindo::XcodeBuildConfig.update_ios_project_version(
231
+ project_dir: @project_path,
232
+ version: normalized,
233
+ build_number: build_number.to_s.strip.empty? ? '1' : build_number
234
+ )
235
+ end
236
+
237
+ # 当前环境配置仓库中的主 Bundle ID(如 workhard 为 com.eyesofstorms.*),与证书使用同一来源
238
+ def config_bundle_id
239
+ require 'pindo/config/ios_config_parser'
240
+ Pindo::IosConfigParser.instance.bundle_id
241
+ end
242
+
213
243
  # 检查配置
214
244
  def pull_config
215
245
  # 检查 IosConfigParser 单例中是否已加载配置
@@ -12,38 +12,69 @@ module Pindo
12
12
  @project_obj = Xcodeproj::Project.open(proj_fullname)
13
13
  end
14
14
 
15
- # 查找工程的 AppIcon.appiconset 目录,找不到返回 nil(不抛异常)
15
+ DEFAULT_APP_ICON_NAME = "AppIcon".freeze
16
+ APP_ICON_NAME_SETTING = "ASSETCATALOG_COMPILER_APPICON_NAME".freeze
17
+
18
+ # 查找工程的 App 图标集目录(<图标名>.appiconset),找不到返回 nil(不抛异常)
16
19
  def find_xcodeproj_icon_path()
17
- icon_path = nil
18
- select_target = @project_obj.targets.select { |target| target.respond_to?(:product_type) && target.product_type.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application]) }.first
20
+ icon_dir_name = "#{app_icon_name}.appiconset"
21
+
22
+ # 优先在主 target 自己的 asset catalog 中查找
23
+ icon_path = main_target_asset_catalogs
24
+ .map { |catalog| File.join(catalog, icon_dir_name) }
25
+ .find { |path| File.directory?(path) }
26
+ return icon_path if icon_path
27
+
28
+ icon_path_array = Dir.glob(File.join(@project_obj.project_dir, "**", icon_dir_name))
29
+ if icon_path_array.size > 1
30
+ icon_path = icon_path_array.find{ |filename| File.directory?(filename) && filename.include?("Assets.xcassets/#{icon_dir_name}")}
31
+ elsif icon_path_array.size == 1
32
+ icon_path = icon_path_array.first
33
+ end
19
34
 
20
- project_dir = @project_obj.project_dir
35
+ return nil if icon_path.nil? || icon_path.empty? || !File.exist?(icon_path)
36
+ icon_path
37
+ end
21
38
 
22
- if !select_target.nil?
23
- file_refs = select_target.resources_build_phase.files_references.select { |file| file.display_name.include?("Assets.xcassets") } || []
24
- file_refs.each do |file_ref|
25
- icon_path = File.join(file_ref.real_path,"AppIcon.appiconset")
26
- if File.exist?(icon_path)
27
- break
28
- else
29
- next
30
- end
31
- end
32
- end
33
- if icon_path.nil? || icon_path.empty? || !File.exist?(icon_path)
34
- icon_path_array = Dir.glob(File.join(project_dir, "**", "AppIcon.appiconset"))
35
- if icon_path_array.size > 1
36
- icon_path = icon_path_array.find{ |filename| File.directory?(filename) && filename.include?("Assets.xcassets/AppIcon.appiconset")}
37
- elsif icon_path_array.size == 1
38
- icon_path = icon_path_array.first
39
- end
39
+ # 查找 App 图标集目录;工程没有图标集时(如 Xcode 新模板工程),
40
+ # 在主 target 的 asset catalog 中创建,并设置 ASSETCATALOG_COMPILER_APPICON_NAME
41
+ def ensure_app_icon_path()
42
+ icon_path = find_xcodeproj_icon_path()
43
+ return icon_path if icon_path
44
+
45
+ catalog = main_target_asset_catalogs.first
46
+ if catalog.nil?
47
+ raise Informative, "没有找到Xcode icon 目录:主 target 中既没有 #{app_icon_name}.appiconset,也没有可存放图标的 .xcassets"
40
48
  end
41
49
 
42
- if icon_path.nil? || icon_path.empty? || !File.exist?(icon_path)
43
- return nil
50
+ icon_path = File.join(catalog, "#{app_icon_name}.appiconset")
51
+ FileUtils.mkdir_p(icon_path)
52
+ assign_app_icon_name
53
+ puts " ✓ 工程中没有 App 图标集,已创建: #{icon_path}"
54
+ icon_path
55
+ end
56
+
57
+ # 主 App target 配置的图标名,未配置时为 AppIcon
58
+ def app_icon_name()
59
+ names = main_app_target&.build_configurations&.map { |config| config.build_settings[APP_ICON_NAME_SETTING] } || []
60
+ name = names.compact.map(&:to_s).find { |value| !value.strip.empty? }
61
+ name || DEFAULT_APP_ICON_NAME
62
+ end
63
+
64
+ # 主 App target 使用的 asset catalog(含文件夹同步方式管理的资源)
65
+ def main_target_asset_catalogs()
66
+ target = main_app_target
67
+ return [] if target.nil?
68
+
69
+ referenced = target.resources_build_phase.files_references
70
+ .select { |file| file.respond_to?(:real_path) && file.real_path.to_s.end_with?(".xcassets") }
71
+ .map { |file| file.real_path.to_s }
72
+
73
+ synchronized = synchronized_group_paths(target).flat_map do |group_path|
74
+ Dir.glob(File.join(group_path, "**", "*.xcassets")).sort
44
75
  end
45
76
 
46
- return icon_path
77
+ (referenced + synchronized).uniq.select { |path| File.directory?(path) }
47
78
  end
48
79
 
49
80
  # 工程是否包含 AppIcon 目录(macOS 命令行工具等无 icon 工程返回 false)
@@ -68,7 +99,7 @@ module Pindo
68
99
  end
69
100
 
70
101
  def install_icon_res(new_icon_dir:nil)
71
- icon_path = get_xcodeproj_icon_path()
102
+ icon_path = ensure_app_icon_path()
72
103
  begin
73
104
  FileUtils.rm_rf(icon_path)
74
105
  FileUtils.mkdir_p(icon_path)
@@ -265,6 +296,36 @@ module Pindo
265
296
 
266
297
  end
267
298
 
299
+ private
300
+
301
+ def main_app_target()
302
+ @project_obj.targets.find do |target|
303
+ target.respond_to?(:product_type) && target.product_type.to_s.include?(Xcodeproj::Constants::PRODUCT_TYPE_UTI[:application])
304
+ end
305
+ end
306
+
307
+ # 文件夹同步(PBXFileSystemSynchronizedRootGroup)方式管理的 target 目录
308
+ def synchronized_group_paths(target)
309
+ return [] unless target.respond_to?(:file_system_synchronized_groups)
310
+
311
+ target.file_system_synchronized_groups
312
+ .map { |group| Xcodeproj::Project::Object::GroupableHelper.real_path(group).to_s }
313
+ .select { |path| File.directory?(path) }
314
+ end
315
+
316
+ # 未配置图标名的 target 补上 ASSETCATALOG_COMPILER_APPICON_NAME,使图标集参与编译
317
+ def assign_app_icon_name()
318
+ target = main_app_target
319
+ return if target.nil?
320
+
321
+ name = app_icon_name
322
+ missing = target.build_configurations.select { |config| config.build_settings[APP_ICON_NAME_SETTING].to_s.strip.empty? }
323
+ return if missing.empty?
324
+
325
+ missing.each { |config| config.build_settings[APP_ICON_NAME_SETTING] = name }
326
+ @project_obj.save
327
+ end
328
+
268
329
  end
269
330
 
270
331
  end
@@ -21,6 +21,11 @@ module Pindo
21
21
  /func\s+application\s*\([^)]*configurationForConnecting\b/
22
22
  ).freeze
23
23
 
24
+ # SwiftUI App 生命周期(@main 入口遵循 App 协议)本身基于 UIScene
25
+ SWIFTUI_APP_PATTERN = /^[ \t]*@main\b[^{]*?\b(?:struct|class|enum)\s+\w+\s*:[^{]*\bApp\b/.freeze
26
+
27
+ SCENE_ADOPTION_SOURCE_PATTERN = Regexp.union(SCENE_CONFIGURATION_PATTERN, SWIFTUI_APP_PATTERN).freeze
28
+
24
29
  SOURCE_EXTENSIONS = %w[.m .mm .swift].freeze
25
30
 
26
31
  EXCLUDED_DIRECTORY_NAMES = %w[.git Pods build DerivedData].freeze
@@ -47,7 +52,7 @@ module Pindo
47
52
  )
48
53
  return if scene_manifest_declared?(info_plist_path)
49
54
  return if scene_manifest_generated?(release_config)
50
- return if delegate_provides_scene_configuration?(project_dir)
55
+ return if sources_adopt_scene_lifecycle?(project_dir)
51
56
 
52
57
  raise Informative, adoption_error_message(sdk_version, info_plist_path)
53
58
  end
@@ -91,13 +96,19 @@ module Pindo
91
96
  # Xcode 只在 GENERATE_INFOPLIST_FILE = YES 时采用 INFOPLIST_KEY_* 设置
92
97
  def scene_manifest_generated?(release_config)
93
98
  settings = release_config.build_settings
94
- settings['GENERATE_INFOPLIST_FILE'].to_s.casecmp?('YES') &&
95
- settings[SCENE_MANIFEST_GENERATION_SETTING].to_s.casecmp?('YES')
99
+ iphoneos_setting(settings, 'GENERATE_INFOPLIST_FILE').to_s.casecmp?('YES') &&
100
+ iphoneos_setting(settings, SCENE_MANIFEST_GENERATION_SETTING).to_s.casecmp?('YES')
101
+ end
102
+
103
+ # iOS 真机构建实际生效的值:[sdk=iphoneos*] 条件设置优先于无条件设置(多平台模板只写条件设置)
104
+ def iphoneos_setting(settings, key)
105
+ _name, conditional = settings.find { |name, _value| name.start_with?("#{key}[sdk=iphoneos") }
106
+ conditional.nil? ? settings[key] : conditional
96
107
  end
97
108
 
98
- def delegate_provides_scene_configuration?(project_dir)
109
+ def sources_adopt_scene_lifecycle?(project_dir)
99
110
  each_source_file(project_dir).any? do |path|
100
- File.binread(path).match?(SCENE_CONFIGURATION_PATTERN)
111
+ File.binread(path).match?(SCENE_ADOPTION_SOURCE_PATTERN)
101
112
  end
102
113
  end
103
114
 
@@ -11,6 +11,18 @@ module Pindo
11
11
 
12
12
  class XcodeBuildConfig
13
13
 
14
+ # 未提供任何 Bundle ID 线索时,工作流推导 Bundle ID 使用的前缀
15
+ DEFAULT_BUNDLE_ID_PREFIX = "com.heroneverdie101".freeze
16
+
17
+ # 从 Bundle ID 提取前缀:通配 ID 去掉 ".*",具体 ID 去掉最后一段
18
+ # @param bundle_id [String, nil] 如 "com.example.*" 或 "com.example.app"
19
+ # @return [String, nil] 如 "com.example";无法提取时返回 nil
20
+ def self.bundle_id_prefix_from(bundle_id)
21
+ value = bundle_id.to_s.strip
22
+ prefix = value.end_with?(".*") ? value.chomp(".*") : value.rpartition(".").first
23
+ prefix.empty? || prefix.include?("*") ? nil : prefix
24
+ end
25
+
14
26
  # 使用package_name一次性更新Display Name、Bundle ID和URL Schemes(基于package_name)
15
27
  # 优化版本:只读写一次plist文件,提高性能
16
28
  # 注意:此函数只添加基于package_name的URL Scheme,基于实际Bundle ID的URL Scheme
@@ -19,8 +31,9 @@ module Pindo
19
31
  # @param workflow_packname [String] 工作流的名称(如:"Test Demo")
20
32
  # @param project_id [String] JPS项目ID(可选,用于添加快捷操作)
21
33
  # @param bundle_id [String] 显式指定的 Bundle ID(可选,来自 --bundleid)
34
+ # @param bundle_id_prefix [String] 工作流推导 Bundle ID 的前缀(可选,如 "com.example")
22
35
  # @return [Boolean] 是否成功更新
23
- def self.update_project_with_workflow(project_dir: nil, workflow_packname: nil, project_id: nil, bundle_id: nil)
36
+ def self.update_project_with_workflow(project_dir: nil, workflow_packname: nil, project_id: nil, bundle_id: nil, bundle_id_prefix: nil)
24
37
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?
25
38
  raise ArgumentError, "Workflow Package Name不能为空" if workflow_packname.nil?
26
39
 
@@ -30,10 +43,14 @@ module Pindo
30
43
 
31
44
  # Bundle ID 优先使用显式传入的值(--bundleid),未传时按工作流名推导。
32
45
  # 通配符(如 com.example.*)不能作为工程的 PRODUCT_BUNDLE_IDENTIFIER,
33
- # 与 BaseCertOperator#configure_target_build_settings 的处理保持一致,退回推导值。
46
+ # 与 BaseCertOperator#configure_target_build_settings 的处理保持一致,退回推导值,
47
+ # 推导值的前缀依次取 bundle_id_prefix、通配 ID 的前缀、默认前缀。
34
48
  explicit_bundle_id = bundle_id.to_s.strip
35
49
  use_explicit_bundle_id = !explicit_bundle_id.empty? && !explicit_bundle_id.include?("*")
36
- final_bundle_id = use_explicit_bundle_id ? explicit_bundle_id : "com.heroneverdie101.#{package_scheme}"
50
+ derived_prefix = bundle_id_prefix.to_s.strip
51
+ derived_prefix = bundle_id_prefix_from(explicit_bundle_id).to_s if derived_prefix.empty?
52
+ derived_prefix = DEFAULT_BUNDLE_ID_PREFIX if derived_prefix.empty?
53
+ final_bundle_id = use_explicit_bundle_id ? explicit_bundle_id : "#{derived_prefix}.#{package_scheme}"
37
54
 
38
55
  project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
39
56
  return false if project_fullname.nil?
@@ -315,6 +332,33 @@ module Pindo
315
332
  # @param version [String] 版本号
316
333
  # @param build_number [Integer] Build号
317
334
  # @return [Boolean] 是否成功更新
335
+ # 把纯数字版本补齐为 major.minor.patch(JPS 要求的格式),如 "1.0" => "1.0.0"
336
+ # @param version [String, nil] 工程中的版本号
337
+ # @return [String, nil] 补齐后的版本号;含变量、后缀或超过三段时返回 nil
338
+ def self.normalize_marketing_version(version)
339
+ value = version.to_s.strip
340
+ return nil unless value.match?(/\A\d+(\.\d+){0,2}\z/)
341
+
342
+ segments = value.split(".")
343
+ (segments + ["0"] * (3 - segments.size)).join(".")
344
+ end
345
+
346
+ # 读取主 App target 当前的版本号与 Build 号(Release 配置优先)
347
+ # @param project_dir [String] 项目目录
348
+ # @return [Array(String, String)] [MARKETING_VERSION, CURRENT_PROJECT_VERSION],取不到时为 nil
349
+ def self.current_app_version(project_dir:)
350
+ xcodeproj_path = find_xcodeproj(project_dir)
351
+ return [nil, nil] if xcodeproj_path.nil?
352
+
353
+ target = Xcodeproj::Project.open(xcodeproj_path).targets.find do |t|
354
+ t.respond_to?(:product_type) && t.product_type.to_s.eql?("com.apple.product-type.application")
355
+ end
356
+ return [nil, nil] if target.nil?
357
+
358
+ config = target.build_configurations.find { |c| c.name == "Release" } || target.build_configurations.first
359
+ [config.build_settings['MARKETING_VERSION'], config.build_settings['CURRENT_PROJECT_VERSION']]
360
+ end
361
+
318
362
  def self.update_ios_project_version(project_dir: nil, version: nil, build_number: nil)
319
363
  raise ArgumentError, "项目目录不能为空" if project_dir.nil?
320
364
  raise ArgumentError, "版本号不能为空" if version.nil?
data/lib/pindo/version.rb CHANGED
@@ -6,7 +6,7 @@ require 'time'
6
6
 
7
7
  module Pindo
8
8
 
9
- VERSION = "5.21.4"
9
+ VERSION = "5.21.5"
10
10
 
11
11
  class VersionCheck
12
12
  RUBYGEMS_API = 'https://rubygems.org/api/v1/gems/pindo.json'
data/lib/pindo.rb CHANGED
@@ -10,6 +10,7 @@ module Pindo
10
10
  autoload :Executable, 'pindo/base/executable'
11
11
  autoload :Plistbuddyexecutable, 'pindo/base/plistbuddyexecutable'
12
12
 
13
+ require 'pindo/base/xcodeproj_compat'
13
14
  require 'pindo/command'
14
15
  require 'pindo/version'
15
16
 
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.21.4
4
+ version: 5.21.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - wade
@@ -272,6 +272,7 @@ files:
272
272
  - lib/pindo/base/plaininformative.rb
273
273
  - lib/pindo/base/plistbuddyexecutable.rb
274
274
  - lib/pindo/base/standarderror.rb
275
+ - lib/pindo/base/xcodeproj_compat.rb
275
276
  - lib/pindo/client/applovinclient.rb
276
277
  - lib/pindo/client/aws3sclient.rb
277
278
  - lib/pindo/client/bossclient.rb