fastlane 2.229.0 → 2.230.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +100 -94
  3. data/deliver/lib/assets/summary.html.erb +3 -3
  4. data/deliver/lib/deliver/app_screenshot.rb +215 -347
  5. data/deliver/lib/deliver/app_screenshot_iterator.rb +4 -1
  6. data/deliver/lib/deliver/app_screenshot_validator.rb +5 -21
  7. data/deliver/lib/deliver/loader.rb +2 -9
  8. data/deliver/lib/deliver/upload_metadata.rb +5 -0
  9. data/deliver/lib/deliver/upload_screenshots.rb +4 -2
  10. data/fastlane/lib/fastlane/actions/docs/create_app_online.md +2 -1
  11. data/fastlane/lib/fastlane/actions/docs/sync_code_signing.md +3 -1
  12. data/fastlane/lib/fastlane/actions/docs/upload_to_app_store.md.erb +34 -6
  13. data/fastlane/lib/fastlane/actions/docs/upload_to_testflight.md +2 -0
  14. data/fastlane/lib/fastlane/actions/install_xcode_plugin.rb +3 -2
  15. data/fastlane/lib/fastlane/actions/modify_services.rb +1 -0
  16. data/fastlane/lib/fastlane/actions/notarize.rb +1 -1
  17. data/fastlane/lib/fastlane/actions/xcov.rb +1 -7
  18. data/fastlane/lib/fastlane/documentation/markdown_docs_generator.rb +4 -4
  19. data/fastlane/lib/fastlane/plugins/template/.github/workflows/test.yml +20 -20
  20. data/fastlane/lib/fastlane/version.rb +1 -1
  21. data/fastlane/swift/Deliverfile.swift +1 -1
  22. data/fastlane/swift/DeliverfileProtocol.swift +1 -1
  23. data/fastlane/swift/Fastlane.swift +85 -13
  24. data/fastlane/swift/Gymfile.swift +1 -1
  25. data/fastlane/swift/GymfileProtocol.swift +9 -1
  26. data/fastlane/swift/Matchfile.swift +1 -1
  27. data/fastlane/swift/MatchfileProtocol.swift +1 -1
  28. data/fastlane/swift/Precheckfile.swift +1 -1
  29. data/fastlane/swift/PrecheckfileProtocol.swift +1 -1
  30. data/fastlane/swift/Scanfile.swift +1 -1
  31. data/fastlane/swift/ScanfileProtocol.swift +5 -1
  32. data/fastlane/swift/Screengrabfile.swift +1 -1
  33. data/fastlane/swift/ScreengrabfileProtocol.swift +1 -1
  34. data/fastlane/swift/Snapshotfile.swift +1 -1
  35. data/fastlane/swift/SnapshotfileProtocol.swift +5 -1
  36. data/fastlane_core/lib/fastlane_core/fastlane_pty.rb +5 -1
  37. data/fastlane_core/lib/fastlane_core/ipa_upload_package_builder.rb +14 -0
  38. data/fastlane_core/lib/fastlane_core/itunes_transporter.rb +38 -8
  39. data/fastlane_core/lib/fastlane_core/project.rb +4 -0
  40. data/fastlane_core/lib/fastlane_core/provisioning_profile.rb +7 -1
  41. data/frameit/lib/frameit/device.rb +2 -2
  42. data/frameit/lib/frameit/device_types.rb +108 -70
  43. data/frameit/lib/frameit/template_finder.rb +1 -1
  44. data/gym/lib/gym/module.rb +9 -4
  45. data/gym/lib/gym/options.rb +14 -1
  46. data/gym/lib/gym/runner.rb +38 -3
  47. data/produce/lib/produce/developer_center.rb +1 -0
  48. data/produce/lib/produce/service.rb +6 -1
  49. data/scan/lib/scan/options.rb +5 -0
  50. data/scan/lib/scan/test_command_generator.rb +8 -0
  51. data/sigh/lib/sigh/local_manage.rb +6 -4
  52. data/sigh/lib/sigh/runner.rb +18 -1
  53. data/snapshot/lib/snapshot/options.rb +5 -0
  54. data/spaceship/lib/spaceship/connect_api/models/age_rating_declaration.rb +62 -8
  55. data/spaceship/lib/spaceship/connect_api/models/app_info_localization.rb +4 -4
  56. data/spaceship/lib/spaceship/connect_api/models/app_screenshot_set.rb +7 -1
  57. data/spaceship/lib/spaceship/connect_api/models/app_store_version_localization.rb +16 -16
  58. data/spaceship/lib/spaceship/connect_api/models/bundle_id_capability.rb +2 -0
  59. data/spaceship/lib/spaceship/connect_api/provisioning/provisioning.rb +0 -6
  60. data/spaceship/lib/spaceship/errors.rb +8 -6
  61. data/supply/lib/supply/client.rb +18 -1
  62. metadata +75 -29
  63. data/fastlane/lib/fastlane/core_ext/bundler_monkey_patch.rb +0 -14
  64. data/fastlane/lib/fastlane/plugins/template/.circleci/config.yml +0 -43
  65. data/fastlane/lib/fastlane/plugins/template/.travis.yml +0 -4
@@ -221,6 +221,9 @@ public protocol ScanfileProtocol: AnyObject {
221
221
  /// Sets a custom path for Swift Package Manager dependencies
222
222
  var clonedSourcePackagesPath: String? { get }
223
223
 
224
+ /// Sets a custom package cache path for Swift Package Manager dependencies
225
+ var packageCachePath: String? { get }
226
+
224
227
  /// Skips resolution of Swift Package Manager dependencies
225
228
  var skipPackageDependenciesResolution: Bool { get }
226
229
 
@@ -314,6 +317,7 @@ public extension ScanfileProtocol {
314
317
  var customReportFileName: String? { return nil }
315
318
  var xcodebuildCommand: String { return "env NSUnbufferedIO=YES xcodebuild" }
316
319
  var clonedSourcePackagesPath: String? { return nil }
320
+ var packageCachePath: String? { return nil }
317
321
  var skipPackageDependenciesResolution: Bool { return false }
318
322
  var disablePackageAutomaticUpdates: Bool { return false }
319
323
  var useSystemScm: Bool { return false }
@@ -324,4 +328,4 @@ public extension ScanfileProtocol {
324
328
 
325
329
  // Please don't remove the lines below
326
330
  // They are used to detect outdated files
327
- // FastlaneRunnerAPIVersion [0.9.145]
331
+ // FastlaneRunnerAPIVersion [0.9.147]
@@ -17,4 +17,4 @@ public class Screengrabfile: ScreengrabfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.229.0
20
+ // Generated with fastlane 2.230.0
@@ -96,4 +96,4 @@ public extension ScreengrabfileProtocol {
96
96
 
97
97
  // Please don't remove the lines below
98
98
  // They are used to detect outdated files
99
- // FastlaneRunnerAPIVersion [0.9.135]
99
+ // FastlaneRunnerAPIVersion [0.9.137]
@@ -17,4 +17,4 @@ public class Snapshotfile: SnapshotfileProtocol {
17
17
  // during the `init` process, and you won't see this message
18
18
  }
19
19
 
20
- // Generated with fastlane 2.229.0
20
+ // Generated with fastlane 2.230.0
@@ -119,6 +119,9 @@ public protocol SnapshotfileProtocol: AnyObject {
119
119
  /// Sets a custom path for Swift Package Manager dependencies
120
120
  var clonedSourcePackagesPath: String? { get }
121
121
 
122
+ /// Sets a custom package cache path for Swift Package Manager dependencies
123
+ var packageCachePath: String? { get }
124
+
122
125
  /// Skips resolution of Swift Package Manager dependencies
123
126
  var skipPackageDependenciesResolution: Bool { get }
124
127
 
@@ -193,6 +196,7 @@ public extension SnapshotfileProtocol {
193
196
  var concurrentSimulators: Bool { return true }
194
197
  var disableSlideToType: Bool { return false }
195
198
  var clonedSourcePackagesPath: String? { return nil }
199
+ var packageCachePath: String? { return nil }
196
200
  var skipPackageDependenciesResolution: Bool { return false }
197
201
  var disablePackageAutomaticUpdates: Bool { return false }
198
202
  var packageAuthorizationProvider: String? { return nil }
@@ -208,4 +212,4 @@ public extension SnapshotfileProtocol {
208
212
 
209
213
  // Please don't remove the lines below
210
214
  // They are used to detect outdated files
211
- // FastlaneRunnerAPIVersion [0.9.129]
215
+ // FastlaneRunnerAPIVersion [0.9.131]
@@ -26,8 +26,10 @@ module FastlaneCore
26
26
  spawn_with_popen(command, &block)
27
27
  end
28
28
 
29
- def self.spawn_with_pty(command, &block)
29
+ def self.spawn_with_pty(original_command, &block)
30
30
  require 'pty'
31
+ # this forces the PTY flush - fixes #21792
32
+ command = ENV['FASTLANE_EXEC_FLUSH_PTY_WORKAROUND'] ? "#{original_command};" : original_command
31
33
  PTY.spawn(command) do |command_stdout, command_stdin, pid|
32
34
  begin
33
35
  yield(command_stdout, command_stdin, pid)
@@ -37,6 +39,8 @@ module FastlaneCore
37
39
  # This is expected on some linux systems, that indicates that the subcommand finished
38
40
  # and we kept trying to read, ignore it
39
41
  ensure
42
+ command_stdin.close
43
+ command_stdout.close
40
44
  begin
41
45
  Process.wait(pid)
42
46
  rescue Errno::ECHILD, PTY::ChildExited
@@ -13,6 +13,20 @@ module FastlaneCore
13
13
  attr_accessor :package_path
14
14
 
15
15
  def generate(app_id: nil, ipa_path: nil, package_path: nil, platform: nil, app_identifier: nil, short_version: nil, bundle_version: nil)
16
+ unless Helper.is_mac?
17
+ # .itmsp packages are not supported for ipa uploads starting Transporter 4.1, for non-macOS
18
+ self.package_path = package_path
19
+ copy_ipa(ipa_path)
20
+
21
+ # copy any AppStoreInfo.plist file that's next to the ipa file
22
+ app_store_info_path = File.join(File.dirname(ipa_path), "AppStoreInfo.plist")
23
+ if File.exist?(app_store_info_path)
24
+ FileUtils.cp(app_store_info_path, File.join(self.package_path, "AppStoreInfo.plist"))
25
+ end
26
+
27
+ return self.package_path
28
+ end
29
+
16
30
  self.package_path = File.join(package_path, "#{app_id}-#{SecureRandom.uuid}.itmsp")
17
31
  FileUtils.rm_rf(self.package_path) if File.directory?(self.package_path)
18
32
  FileUtils.mkdir_p(self.package_path)
@@ -219,8 +219,8 @@ module FastlaneCore
219
219
  end
220
220
 
221
221
  def file_upload_option(source)
222
- ext = File.extname(source).downcase
223
- is_asset_file_type = !File.directory?(source) && [".ipa", ".pkg", ".dmg", ".zip"].include?(ext)
222
+ file_ext = File.extname(source).downcase
223
+ is_asset_file_type = !File.directory?(source) && allowed_package_extensions.map { |ext| ".#{ext}" }.include?(file_ext)
224
224
 
225
225
  if is_asset_file_type
226
226
  return "-assetFile #{source.shellescape}"
@@ -246,11 +246,16 @@ module FastlaneCore
246
246
  end
247
247
  return deliver_additional_params
248
248
  end
249
+
250
+ def allowed_package_extensions
251
+ ["ipa", "pkg", "dmg", "zip"]
252
+ end
249
253
  end
250
254
 
251
255
  # Generates commands and executes the altool.
252
256
  class AltoolTransporterExecutor < TransporterExecutor
253
- ERROR_REGEX = /\*\*\* Error:\s+(.+)/
257
+ # Xcode 26 uses ERROR, while previous versions used *** Error
258
+ ERROR_REGEX = /(?:\*\*\*\s*)?ERROR:\s+(.+)/i
254
259
 
255
260
  private_constant :ERROR_REGEX
256
261
 
@@ -296,7 +301,7 @@ module FastlaneCore
296
301
  end
297
302
 
298
303
  yield(@all_lines) if block_given?
299
- exit_status.zero?
304
+ @errors.empty?
300
305
  end
301
306
 
302
307
  def build_credential_params(username = nil, password = nil, jwt = nil, api_key = nil)
@@ -478,6 +483,31 @@ module FastlaneCore
478
483
  UI.error("Could not download/upload from App Store Connect! It's probably related to your password or your internet connection.")
479
484
  end
480
485
 
486
+ def file_upload_option(source)
487
+ # uploading packages on non-macOS platforms requires AppStoreInfo.plist starting with Transporter >= 4.1
488
+ if !Helper.is_mac? && File.directory?(source)
489
+ asset_file = Dir.glob(File.join(source, "*.{#{allowed_package_extensions.join(',')}}")).first
490
+ unless asset_file
491
+ UI.user_error!("No package file (#{allowed_package_extensions.join(',')}) found in #{source}")
492
+ end
493
+
494
+ appstore_info_path = File.join(source, "AppStoreInfo.plist")
495
+ unless File.file?(appstore_info_path)
496
+ UI.error("AppStoreInfo.plist is required for uploading #{File.extname(asset_file)} files on non-macOS platforms.")
497
+ UI.error("Expected AppStoreInfo.plist in the same directory as the #{File.extname(asset_file)} file.")
498
+ UI.error("Generate it by running either 'fastlane gym [...] --generate_appstore_info'")
499
+ UI.error("Or add '<key>generateAppStoreInformation</key><true/>' in an options.plist then run 'fastlane gym [...] --export_options options.plist'.")
500
+ UI.user_error!("Missing required AppStoreInfo.plist file for iTMSTransporter upload")
501
+ end
502
+
503
+ UI.verbose("Using AppStoreInfo.plist for iTMSTransporter upload: #{appstore_info_path}")
504
+ return "-assetFile #{asset_file.shellescape} -assetDescription #{appstore_info_path.shellescape}"
505
+ end
506
+
507
+ # use standard behavior for other file types or macOS platform
508
+ super(source)
509
+ end
510
+
481
511
  private
482
512
 
483
513
  def shell_escaped_password(password)
@@ -776,16 +806,16 @@ module FastlaneCore
776
806
  raise "app_id and dir are required or package_path or asset_path is required" if (app_id.nil? || dir.nil?) && package_path.nil? && asset_path.nil?
777
807
 
778
808
  # Transport can upload .ipa, .dmg, and .pkg files directly with -assetFile
779
- # However, -assetFile requires -assetDescription if Linux or Windows
780
- # This will give the asset directly if macOS and asset_path exists
781
- # otherwise it will use the .itmsp package
809
+ # However, -assetFile requires -assetDescription arguments if Linux or Windows.
810
+ # This will return the asset directly if asset_path exists,
811
+ # otherwise it will use the .itmsp package for the -f argument
782
812
 
783
813
  force_itmsp = FastlaneCore::Env.truthy?("ITMSTRANSPORTER_FORCE_ITMS_PACKAGE_UPLOAD")
784
814
  can_use_asset_path = Helper.is_mac? && asset_path
785
815
 
786
816
  actual_dir = if can_use_asset_path && !force_itmsp
787
817
  # The asset gets deleted upon completion so copying to a temp directory
788
- # (with randomized filename, for multibyte-mixed filename upload fails)
818
+ # (with randomized filename. for multibyte-mixed filename it fails to upload)
789
819
  new_file_name = "#{SecureRandom.uuid}#{File.extname(asset_path)}"
790
820
  tmp_asset_path = File.join(Dir.tmpdir, new_file_name)
791
821
  FileUtils.cp(asset_path, tmp_asset_path)
@@ -348,6 +348,10 @@ module FastlaneCore
348
348
  proj << "-clonedSourcePackagesDirPath #{options[:cloned_source_packages_path].shellescape}"
349
349
  end
350
350
 
351
+ if xcode_at_least_11 && options[:package_cache_path]
352
+ proj << "-packageCachePath #{options[:package_cache_path].shellescape}"
353
+ end
354
+
351
355
  if xcode_at_least_11 && options[:disable_package_automatic_updates]
352
356
  proj << "-disableAutomaticPackageResolution"
353
357
  end
@@ -73,7 +73,13 @@ module FastlaneCore
73
73
  end
74
74
 
75
75
  def profiles_path
76
- path = File.expand_path("~") + "/Library/MobileDevice/Provisioning Profiles/"
76
+ path = File.expand_path("~")
77
+ # Xcode 16 has a new location for provisioning profiles.
78
+ if FastlaneCore::Helper.xcode_at_least?(16)
79
+ path = File.join(path, "Library", "Developer", "Xcode", "UserData", "Provisioning Profiles")
80
+ else
81
+ path = File.join(path, "Library", "MobileDevice", "Provisioning Profiles")
82
+ end
77
83
  # If the directory doesn't exist, create it first
78
84
  unless File.directory?(path)
79
85
  FileUtils.mkdir_p(path)
@@ -71,9 +71,9 @@ module Frameit
71
71
  return nil
72
72
  end
73
73
 
74
- # Previously ENV[FRAMEIT_FORCE_DEVICE_TYPE] was matched to Deliver::AppScreenshot::ScreenSize constants. However,
74
+ # Previously ENV[FRAMEIT_FORCE_DEVICE_TYPE] was matched to Deliver::AppScreenshot display type strings.
75
75
  # options.rb defined a few Apple devices with unspecified IDs, this option was never read from Frameit.config.
76
- # Therefore this function matches both ScreenSize constants and formatted names to maintain backward compatibility.
76
+ # Therefore this function matches both DisplayType constants and formatted names to maintain backward compatibility.
77
77
  def self.find_device_by_id_or_name(id)
78
78
  return nil if id.nil?
79
79
  found_device = nil
@@ -1,8 +1,46 @@
1
1
  require_relative 'module'
2
2
  require_relative './device'
3
- require 'deliver/app_screenshot'
3
+ require 'spaceship/connect_api/models/app_screenshot_set'
4
4
 
5
5
  module Frameit
6
+ DisplayType = Spaceship::ConnectAPI::AppScreenshotSet::DisplayType
7
+
8
+ DEVICE_SCREEN_IDS = {
9
+ DisplayType::APP_IPHONE_35 => "iOS-3.5-in",
10
+ DisplayType::APP_IPHONE_40 => "iOS-4-in",
11
+ DisplayType::APP_IPHONE_47 => "iOS-4.7-in",
12
+ DisplayType::APP_IPHONE_55 => "iOS-5.5-in",
13
+ DisplayType::APP_IPHONE_58 => "iOS-5.8-in",
14
+ DisplayType::APP_IPHONE_61 => "iOS-6.1-in",
15
+ DisplayType::APP_IPHONE_65 => "iOS-6.5-in",
16
+ DisplayType::APP_IPHONE_67 => "iOS-6.7-in",
17
+ DisplayType::APP_IPAD_97 => "iOS-iPad",
18
+ DisplayType::APP_IPAD_105 => "iOS-iPad-10.5",
19
+ DisplayType::APP_IPAD_PRO_3GEN_11 => "iOS-iPad-11",
20
+ DisplayType::APP_IPAD_PRO_129 => "iOS-iPad-Pro",
21
+ DisplayType::APP_IPAD_PRO_3GEN_129 => "iOS-iPad-Pro-12.9",
22
+ DisplayType::IMESSAGE_APP_IPHONE_40 => "iOS-4-in-messages",
23
+ DisplayType::IMESSAGE_APP_IPHONE_47 => "iOS-4.7-in-messages",
24
+ DisplayType::IMESSAGE_APP_IPHONE_55 => "iOS-5.5-in-messages",
25
+ DisplayType::IMESSAGE_APP_IPHONE_58 => "iOS-5.8-in-messages",
26
+ DisplayType::IMESSAGE_APP_IPHONE_61 => "iOS-6.1-in-messages",
27
+ DisplayType::IMESSAGE_APP_IPHONE_65 => "iOS-6.5-in-messages",
28
+ DisplayType::IMESSAGE_APP_IPHONE_67 => "iOS-6.7-in-messages",
29
+ DisplayType::IMESSAGE_APP_IPAD_97 => "iOS-iPad-messages",
30
+ DisplayType::IMESSAGE_APP_IPAD_105 => "iOS-iPad-10.5-messages",
31
+ DisplayType::IMESSAGE_APP_IPAD_PRO_3GEN_11 => "iOS-iPad-11-messages",
32
+ DisplayType::IMESSAGE_APP_IPAD_PRO_129 => "iOS-iPad-Pro-messages",
33
+ DisplayType::IMESSAGE_APP_IPAD_PRO_3GEN_129 => "iOS-iPad-Pro-12.9-messages",
34
+ DisplayType::APP_WATCH_SERIES_3 => "iOS-Apple-Watch",
35
+ DisplayType::APP_WATCH_SERIES_4 => "iOS-Apple-Watch-Series4",
36
+ DisplayType::APP_WATCH_SERIES_7 => "iOS-Apple-Watch-Series7",
37
+ DisplayType::APP_WATCH_SERIES_10 => "iOS-Apple-Watch-Series10",
38
+ DisplayType::APP_WATCH_ULTRA => "iOS-Apple-Watch-Ultra",
39
+ DisplayType::APP_APPLE_TV => "Apple-TV",
40
+ DisplayType::APP_DESKTOP => "Mac",
41
+ DisplayType::APP_APPLE_VISION_PRO => "visionOS-Vision-Pro"
42
+ }.freeze
43
+
6
44
  module Color
7
45
  MATTE_BLACK ||= "Matte Black"
8
46
  SPACE_GRAY ||= "Space Gray"
@@ -81,80 +119,80 @@ module Frameit
81
119
  end
82
120
 
83
121
  module Devices
84
- GOOGLE_PIXEL_3 ||= Frameit::Device.new("google-pixel-3", "Google Pixel 3", 7, [[1080, 2160], [2160, 1080]], 443, Color::JUST_BLACK, Platform::ANDROID)
85
- GOOGLE_PIXEL_3_XL ||= Frameit::Device.new("google-pixel-3-xl", "Google Pixel 3 XL", 7, [[1440, 2960], [2960, 1440]], 523, Color::JUST_BLACK, Platform::ANDROID)
122
+ GOOGLE_PIXEL_3 ||= Device.new("google-pixel-3", "Google Pixel 3", 7, [[1080, 2160], [2160, 1080]], 443, Color::JUST_BLACK, Platform::ANDROID)
123
+ GOOGLE_PIXEL_3_XL ||= Device.new("google-pixel-3-xl", "Google Pixel 3 XL", 7, [[1440, 2960], [2960, 1440]], 523, Color::JUST_BLACK, Platform::ANDROID)
86
124
  # Google Pixel 4's priority should be higher than Samsung Galaxy S10+ (priority 8):
87
- GOOGLE_PIXEL_4 ||= Frameit::Device.new("google-pixel-4", "Google Pixel 4", 9, [[1080, 2280], [2280, 1080]], 444, Color::JUST_BLACK, Platform::ANDROID)
88
- GOOGLE_PIXEL_4_XL ||= Frameit::Device.new("google-pixel-4-xl", "Google Pixel 4 XL", 9, [[1440, 3040], [3040, 1440]], 537, Color::JUST_BLACK, Platform::ANDROID)
89
- GOOGLE_PIXEL_5 ||= Frameit::Device.new("google-pixel-5", "Google Pixel 5", 10, [[1080, 2340], [2340, 1080]], 432, Color::JUST_BLACK, Platform::ANDROID)
90
- HTC_ONE_A9 ||= Frameit::Device.new("htc-one-a9", "HTC One A9", 6, [[1080, 1920], [1920, 1080]], 441, Color::BLACK, Platform::ANDROID)
91
- HTC_ONE_M8 ||= Frameit::Device.new("htc-one-m8", "HTC One M8", 3, [[1080, 1920], [1920, 1080]], 441, Color::BLACK, Platform::ANDROID)
92
- HUAWEI_P8 ||= Frameit::Device.new("huawei-p8", "Huawei P8", 5, [[1080, 1920], [1920, 1080]], 424, Color::BLACK, Platform::ANDROID)
93
- MOTOROLA_MOTO_E ||= Frameit::Device.new("motorola-moto-e", "Motorola Moto E", 3, [[540, 960], [960, 540]], 245, Color::BLACK, Platform::ANDROID)
94
- MOTOROLA_MOTO_G ||= Frameit::Device.new("motorola-moto-g", "Motorola Moto G", 4, [[1080, 1920], [1920, 1080]], 401, nil, Platform::ANDROID, nil)
95
- NEXUS_4 ||= Frameit::Device.new("nexus-4", "Nexus 4", 7, [[768, 1280], [1820, 768]], 318, nil, Platform::ANDROID)
96
- NEXUS_5X ||= Frameit::Device.new("nexus-5x", "Nexus 5X", 7, [[1080, 1920], [1920, 1080]], 423, nil, Platform::ANDROID)
97
- NEXUS_6P ||= Frameit::Device.new("nexus-6p", "Nexus 6P", 7, [[1440, 2560], [2560, 1440]], 518, nil, Platform::ANDROID)
98
- NEXUS_9 ||= Frameit::Device.new("nexus-9", "Nexus 9", 7, [[1536, 2048], [2048, 1536]], 281, nil, Platform::ANDROID)
99
- SAMSUNG_GALAXY_GRAND_PRIME ||= Frameit::Device.new("samsung-galaxy-grand-prime", "Samsung Galaxy Grand Prime", 5, [[540, 960], [960, 540]], 220, Color::BLACK, Platform::ANDROID)
100
- SAMSUNG_GALAXY_NOTE_5 ||= Frameit::Device.new("samsung-galaxy-note-5", "Samsung Galaxy Note 5", 5, [[1440, 2560], [2560, 1440]], 518, Color::BLACK, Platform::ANDROID)
101
- SAMSUNG_GALAXY_NOTE_10 ||= Frameit::Device.new("samsung-galaxy-note-10", "Samsung Galaxy Note 10", 6, [[1080, 2280], [2280, 1080]], 401, Color::AURA_BLACK, Platform::ANDROID)
102
- SAMSUNG_GALAXY_NOTE_10_PLUS ||= Frameit::Device.new("samsung-galaxy-note-10-plus", "Samsung Galaxy Note 10+", 7, [[1440, 3040], [3040, 1440]], 498, Color::AURA_BLACK, Platform::ANDROID)
103
- SAMSUNG_GALAXY_S_DUOS ||= Frameit::Device.new("samsung-galaxy-s-duos", "Samsung Galaxy S Duos", 3, [[480, 800], [800, 480]], 233, nil, Platform::ANDROID)
104
- SAMSUNG_GALAXY_S3 ||= Frameit::Device.new("samsung-galaxy-s3", "Samsung Galaxy S3", 3, [[720, 1280], [1280, 720]], 306, nil, Platform::ANDROID)
105
- SAMSUNG_GALAXY_S5 ||= Frameit::Device.new("samsung-galaxy-s5", "Samsung Galaxy S5", 3, [[1080, 1920], [1920, 1080]], 432, Color::BLACK, Platform::ANDROID)
106
- SAMSUNG_GALAXY_S7 ||= Frameit::Device.new("samsung-galaxy-s7", "Samsung Galaxy S7", 4, [[1440, 2560], [2560, 1440]], 577, Color::BLACK, Platform::ANDROID)
107
- SAMSUNG_GALAXY_S8 ||= Frameit::Device.new("samsung-galaxy-s8", "Samsung Galaxy S8", 5, [[1440, 2960], [2960, 1440]], 570, Color::MIDNIGHT_BLACK, Platform::ANDROID)
108
- SAMSUNG_GALAXY_S9 ||= Frameit::Device.new("samsung-galaxy-s9", "Samsung Galaxy S9", 6, [[1440, 2960], [2960, 1440]], 570, Color::MIDNIGHT_BLACK, Platform::ANDROID)
109
- SAMSUNG_GALAXY_S10 ||= Frameit::Device.new("samsung-galaxy-s10", "Samsung Galaxy S10", 7, [[1440, 3040], [3040, 1440]], 550, Color::PRISM_BLACK, Platform::ANDROID)
110
- SAMSUNG_GALAXY_S10_PLUS ||= Frameit::Device.new("samsung-galaxy-s10-plus", "Samsung Galaxy S10+", 8, [[1440, 3040], [3040, 1440]], 522, Color::PRISM_BLACK, Platform::ANDROID)
111
- XIAOMI_MI_MIX_ALPHA ||= Frameit::Device.new("xiaomi-mi-mix-alpha", "Xiaomi Mi Mix Alpha", 1, [[2088, 2250], [2250, 2088]], 388, nil, Platform::ANDROID)
112
- IPHONE_5S ||= Frameit::Device.new("iphone-5s", "Apple iPhone 5s", 2, [[640, 1096], [640, 1136], [1136, 600], [1136, 640]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_40, :use_legacy_iphone5s)
113
- IPHONE_5C ||= Frameit::Device.new("iphone-5c", "Apple iPhone 5c", 2, [[640, 1136], [1136, 640]], 326, Color::WHITE)
114
- IPHONE_SE ||= Frameit::Device.new("iphone-se", "Apple iPhone SE", 3, [[640, 1096], [640, 1136], [1136, 600], [1136, 640]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_40)
115
- IPHONE_6S ||= Frameit::Device.new("iphone-6s", "Apple iPhone 6s", 4, [[750, 1334], [1334, 750]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_47, :use_legacy_iphone6s)
116
- IPHONE_6S_PLUS ||= Frameit::Device.new("iphone-6s-plus", "Apple iPhone 6s Plus", 4, [[1242, 2208], [2208, 1242]], 401, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_55, :use_legacy_iphone6s)
117
- IPHONE_7 ||= Frameit::Device.new("iphone-7", "Apple iPhone 7", 5, [[750, 1334], [1334, 750]], 326, Color::MATTE_BLACK, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_47, :use_legacy_iphone7)
118
- IPHONE_7_PLUS ||= Frameit::Device.new("iphone-7-plus", "Apple iPhone 7 Plus", 5, [[1242, 2208], [2208, 1242]], 401, Color::MATTE_BLACK, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_55, :use_legacy_iphone7)
119
- IPHONE_8 ||= Frameit::Device.new("iphone-8", "Apple iPhone 8", 6, [[750, 1334], [1334, 750]], 326, Color::SPACE_GRAY)
120
- IPHONE_8_PLUS ||= Frameit::Device.new("iphone-8-plus", "Apple iPhone 8 Plus", 6, [[1242, 2208], [2208, 1242]], 401, Color::SPACE_GRAY)
121
- IPHONE_X ||= Frameit::Device.new("iphone-X", "Apple iPhone X", 7, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_58, :use_legacy_iphonex)
122
- IPHONE_XS ||= Frameit::Device.new("iphone-XS", "Apple iPhone XS", 8, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_58, :use_legacy_iphonexs)
123
- IPHONE_XR ||= Frameit::Device.new("iphone-XR", "Apple iPhone XR", 8, [[828, 1792], [1792, 828]], 326, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_65, :use_legacy_iphonexsmax)
124
- IPHONE_XS_MAX ||= Frameit::Device.new("iphone-XS-Max", "Apple iPhone XS Max", 8, [[1242, 2688], [2688, 1242]], 458, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_65, :use_legacy_iphonexsmax)
125
- IPHONE_11 ||= Frameit::Device.new("iphone-11", "Apple iPhone 11", 9, [[828, 1792], [1792, 828]], 326, Color::BLACK, Platform::IOS)
126
- IPHONE_11_PRO ||= Frameit::Device.new("iphone-11-pro", "Apple iPhone 11 Pro", 9, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS)
127
- IPHONE_11_PRO_MAX ||= Frameit::Device.new("iphone11-pro-max", "Apple iPhone 11 Pro Max", 9, [[1242, 2688], [2688, 1242]], 458, Color::SPACE_GRAY, Platform::IOS)
128
- IPHONE_12 ||= Frameit::Device.new("iphone-12", "Apple iPhone 12", 10, [[1170, 2532], [2532, 1170]], 460, Color::BLACK, Platform::IOS)
129
- IPHONE_12_PRO ||= Frameit::Device.new("iphone-12-pro", "Apple iPhone 12 Pro", 10, [[1170, 2532], [2532, 1170]], 460, Color::SPACE_GRAY, Platform::IOS)
130
- IPHONE_12_PRO_MAX ||= Frameit::Device.new("iphone12-pro-max", "Apple iPhone 12 Pro Max", 10, [[1284, 2778], [2778, 1284]], 458, Color::GRAPHITE, Platform::IOS)
131
- IPHONE_12_MINI ||= Frameit::Device.new("iphone-12-mini", "Apple iPhone 12 Mini", 10, [[1125, 2436], [2436, 1125]], 476, Color::BLACK, Platform::IOS)
132
- IPHONE_13 ||= Frameit::Device.new("iphone-13", "Apple iPhone 13", 11, [[1170, 2532], [2532, 1170]], 460, Color::MIDNIGHT, Platform::IOS)
133
- IPHONE_13_PRO ||= Frameit::Device.new("iphone-13-pro", "Apple iPhone 13 Pro", 11, [[1170, 2532], [2532, 1170]], 460, Color::GRAPHITE, Platform::IOS)
134
- IPHONE_13_PRO_MAX ||= Frameit::Device.new("iphone13-pro-max", "Apple iPhone 13 Pro Max", 11, [[1284, 2778], [2778, 1284]], 458, Color::GRAPHITE, Platform::IOS)
135
- IPHONE_13_MINI ||= Frameit::Device.new("iphone-13-mini", "Apple iPhone 13 Mini", 11, [[1080, 2340], [2340, 1080]], 476, Color::MIDNIGHT, Platform::IOS)
136
- IPHONE_14 ||= Frameit::Device.new("iphone-14", "Apple iPhone 14", 12, [[1170, 2532], [2532, 1170]], 460, Color::MIDNIGHT, Platform::IOS)
137
- IPHONE_14_PLUS ||= Frameit::Device.new("iphone-14-plus", "Apple iPhone 14 Plus", 12, [[1284, 2778], [2778, 1284]], 458, Color::MIDNIGHT, Platform::IOS)
138
- IPHONE_14_PRO ||= Frameit::Device.new("iphone-14-pro", "Apple iPhone 14 Pro", 12, [[1178, 2556], [2556, 1178]], 460, Color::PURPLE, Platform::IOS)
139
- IPHONE_14_PRO_MAX ||= Frameit::Device.new("iphone14-pro-max", "Apple iPhone 14 Pro Max", 12, [[1290, 2796], [2796, 1290]], 458, Color::PURPLE, Platform::IOS)
140
- IPAD_10_2 ||= Frameit::Device.new("ipad-10-2", "Apple iPad 10.2", 1, [[1620, 2160], [2160, 1620]], 264, Color::SPACE_GRAY, Platform::IOS)
141
- IPAD_AIR_2 ||= Frameit::Device.new("ipad-air-2", "Apple iPad Air 2", 1, [[1536, 2048], [2048, 1536]], 264, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD)
142
- IPAD_AIR_2019 ||= Frameit::Device.new("ipad-air-2019", "Apple iPad Air (2019)", 2, [[1668, 2224], [2224, 1668]], 265, Color::SPACE_GRAY, Platform::IOS)
143
- IPAD_MINI_4 ||= Frameit::Device.new("ipad-mini-4", "Apple iPad Mini 4", 2, [[1536, 2048], [2048, 1536]], 324, Color::SPACE_GRAY)
144
- IPAD_MINI_2019 ||= Frameit::Device.new("ipad-mini-2019", "Apple iPad Mini (2019)", 3, [[1536, 2048], [2048, 1536]], 324, Color::SPACE_GRAY)
145
- # this is 1st or 2nd gen of iPad Pro 12.9:
146
- IPAD_PRO ||= Frameit::Device.new("ipad-pro", "Apple iPad Pro", 3, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD_PRO)
147
- # 3rd generation:
148
- IPAD_PRO_12_9 ||= Frameit::Device.new("ipadPro129", "Apple iPad Pro (12.9-inch) (3rd generation)", 4, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD_PRO_12_9)
149
- # 4th generation:
150
- IPAD_PRO_12_9_4 ||= Frameit::Device.new("ipadPro129", "Apple iPad Pro (12.9-inch) (4th generation)", 5, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD_PRO_12_9)
125
+ GOOGLE_PIXEL_4 ||= Device.new("google-pixel-4", "Google Pixel 4", 9, [[1080, 2280], [2280, 1080]], 444, Color::JUST_BLACK, Platform::ANDROID)
126
+ GOOGLE_PIXEL_4_XL ||= Device.new("google-pixel-4-xl", "Google Pixel 4 XL", 9, [[1440, 3040], [3040, 1440]], 537, Color::JUST_BLACK, Platform::ANDROID)
127
+ GOOGLE_PIXEL_5 ||= Device.new("google-pixel-5", "Google Pixel 5", 10, [[1080, 2340], [2340, 1080]], 432, Color::JUST_BLACK, Platform::ANDROID)
128
+ HTC_ONE_A9 ||= Device.new("htc-one-a9", "HTC One A9", 6, [[1080, 1920], [1920, 1080]], 441, Color::BLACK, Platform::ANDROID)
129
+ HTC_ONE_M8 ||= Device.new("htc-one-m8", "HTC One M8", 3, [[1080, 1920], [1920, 1080]], 441, Color::BLACK, Platform::ANDROID)
130
+ HUAWEI_P8 ||= Device.new("huawei-p8", "Huawei P8", 5, [[1080, 1920], [1920, 1080]], 424, Color::BLACK, Platform::ANDROID)
131
+ MOTOROLA_MOTO_E ||= Device.new("motorola-moto-e", "Motorola Moto E", 3, [[540, 960], [960, 540]], 245, Color::BLACK, Platform::ANDROID)
132
+ MOTOROLA_MOTO_G ||= Device.new("motorola-moto-g", "Motorola Moto G", 4, [[1080, 1920], [1920, 1080]], 401, nil, Platform::ANDROID, nil)
133
+ NEXUS_4 ||= Device.new("nexus-4", "Nexus 4", 7, [[768, 1280], [1820, 768]], 318, nil, Platform::ANDROID)
134
+ NEXUS_5X ||= Device.new("nexus-5x", "Nexus 5X", 7, [[1080, 1920], [1920, 1080]], 423, nil, Platform::ANDROID)
135
+ NEXUS_6P ||= Device.new("nexus-6p", "Nexus 6P", 7, [[1440, 2560], [2560, 1440]], 518, nil, Platform::ANDROID)
136
+ NEXUS_9 ||= Device.new("nexus-9", "Nexus 9", 7, [[1536, 2048], [2048, 1536]], 281, nil, Platform::ANDROID)
137
+ SAMSUNG_GALAXY_GRAND_PRIME ||= Device.new("samsung-galaxy-grand-prime", "Samsung Galaxy Grand Prime", 5, [[540, 960], [960, 540]], 220, Color::BLACK, Platform::ANDROID)
138
+ SAMSUNG_GALAXY_NOTE_5 ||= Device.new("samsung-galaxy-note-5", "Samsung Galaxy Note 5", 5, [[1440, 2560], [2560, 1440]], 518, Color::BLACK, Platform::ANDROID)
139
+ SAMSUNG_GALAXY_NOTE_10 ||= Device.new("samsung-galaxy-note-10", "Samsung Galaxy Note 10", 6, [[1080, 2280], [2280, 1080]], 401, Color::AURA_BLACK, Platform::ANDROID)
140
+ SAMSUNG_GALAXY_NOTE_10_PLUS ||= Device.new("samsung-galaxy-note-10-plus", "Samsung Galaxy Note 10+", 7, [[1440, 3040], [3040, 1440]], 498, Color::AURA_BLACK, Platform::ANDROID)
141
+ SAMSUNG_GALAXY_S_DUOS ||= Device.new("samsung-galaxy-s-duos", "Samsung Galaxy S Duos", 3, [[480, 800], [800, 480]], 233, nil, Platform::ANDROID)
142
+ SAMSUNG_GALAXY_S3 ||= Device.new("samsung-galaxy-s3", "Samsung Galaxy S3", 3, [[720, 1280], [1280, 720]], 306, nil, Platform::ANDROID)
143
+ SAMSUNG_GALAXY_S5 ||= Device.new("samsung-galaxy-s5", "Samsung Galaxy S5", 3, [[1080, 1920], [1920, 1080]], 432, Color::BLACK, Platform::ANDROID)
144
+ SAMSUNG_GALAXY_S7 ||= Device.new("samsung-galaxy-s7", "Samsung Galaxy S7", 4, [[1440, 2560], [2560, 1440]], 577, Color::BLACK, Platform::ANDROID)
145
+ SAMSUNG_GALAXY_S8 ||= Device.new("samsung-galaxy-s8", "Samsung Galaxy S8", 5, [[1440, 2960], [2960, 1440]], 570, Color::MIDNIGHT_BLACK, Platform::ANDROID)
146
+ SAMSUNG_GALAXY_S9 ||= Device.new("samsung-galaxy-s9", "Samsung Galaxy S9", 6, [[1440, 2960], [2960, 1440]], 570, Color::MIDNIGHT_BLACK, Platform::ANDROID)
147
+ SAMSUNG_GALAXY_S10 ||= Device.new("samsung-galaxy-s10", "Samsung Galaxy S10", 7, [[1440, 3040], [3040, 1440]], 550, Color::PRISM_BLACK, Platform::ANDROID)
148
+ SAMSUNG_GALAXY_S10_PLUS ||= Device.new("samsung-galaxy-s10-plus", "Samsung Galaxy S10+", 8, [[1440, 3040], [3040, 1440]], 522, Color::PRISM_BLACK, Platform::ANDROID)
149
+ XIAOMI_MI_MIX_ALPHA ||= Device.new("xiaomi-mi-mix-alpha", "Xiaomi Mi Mix Alpha", 1, [[2088, 2250], [2250, 2088]], 388, nil, Platform::ANDROID)
150
+ IPHONE_5S ||= Device.new("iphone-5s", "Apple iPhone 5s", 2, [[640, 1096], [640, 1136], [1136, 600], [1136, 640]], 326, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_40], :use_legacy_iphone5s)
151
+ IPHONE_5C ||= Device.new("iphone-5c", "Apple iPhone 5c", 2, [[640, 1136], [1136, 640]], 326, Color::WHITE)
152
+ IPHONE_SE ||= Device.new("iphone-se", "Apple iPhone SE", 3, [[640, 1096], [640, 1136], [1136, 600], [1136, 640]], 326, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_40])
153
+ IPHONE_6S ||= Device.new("iphone-6s", "Apple iPhone 6s", 4, [[750, 1334], [1334, 750]], 326, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_47], :use_legacy_iphone6s)
154
+ IPHONE_6S_PLUS ||= Device.new("iphone-6s-plus", "Apple iPhone 6s Plus", 4, [[1242, 2208], [2208, 1242]], 401, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_55], :use_legacy_iphone6s)
155
+ IPHONE_7 ||= Device.new("iphone-7", "Apple iPhone 7", 5, [[750, 1334], [1334, 750]], 326, Color::MATTE_BLACK, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_47], :use_legacy_iphone7)
156
+ IPHONE_7_PLUS ||= Device.new("iphone-7-plus", "Apple iPhone 7 Plus", 5, [[1242, 2208], [2208, 1242]], 401, Color::MATTE_BLACK, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_55], :use_legacy_iphone7)
157
+ IPHONE_8 ||= Device.new("iphone-8", "Apple iPhone 8", 6, [[750, 1334], [1334, 750]], 326, Color::SPACE_GRAY)
158
+ IPHONE_8_PLUS ||= Device.new("iphone-8-plus", "Apple iPhone 8 Plus", 6, [[1242, 2208], [2208, 1242]], 401, Color::SPACE_GRAY)
159
+ IPHONE_X ||= Device.new("iphone-X", "Apple iPhone X", 7, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_58], :use_legacy_iphonex)
160
+ IPHONE_XS ||= Device.new("iphone-XS", "Apple iPhone XS", 8, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_58], :use_legacy_iphonexs)
161
+ IPHONE_XR ||= Device.new("iphone-XR", "Apple iPhone XR", 8, [[828, 1792], [1792, 828]], 326, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_65], :use_legacy_iphonexsmax)
162
+ IPHONE_XS_MAX ||= Device.new("iphone-XS-Max", "Apple iPhone XS Max", 8, [[1242, 2688], [2688, 1242]], 458, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_65], :use_legacy_iphonexsmax)
163
+ IPHONE_11 ||= Device.new("iphone-11", "Apple iPhone 11", 9, [[828, 1792], [1792, 828]], 326, Color::BLACK, Platform::IOS)
164
+ IPHONE_11_PRO ||= Device.new("iphone-11-pro", "Apple iPhone 11 Pro", 9, [[1125, 2436], [2436, 1125]], 458, Color::SPACE_GRAY, Platform::IOS)
165
+ IPHONE_11_PRO_MAX ||= Device.new("iphone11-pro-max", "Apple iPhone 11 Pro Max", 9, [[1242, 2688], [2688, 1242]], 458, Color::SPACE_GRAY, Platform::IOS)
166
+ IPHONE_12 ||= Device.new("iphone-12", "Apple iPhone 12", 10, [[1170, 2532], [2532, 1170]], 460, Color::BLACK, Platform::IOS)
167
+ IPHONE_12_PRO ||= Device.new("iphone-12-pro", "Apple iPhone 12 Pro", 10, [[1170, 2532], [2532, 1170]], 460, Color::SPACE_GRAY, Platform::IOS)
168
+ IPHONE_12_PRO_MAX ||= Device.new("iphone12-pro-max", "Apple iPhone 12 Pro Max", 10, [[1284, 2778], [2778, 1284]], 458, Color::GRAPHITE, Platform::IOS)
169
+ IPHONE_12_MINI ||= Device.new("iphone-12-mini", "Apple iPhone 12 Mini", 10, [[1125, 2436], [2436, 1125]], 476, Color::BLACK, Platform::IOS)
170
+ IPHONE_13 ||= Device.new("iphone-13", "Apple iPhone 13", 11, [[1170, 2532], [2532, 1170]], 460, Color::MIDNIGHT, Platform::IOS)
171
+ IPHONE_13_PRO ||= Device.new("iphone-13-pro", "Apple iPhone 13 Pro", 11, [[1170, 2532], [2532, 1170]], 460, Color::GRAPHITE, Platform::IOS)
172
+ IPHONE_13_PRO_MAX ||= Device.new("iphone13-pro-max", "Apple iPhone 13 Pro Max", 11, [[1284, 2778], [2778, 1284]], 458, Color::GRAPHITE, Platform::IOS)
173
+ IPHONE_13_MINI ||= Device.new("iphone-13-mini", "Apple iPhone 13 Mini", 11, [[1080, 2340], [2340, 1080]], 476, Color::MIDNIGHT, Platform::IOS)
174
+ IPHONE_14 ||= Device.new("iphone-14", "Apple iPhone 14", 12, [[1170, 2532], [2532, 1170]], 460, Color::MIDNIGHT, Platform::IOS)
175
+ IPHONE_14_PLUS ||= Device.new("iphone-14-plus", "Apple iPhone 14 Plus", 12, [[1284, 2778], [2778, 1284]], 458, Color::MIDNIGHT, Platform::IOS)
176
+ IPHONE_14_PRO ||= Device.new("iphone-14-pro", "Apple iPhone 14 Pro", 12, [[1179, 2556], [2556, 1179]], 460, Color::PURPLE, Platform::IOS)
177
+ IPHONE_14_PRO_MAX ||= Device.new("iphone14-pro-max", "Apple iPhone 14 Pro Max", 12, [[1290, 2796], [2796, 1290]], 458, Color::PURPLE, Platform::IOS)
178
+ IPAD_10_2 ||= Device.new("ipad-10-2", "Apple iPad 10.2", 1, [[1620, 2160], [2160, 1620]], 264, Color::SPACE_GRAY, Platform::IOS)
179
+ IPAD_AIR_2 ||= Device.new("ipad-air-2", "Apple iPad Air 2", 1, [[1536, 2048], [2048, 1536]], 264, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_97])
180
+ IPAD_AIR_2019 ||= Device.new("ipad-air-2019", "Apple iPad Air (2019)", 2, [[1668, 2224], [2224, 1668]], 265, Color::SPACE_GRAY, Platform::IOS)
181
+ IPAD_MINI_4 ||= Device.new("ipad-mini-4", "Apple iPad Mini 4", 2, [[1536, 2048], [2048, 1536]], 324, Color::SPACE_GRAY)
182
+ IPAD_MINI_2019 ||= Device.new("ipad-mini-2019", "Apple iPad Mini (2019)", 3, [[1536, 2048], [2048, 1536]], 324, Color::SPACE_GRAY)
183
+ # iPad Pro 12.9" (2nd gen):
184
+ IPAD_PRO ||= Device.new("ipad-pro", "Apple iPad Pro", 3, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_PRO_129])
185
+ # iPad Pro 13" (3rd gen - rebranded from 12.9"):
186
+ IPAD_PRO_12_9 ||= Device.new("ipadPro129", "Apple iPad Pro (12.9-inch) (3rd generation)", 4, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_PRO_3GEN_129])
187
+ # iPad Pro 13" (4th gen):
188
+ IPAD_PRO_12_9_4 ||= Device.new("ipadPro129", "Apple iPad Pro (12.9-inch) (4th generation)", 5, [[2048, 2732], [2732, 2048]], 264, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_PRO_3GEN_129])
151
189
  # iPad Pro (10.5-inch) is not in frameit-frames repo, but must be included so that we are backward compatible with PR #15373
152
190
  # priority must be lower so that users who didn't copy the frame to their frameit frames folder will not get an error
153
191
  # ID and formatted name must be exactly as specified so that device.detect_device() will select this device if the filename includes them
154
- IPAD_PRO_10_5 ||= Frameit::Device.new("ipad105", "Apple iPad Pro (10.5-inch)", 1, [[1668, 2224], [2224, 1668]], 265, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD_10_5)
155
- IPAD_PRO_11 ||= Frameit::Device.new("ipadPro11", "Apple iPad Pro (11-inch)", 1, [[1668, 2388], [2388, 1668]], 265, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::IOS_IPAD_11)
192
+ IPAD_PRO_10_5 ||= Device.new("ipad105", "Apple iPad Pro (10.5-inch)", 1, [[1668, 2224], [2224, 1668]], 265, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_105])
193
+ IPAD_PRO_11 ||= Device.new("ipadPro11", "Apple iPad Pro (11-inch)", 1, [[1668, 2388], [2388, 1668]], 265, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_IPAD_PRO_3GEN_11])
156
194
 
157
- MAC ||= Frameit::Device.new("mac", "Apple MacBook", 0, [[1280, 800], [1440, 900], [2560, 1600], [2880, 1800]], nil, Color::SPACE_GRAY, Platform::IOS, Deliver::AppScreenshot::ScreenSize::MAC)
195
+ MAC ||= Device.new("mac", "Apple MacBook", 0, [[1280, 800], [1440, 900], [2560, 1600], [2880, 1800]], nil, Color::SPACE_GRAY, Platform::IOS, DEVICE_SCREEN_IDS[DisplayType::APP_DESKTOP])
158
196
 
159
197
  def self.all_device_names_without_apple
160
198
  Devices.constants.map { |c| Devices.const_get(c).formatted_name_without_apple }
@@ -24,7 +24,7 @@ module Frameit
24
24
  end
25
25
 
26
26
  if templates.count == 0
27
- if screenshot.deliver_screen_id == Deliver::AppScreenshot::ScreenSize::IOS_35
27
+ if screenshot.deliver_screen_id == DEVICE_SCREEN_IDS[DisplayType::APP_IPHONE_35]
28
28
  UI.important("Unfortunately 3.5\" device frames were discontinued. Skipping screen '#{screenshot.path}'")
29
29
  UI.error("Looked for: '#{filename}.png'")
30
30
  else
@@ -25,6 +25,14 @@ module Gym
25
25
  require 'gym/xcodebuild_fixes/generic_archive_fix'
26
26
  end
27
27
 
28
+ def building_for_ipa?
29
+ return !building_for_pkg?
30
+ end
31
+
32
+ def building_for_pkg?
33
+ return building_for_mac?
34
+ end
35
+
28
36
  def building_for_ios?
29
37
  if Gym.project.mac?
30
38
  # Can be building for iOS if mac project and catalyst or multiplatform and set to iOS
@@ -43,10 +51,7 @@ module Gym
43
51
  # Can be a mac project and not build mac if catalyst
44
52
  return building_mac_catalyst_for_mac?
45
53
  else
46
- # Can be mac project but multiplatform and building for iOS
47
- return false if building_multiplatform_for_ios?
48
-
49
- return Gym.project.mac?
54
+ return (!Gym.project.multiplatform? && Gym.project.mac?) || building_multiplatform_for_mac?
50
55
  end
51
56
  end
52
57
 
@@ -4,6 +4,7 @@ require 'credentials_manager/appfile_config'
4
4
  require_relative 'module'
5
5
 
6
6
  module Gym
7
+ # rubocop:disable Metrics/ClassLength
7
8
  class Options
8
9
  def self.available_options
9
10
  return @options if @options
@@ -305,6 +306,11 @@ module Gym
305
306
  description: "Sets a custom path for Swift Package Manager dependencies",
306
307
  type: String,
307
308
  optional: true),
309
+ FastlaneCore::ConfigItem.new(key: :package_cache_path,
310
+ env_name: "GYM_PACKAGE_CACHE_PATH",
311
+ description: "Sets a custom package cache path for Swift Package Manager dependencies",
312
+ type: String,
313
+ optional: true),
308
314
  FastlaneCore::ConfigItem.new(key: :skip_package_dependencies_resolution,
309
315
  env_name: "GYM_SKIP_PACKAGE_DEPENDENCIES_RESOLUTION",
310
316
  description: "Skips resolution of Swift Package Manager dependencies",
@@ -329,8 +335,15 @@ module Gym
329
335
  verify_block: proc do |value|
330
336
  av = %w(netrc keychain)
331
337
  UI.user_error!("Unsupported authorization provider '#{value}', must be: #{av}") unless av.include?(value)
332
- end)
338
+ end),
339
+ FastlaneCore::ConfigItem.new(key: :generate_appstore_info,
340
+ env_name: "GYM_GENERATE_APPSTORE_INFO",
341
+ description: "Generate AppStoreInfo.plist using swinfo for app-store exports",
342
+ type: Boolean,
343
+ optional: true,
344
+ default_value: false)
333
345
  ]
334
346
  end
335
347
  end
348
+ # rubocop:enable Metrics/ClassLength
336
349
  end
@@ -24,7 +24,7 @@ module Gym
24
24
  FileUtils.mkdir_p(File.expand_path(Gym.config[:output_directory]))
25
25
 
26
26
  # Archive
27
- if Gym.building_for_ios?
27
+ if Gym.building_for_ipa?
28
28
  fix_generic_archive unless Gym.project.watchos? # See https://github.com/fastlane/fastlane/pull/4325
29
29
  return BuildCommandGenerator.archive_path if Gym.config[:skip_package_ipa]
30
30
 
@@ -38,9 +38,10 @@ module Gym
38
38
  move_app_thinning_size_report
39
39
  move_apps_folder
40
40
  move_asset_packs
41
- move_appstore_info
41
+ appstore_info_path = move_appstore_info
42
+ generate_appstore_info(path) unless appstore_info_path
42
43
  end
43
- elsif Gym.building_for_mac?
44
+ elsif Gym.building_for_pkg?
44
45
  path = File.expand_path(Gym.config[:output_directory])
45
46
  compress_and_move_dsym
46
47
  if Gym.project.mac_app? || Gym.building_mac_catalyst_for_mac?
@@ -369,6 +370,40 @@ module Gym
369
370
  end
370
371
  end
371
372
 
373
+ # Create AppStoreInfo.plist using swinfo for iOS app-store exports
374
+ def generate_appstore_info(ipa_path)
375
+ return unless Gym.config[:generate_appstore_info] && Gym.building_for_ios? && Gym.config[:export_method] == 'app-store'
376
+
377
+ swinfo_plist_path = File.join(File.expand_path(Gym.config[:output_directory]), "AppStoreInfo.plist")
378
+ swinfo_path = File.join(FastlaneCore::Helper.xcode_path, "usr/bin/swinfo")
379
+
380
+ begin
381
+ UI.message("Generating AppStoreInfo.plist...")
382
+
383
+ # Build the swinfo command
384
+ command = [
385
+ "xcrun",
386
+ swinfo_path.shellescape,
387
+ "-f", ipa_path.shellescape,
388
+ "-o", swinfo_plist_path.shellescape,
389
+ "-prettyprint", "true",
390
+ "--plistFormat", "binary"
391
+ ].join(" ")
392
+
393
+ FastlaneCore::CommandExecutor.execute(command: command, print_all: FastlaneCore::Globals.verbose?, print_command: true)
394
+
395
+ if File.exist?(swinfo_plist_path)
396
+ UI.success("Successfully generated AppStoreInfo.plist:")
397
+ UI.message(swinfo_plist_path)
398
+ swinfo_plist_path
399
+ else
400
+ UI.error("Failed to generate AppStoreInfo.plist")
401
+ end
402
+ rescue => ex
403
+ UI.error("Error generating AppStoreInfo.plist: #{ex}")
404
+ end
405
+ end
406
+
372
407
  def find_archive_path
373
408
  Dir.glob(File.join(BuildCommandGenerator.build_path, "*.ipa")).last
374
409
  end
@@ -22,6 +22,7 @@ module Produce
22
22
  associated_domains: [SERVICE_ON, SERVICE_OFF],
23
23
  auto_fill_credential: [SERVICE_ON, SERVICE_OFF],
24
24
  class_kit: [SERVICE_ON, SERVICE_OFF],
25
+ declared_age_range: [SERVICE_ON, SERVICE_OFF],
25
26
  icloud: [SERVICE_LEGACY, SERVICE_CLOUDKIT],
26
27
  custom_network_protocol: [SERVICE_ON, SERVICE_OFF],
27
28
  data_protection: [