ann-flutter-flavor 0.1.2

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 (29) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/Gemfile +3 -0
  4. data/Gemfile.lock +271 -0
  5. data/Rakefile +6 -0
  6. data/ann-flutter-flavor.gemspec +25 -0
  7. data/lib/ann-flutter-flavor.rb +10 -0
  8. data/lib/ann_flutter_flavor/version.rb +3 -0
  9. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_compile_build_action.rb +219 -0
  10. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_download_from_app_store_action.rb +183 -0
  11. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_download_from_play_store_action.rb +168 -0
  12. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_emulators_action.rb +180 -0
  13. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_run_tests_action.rb +128 -0
  14. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_setup_action.rb +137 -0
  15. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_upload_to_app_store_action.rb +280 -0
  16. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_upload_to_firebase_action.rb +199 -0
  17. data/lib/fastlane/plugin/ann_flutter_flavor/actions/ann_upload_to_play_store_action.rb +248 -0
  18. data/lib/fastlane/plugin/ann_flutter_flavor/helper/lanes_android.rb +120 -0
  19. data/lib/fastlane/plugin/ann_flutter_flavor/helper/lanes_annai.rb +502 -0
  20. data/lib/fastlane/plugin/ann_flutter_flavor/helper/lanes_ios.rb +157 -0
  21. data/lib/fastlane/plugin/ann_flutter_flavor/helper/lanes_setup.rb +161 -0
  22. data/lib/fastlane/plugin/ann_flutter_flavor/helper/podspec_bridge.rb +153 -0
  23. data/lib/fastlane/plugin/ann_flutter_flavor/helper/test_integration.rb +346 -0
  24. data/lib/fastlane/plugin/ann_flutter_flavor/helper/utils_project_config.rb +96 -0
  25. data/lib/fastlane/plugin/ann_flutter_flavor/helper/utils_spec_loader.rb +363 -0
  26. data/lib/fastlane/plugin/ann_flutter_flavor/helper/utils_status.rb +115 -0
  27. data/lib/fastlane/plugin/ann_flutter_flavor.rb +23 -0
  28. data/plugin_manager.sh +140 -0
  29. metadata +112 -0
@@ -0,0 +1,502 @@
1
+ require 'yaml'
2
+ require 'fileutils'
3
+ require 'fastlane/action'
4
+
5
+ require 'fastlane/plugin/ann_flutter_flavor/helper/lanes_android'
6
+ require 'fastlane/plugin/ann_flutter_flavor/helper/lanes_ios'
7
+ require 'fastlane/plugin/ann_flutter_flavor/helper/lanes_setup'
8
+ require 'fastlane/plugin/ann_flutter_flavor/helper/utils_project_config'
9
+ require 'fastlane/plugin/ann_flutter_flavor/helper/utils_spec_loader'
10
+ require 'fastlane/plugin/ann_flutter_flavor/helper/utils_status'
11
+
12
+ module FastlaneFlutterFlavor
13
+
14
+ # ------------------------------------
15
+ # AnnaiLanes (Main Wrapper Class)
16
+ # ------------------------------------
17
+ class AnnaiLanes
18
+
19
+ # Refactored initialize to use a single 'platform' symbol and accept an optional 'spec_file'
20
+ def initialize(lane:, platform:, spec_file: nil)
21
+ @lane = lane
22
+ @statusManager = StatusManager.new(lane: lane)
23
+
24
+ # Validate the platform input: now includes :web
25
+ unless [:android, :ios, :web].include?(platform)
26
+ raise "Invalid Fastfile configuration: 'platform' must be :android, :ios, or :web"
27
+ end
28
+
29
+ # Set internal flags based on the single parameter
30
+ @platform = platform
31
+ @isAndroid = (platform == :android)
32
+ @isIos = (platform == :ios)
33
+ @isWeb = (platform == :web) # New flag for web platform
34
+
35
+ # 1. Find the project root folder using ProjectUtil helper
36
+ @root_folder = FastlaneFlutterFlavor::ProjectUtil.find_flutter_root
37
+
38
+ # 2. Resolve the main spec file path
39
+ if spec_file
40
+ # If a spec_file path is explicitly provided, resolve it relative to the root folder.
41
+ full_spec_file = File.expand_path(spec_file, @root_folder)
42
+ else
43
+ # Otherwise, use ProjectUtil's logic which checks for ANN_SPEC_FILE env var and defaults.
44
+ # The method handles checking the ANN_SPEC_FILE environment variable and applying defaults.
45
+ full_spec_file = FastlaneFlutterFlavor::ProjectUtil.find_annai_spec_path(nil)
46
+ end
47
+
48
+ # full_spec_file contains the absolute path if found/resolved.
49
+ unless File.exist?(full_spec_file)
50
+ error_msg = "Configuration Error: The required specification file was not found. Path checked: #{full_spec_file}. "
51
+ unless spec_file
52
+ error_msg += "Please ensure 'annspec.yaml' exists or set the ANN_SPEC_FILE environment variable correctly."
53
+ end
54
+ raise error_msg
55
+ end
56
+
57
+ # Determine the root folder for resolving relative paths used in the spec file
58
+ @spec_root_folder = File.dirname(full_spec_file)
59
+
60
+ # Initialize the YamlSpecLoader using the determined root folder and file path
61
+ # We pass the root folder for context, and the full file path for loading
62
+ @specLoader = YamlSpecLoader.new(@root_folder, full_spec_file)
63
+
64
+ # Helper classes are only initialized if they are mobile platforms
65
+ @androidLanes = AndroidLanes.new(lane: lane, root_folder:@root_folder) if @isAndroid
66
+ @iosLanes = IosLanes.new(lane: lane, root_folder:@root_folder) if @isIos
67
+
68
+ @setup_lanes = SetupLanes.new(root_folder: @root_folder,status_manager: @statusManager)
69
+ end
70
+
71
+ def finalize()
72
+ @statusManager.displayStatus
73
+ end
74
+
75
+ # Handles unexpected exceptions during lane execution
76
+ def onError(exception)
77
+ @statusManager.logError "", "Unknown Error", exception.message
78
+ @statusManager.displayStatus
79
+ end
80
+
81
+ def compile_build(flavor: "", sub_command: "appbundle", build_config: "release",
82
+ main_file: "lib/main.dart", skip_sound_null_safety: false,
83
+ skip_code_sign: false, export_options_plist: "", additional_parameter: "", platform:
84
+ )
85
+
86
+ begin
87
+ # nullSafety is the argument string or empty
88
+ nullSafety = skip_sound_null_safety ? "--no-sound-null-safety" : ""
89
+
90
+ # Determine command-line flavor parameters. The original 'flavor' parameter is preserved for logging.
91
+ cli_flavor = flavor
92
+ cli_flavor_option = cli_flavor.empty? ? "" : "--flavor"
93
+
94
+ # Initialize platform-specific options as empty
95
+ codeSign = ""
96
+ export_option = ""
97
+
98
+ if @isIos
99
+ # Only iOS uses codesign and export options plist
100
+ codeSign = skip_code_sign ? "--no-codesign" : ""
101
+ export_option = export_options_plist.empty? ? "" : "--export-options-plist=#{export_options_plist}"
102
+
103
+ elsif @isWeb
104
+ # Web compilation does not support --flavor. Override CLI parameters.
105
+ Fastlane::UI.message("Web compilation detected. Omitting '--flavor' from Flutter build command, but using '#{flavor}' for logging.")
106
+ cli_flavor = ""
107
+ cli_flavor_option = ""
108
+ end
109
+
110
+ # Base command parts
111
+ command_parts = [
112
+ "flutter", "build",
113
+ sub_command,
114
+ "--#{build_config}",
115
+ ]
116
+
117
+ # Conditionally add nullSafety parameter
118
+ command_parts << nullSafety unless nullSafety.empty?
119
+
120
+ # Conditionally add flavor parts (only for non-web, non-empty flavor scenarios)
121
+ if !cli_flavor_option.empty?
122
+ command_parts << cli_flavor_option
123
+ command_parts << cli_flavor
124
+ end
125
+
126
+ command_parts << "-t"
127
+ command_parts << main_file
128
+ command_parts << additional_parameter
129
+
130
+ # Conditionally add iOS-specific parts
131
+ if @isIos
132
+ command_parts << codeSign unless codeSign.empty?
133
+ command_parts << export_option unless export_option.empty?
134
+ end
135
+
136
+ # Ensure the command runs from the Flutter root
137
+ flutter_root = @root_folder
138
+
139
+ # Clean up empty strings and execute
140
+ command_to_execute = command_parts.flatten.compact.map(&:to_s).reject(&:empty?)
141
+
142
+ Fastlane::UI.message("Executing command: #{command_to_execute.join(' ')}")
143
+
144
+ Dir.chdir flutter_root do
145
+ Fastlane::Actions::sh(*command_to_execute)
146
+ end
147
+
148
+ # Logging uses the original 'flavor' parameter
149
+ @statusManager.logSuccess flavor, "compile_build", platform
150
+ return true
151
+
152
+ rescue => e
153
+ Fastlane::UI.error "Error while compiling flavor #{flavor}"
154
+ Fastlane::UI.error e
155
+
156
+ # Logging uses the original 'flavor' parameter
157
+ @statusManager.logError flavor, "compile_build", platform, e
158
+ return false
159
+ end
160
+ end
161
+
162
+ # New method to compile web build and deploy to Firebase Hosting
163
+ def upload_to_firebase(flavor: "", main_file: "lib/main.dart", build_config: "release",
164
+ skip_compile: false, skip_sound_null_safety: false,
165
+ firebase_project:, firebase_token:) # firebase_project is the user override
166
+
167
+ begin
168
+ unless @isWeb
169
+ raise "Invalid call to upload_to_firebase. This action is only supported for the :web platform. Error during uploading of flavor #{flavor}"
170
+ end
171
+
172
+ # --- 1. Determine the Firebase Project ID (Prioritization Logic) ---
173
+ project_id = firebase_project.to_s.strip # Check user-provided argument first
174
+
175
+ if project_id.empty?
176
+ # If user argument is empty, fallback to spec file configuration
177
+ project_id = @specLoader.get_firebase_project_id(@platform, flavor, "release").to_s.strip
178
+ end
179
+
180
+ if project_id.empty?
181
+ raise "Missing Firebase Project ID. Please provide it via the 'firebase_project' parameter or define it under 'project_id' in your annai spec file for flavor '#{flavor}' and platform '#{@platform}'."
182
+ end
183
+
184
+ final_project_id = project_id
185
+ Fastlane::UI.message("Using Firebase Project ID: '#{final_project_id}'")
186
+
187
+ # 2. Compile the web build unless skipped
188
+ unless skip_compile
189
+ unless(
190
+ compile_build(
191
+ flavor: flavor,
192
+ sub_command: "web", # Use 'web' as sub_command for 'flutter build web'
193
+ build_config: build_config,
194
+ main_file: main_file,
195
+ skip_sound_null_safety: skip_sound_null_safety,
196
+ skip_code_sign: true, # Not applicable for web
197
+ export_options_plist: "", # Not applicable for web
198
+ platform: @platform,
199
+ )
200
+ )
201
+ raise "Error during compilation of web flavor #{flavor}"
202
+ end
203
+ end
204
+
205
+ # 3. Read the existing firebase.json
206
+ firebase_config_path = File.join(@root_folder, "firebase.json")
207
+ config = JSON.parse(File.read(firebase_config_path))
208
+
209
+ # 4. Update the hosting block
210
+ config['hosting'] = {
211
+ "public" => "build/web",
212
+ "ignore" => ["firebase.json", "**/.*", "**/node_modules/**"],
213
+ "rewrites" => [{"source" => "**", "destination" => "/index.html"}]
214
+ }
215
+
216
+ # 5. Write the updated firebase.json back to disk
217
+ File.write(firebase_config_path, JSON.pretty_generate(config))
218
+
219
+ token = firebase_token.to_s.strip
220
+ if token.empty?
221
+ token = @specLoader.get_firebase_token_from_properties.to_s.strip
222
+ unless token.empty?
223
+ Fastlane::UI.message("Successfully retrieved Firebase token from external properties file.")
224
+ end
225
+ end
226
+
227
+ # 6. Deploy to Firebase Hosting using the determined ID
228
+ command_parts = [
229
+ "firebase", "deploy",
230
+ "--only", "hosting",
231
+ "--project", final_project_id,
232
+ ]
233
+ # Only add the token flags if token is present
234
+ if !token.empty?
235
+ command_parts.push("--token", token)
236
+ end
237
+
238
+ firebase_root = @root_folder
239
+
240
+ Fastlane::UI.message("Executing Firebase deploy command: #{command_parts.join(' ')}")
241
+
242
+ Dir.chdir firebase_root do
243
+ Fastlane::Actions::sh(*command_parts)
244
+ end
245
+
246
+ @statusManager.logSuccess flavor, "upload_to_firebase", @platform
247
+ return true
248
+
249
+ rescue => e
250
+ Fastlane::UI.error "Error while uploading to Firebase for web flavor #{flavor}"
251
+ Fastlane::UI.error e
252
+ @statusManager.logError flavor, "upload_to_firebase", @platform, e
253
+ return false
254
+ end
255
+ end
256
+
257
+ def download_from_store(package_name:, api_key_path:, flavor: "", platform:, use_live_version:, metadata_path:, screenshots_path:, distribution_platform:)
258
+ begin
259
+ if @isWeb
260
+ raise "Invalid call: Web compilation does not support downloading from mobile app stores."
261
+ end
262
+
263
+ # API key path is relative to the spec file root
264
+ api_key_absolute_path = File.join(@spec_root_folder, api_key_path)
265
+
266
+ if @isAndroid
267
+ @androidLanes.download_from_store(
268
+ package_name: package_name,
269
+ api_key_path: api_key_absolute_path,
270
+ metadata_path: @androidLanes.get_metadata_path(metadata_path: metadata_path, flavor: flavor),
271
+ platform: platform,
272
+ )
273
+ end
274
+ if @isIos
275
+ @iosLanes.download_from_store(
276
+ package_name: package_name,
277
+ api_key_path: api_key_absolute_path,
278
+ metadata_path: @iosLanes.get_metadata_path(metadata_path: metadata_path, flavor: flavor, distribution_platform: distribution_platform),
279
+ screenshots_path: @iosLanes.get_screenshots_path(screenshots_path: screenshots_path, flavor: flavor, distribution_platform: distribution_platform),
280
+ deliver_file: @iosLanes.get_deliver_file(),
281
+ use_live_version: use_live_version,
282
+ )
283
+ end
284
+ @statusManager.logSuccess flavor, "download_from_store", platform
285
+ return true
286
+ rescue => e
287
+ Fastlane::UI.error "Error while downloading from store for flavor #{flavor}"
288
+ Fastlane::UI.error e
289
+ @statusManager.logError flavor, "download_from_store", platform, e
290
+ return false
291
+ end
292
+ end
293
+
294
+ def upload_to_play_store(package_name:, api_key_path:, in_app_update_priority: 1, flavor: "",
295
+ main_file: "lib/main.dart", track: "beta", track_promote_to: "production", skip_sound_null_safety: false, skip_compile: false,
296
+ skip_upload_prod: false, skip_upload_binary: false, skip_upload_changelogs: false,
297
+ skip_upload_metadata: false, skip_upload_images: false, skip_upload_screenshots: false, platform:,
298
+ metadata_path: nil
299
+ )
300
+
301
+ begin
302
+
303
+ unless @isAndroid
304
+ # This handles both general invalid calls and the new :web case
305
+ raise "Invalid call to upload_to_play_store. This action is only supported for the :android platform. Error during uploading of flavor #{flavor}"
306
+ end
307
+
308
+ build_config = "release"
309
+ sub_command = "appbundle"
310
+ # Adjusted aabFile path to be relative from the root
311
+ aabFile = "build/app/outputs/bundle/release/app-release.aab"
312
+ final_metadata_path = @androidLanes.get_metadata_path(metadata_path: metadata_path, flavor: flavor)
313
+
314
+ if flavor != ""
315
+ aabFile = "build/app/outputs/bundle/" + flavor + "Release/app-" + flavor + "-release.aab"
316
+ end
317
+
318
+ unless skip_compile
319
+ unless(
320
+ compile_build(
321
+ flavor: flavor,
322
+ sub_command: sub_command,
323
+ build_config: build_config,
324
+ main_file: main_file,
325
+ skip_sound_null_safety: skip_sound_null_safety,
326
+ skip_code_sign: false,
327
+ platform: platform,
328
+ )
329
+ )
330
+ raise "Error during compilation of flavor #{flavor}"
331
+ end
332
+ end
333
+
334
+ # Prepend the root folder to the aabFile path since Fastlane actions require absolute paths
335
+ aab_absolute_path = File.join(@root_folder, aabFile)
336
+ # API key path is relative to the spec file root
337
+ api_key_absolute_path = File.join(@spec_root_folder, api_key_path)
338
+
339
+ @androidLanes.upload_to_store(
340
+ aab: aab_absolute_path,
341
+ package_name: package_name,
342
+ in_app_update_priority: in_app_update_priority,
343
+ track: track,
344
+ track_promote_to: track_promote_to,
345
+ metadata_path: final_metadata_path,
346
+ api_key_path: api_key_absolute_path,
347
+ skip_upload_prod: skip_upload_prod,
348
+ skip_upload_binary: skip_upload_binary,
349
+ skip_upload_changelogs: skip_upload_changelogs,
350
+ skip_upload_metadata: skip_upload_metadata,
351
+ skip_upload_images: skip_upload_images,
352
+ skip_upload_screenshots: skip_upload_screenshots,
353
+ platform: platform,
354
+ )
355
+
356
+ @statusManager.logSuccess flavor, "upload_to_play_store", platform
357
+ return true
358
+
359
+ rescue => e
360
+ Fastlane::UI.error "Error while uploading to store for flavor #{flavor}"
361
+ Fastlane::UI.error e
362
+ @statusManager.logError flavor, "upload_to_play_store", platform, e
363
+ return false
364
+ end
365
+ end
366
+
367
+ def upload_to_app_store(bundle_identifier:, api_key_path:, flavor: "",
368
+ main_file: "lib/main.dart", display_name:, export_option_file:,
369
+ team_id:, signing_certificate:, app_version:, build_number:,
370
+ skip_sound_null_safety: false, skip_compile: false, skip_upload_binary: false,
371
+ skip_upload_prod: false,
372
+ skip_upload_metadata: false, skip_upload_screenshots: false,
373
+ export_compliance_uses_encryption: nil, add_id_info_uses_idfa: nil, platform:,
374
+ metadata_path: nil, screenshots_path: nil, distribution_platform: nil
375
+ )
376
+
377
+ begin
378
+
379
+ unless @isIos
380
+ # This handles both general invalid calls and the new :web case
381
+ raise "Invalid call to upload_to_app_store. This action is only supported for the :ios platform. Error during uploading of flavor #{flavor}"
382
+ end
383
+
384
+ build_config = "release"
385
+ sub_command = "ipa"
386
+ build_config_xcode = "Release"
387
+
388
+ # Paths are now relative to the root folder, which is @root_folder
389
+ root_folder = @root_folder
390
+ ipa_folder = File.join(root_folder, "build/ios/ipa/") # Source folder for built IPA
391
+ archive_folder = File.join(root_folder, "build/ios/archive/")
392
+ ipa_flavor_folder = File.join(ipa_folder, flavor, platform) # Destination folder
393
+ ios_project_path = File.join(root_folder, "ios")
394
+
395
+ # The path the upload process will use
396
+ ipa_file = File.join(ipa_flavor_folder, display_name + ".ipa")
397
+
398
+ final_metadata_path = @iosLanes.get_metadata_path(metadata_path: metadata_path, flavor: flavor, distribution_platform: distribution_platform)
399
+ final_screenshots_path = @iosLanes.get_screenshots_path(screenshots_path: screenshots_path, flavor: flavor, distribution_platform: distribution_platform)
400
+ api_key_absolute_path = File.join(@spec_root_folder, api_key_path)
401
+
402
+ if flavor != ""
403
+ build_config_xcode = "Release-" + flavor
404
+ end
405
+
406
+ # 1. Ensure provisioning profile is correct
407
+ Dir.chdir ios_project_path do
408
+ @iosLanes.sigh(
409
+ app_identifier: bundle_identifier,
410
+ api_key_path: api_key_absolute_path,
411
+ team_id: team_id,
412
+ )
413
+ end
414
+
415
+ unless skip_compile
416
+
417
+ # 2. Update Xcode code signing settings
418
+ Dir.chdir ios_project_path do
419
+ @iosLanes.update_code_signing_settings(
420
+ team_id: team_id,
421
+ code_sign_identity: signing_certificate,
422
+ profile_name: ENV["SIGH_NAME"],
423
+ build_configurations: build_config_xcode,
424
+ )
425
+ end
426
+
427
+ # 3. Compile the build (creates an IPA in ipa_folder)
428
+ unless(
429
+ compile_build(
430
+ flavor: flavor,
431
+ sub_command: sub_command,
432
+ build_config: build_config,
433
+ main_file: main_file,
434
+ skip_sound_null_safety: skip_sound_null_safety,
435
+ skip_code_sign: false,
436
+ export_options_plist: export_option_file,
437
+ platform: platform,
438
+ )
439
+ )
440
+ raise "Error during compilation of flavor #{flavor}"
441
+ end
442
+
443
+ # 4. Find the generated IPA, move it to the flavor folder, and rename it.
444
+ ipa_candidates = Dir.glob(File.join(ipa_folder, "*.ipa"))
445
+ if ipa_candidates.empty?
446
+ raise "Compilation Error: No IPA file found in expected directory: #{ipa_folder}"
447
+ end
448
+
449
+ original_ipa_path = ipa_candidates.first
450
+
451
+ # Create the destination directory
452
+ FileUtils.mkdir_p ipa_flavor_folder
453
+
454
+ # Move and rename the IPA file to the expected display_name.ipa
455
+ FileUtils.mv(original_ipa_path, ipa_file)
456
+ Fastlane::UI.message "Moved and renamed IPA from #{File.basename(original_ipa_path)} to #{File.expand_path(ipa_file)}"
457
+
458
+ # 5. Backup the XCArchive
459
+ @iosLanes.backup_xcarchive(
460
+ xcarchive: File.join(archive_folder, 'Runner.xcarchive'),
461
+ destination: ipa_flavor_folder,
462
+ zip_filename: 'Runner',
463
+ )
464
+ end
465
+
466
+ # 6. Upload to App Store Connect
467
+ unless skip_upload_prod && skip_upload_binary && skip_upload_metadata && skip_upload_screenshots
468
+ @iosLanes.upload_to_store(
469
+ ipa_file: ipa_file,
470
+ bundle_identifier: bundle_identifier,
471
+ api_key_path: api_key_absolute_path,
472
+ metadata_path: final_metadata_path,
473
+ screenshots_path: final_screenshots_path,
474
+ app_version: app_version,
475
+ build_number: build_number,
476
+ skip_upload_prod: skip_upload_prod,
477
+ skip_upload_binary: skip_upload_binary,
478
+ skip_upload_metadata: skip_upload_metadata,
479
+ skip_upload_screenshots: skip_upload_screenshots,
480
+ export_compliance_uses_encryption: export_compliance_uses_encryption,
481
+ add_id_info_uses_idfa: add_id_info_uses_idfa,
482
+ platform: platform,
483
+ )
484
+ end
485
+
486
+ @statusManager.logSuccess flavor, "upload_to_app_store", platform
487
+ return true
488
+
489
+ rescue => e
490
+ Fastlane::UI.error "Error while uploading to store for flavor #{flavor}"
491
+ Fastlane::UI.error e
492
+ @statusManager.logError flavor, "upload_to_app_store", platform, e
493
+ return false
494
+ end
495
+ end
496
+
497
+ def clean_build
498
+ @setup_lanes.cleanup
499
+ end
500
+
501
+ end
502
+ end
@@ -0,0 +1,157 @@
1
+ require 'yaml'
2
+ require 'fileutils'
3
+ require 'fastlane/action'
4
+
5
+ module FastlaneFlutterFlavor
6
+
7
+ # ------------------------------------
8
+ # IosLanes (Helper Class)
9
+ # ------------------------------------
10
+ class IosLanes
11
+
12
+ def initialize(lane: ,root_folder:)
13
+ @lane = lane
14
+ @root_folder = root_folder
15
+ end
16
+
17
+ def upload_to_store(ipa_file:, bundle_identifier:, api_key_path:, metadata_path:, screenshots_path:,
18
+ app_version:, build_number:,
19
+ skip_upload_binary: false, skip_upload_prod: false,
20
+ skip_upload_metadata: false,
21
+ skip_upload_screenshots: false, export_compliance_uses_encryption: nil,
22
+ add_id_info_uses_idfa: nil, platform: "ios")
23
+
24
+ final_build_number = build_number.to_s
25
+
26
+ Fastlane::UI.message "App Version: " + app_version
27
+ Fastlane::UI.message "Build Number: " + final_build_number
28
+ Fastlane::UI.message "App identifier: " + bundle_identifier
29
+
30
+ unless skip_upload_binary
31
+ @lane.other_action.upload_to_testflight(
32
+ ipa: ipa_file,
33
+ app_identifier: bundle_identifier,
34
+ api_key_path: api_key_path,
35
+ app_version: app_version,
36
+ build_number: final_build_number,
37
+ expire_previous_builds: true,
38
+ skip_waiting_for_build_processing: skip_upload_prod,
39
+ app_platform: platform,
40
+ )
41
+ end
42
+
43
+ unless skip_upload_prod
44
+
45
+ submission_information = ""
46
+ unless export_compliance_uses_encryption == nil
47
+ submission_information += "\"export_compliance_uses_encryption\": #{export_compliance_uses_encryption}"
48
+ end
49
+ unless add_id_info_uses_idfa == nil
50
+ unless submission_information == ""
51
+ submission_information += ","
52
+ end
53
+ submission_information += "\"add_id_info_uses_idfa\": #{add_id_info_uses_idfa}"
54
+ end
55
+ submission_information = "{#{submission_information}}"
56
+
57
+ @lane.other_action.upload_to_app_store(
58
+ build_number: final_build_number,
59
+ app_identifier: bundle_identifier,
60
+ app_version: app_version,
61
+ api_key_path: api_key_path,
62
+ metadata_path: metadata_path,
63
+ screenshots_path: screenshots_path,
64
+ skip_binary_upload: skip_upload_binary,
65
+ skip_metadata: skip_upload_metadata,
66
+ skip_screenshots: skip_upload_screenshots,
67
+ overwrite_screenshots: skip_upload_screenshots == false,
68
+ submit_for_review: true,
69
+ automatic_release: true,
70
+ force: true,
71
+ precheck_include_in_app_purchases: false,
72
+ submission_information:submission_information,
73
+ platform: platform,
74
+ )
75
+ end
76
+ end
77
+
78
+ def download_from_store(package_name:, api_key_path:, metadata_path:, screenshots_path:, deliver_file:, platform:"ios", use_live_version:false)
79
+ FileUtils.rm_rf(metadata_path)
80
+ FileUtils.rm_rf(screenshots_path)
81
+ FileUtils.remove_file(deliver_file, force = true)
82
+
83
+ Fastlane::Actions::sh(
84
+ "fastlane", "deliver", "init",
85
+ "--metadata_path", metadata_path,
86
+ "--screenshots_path", screenshots_path,
87
+ "--app_identifier", package_name,
88
+ "--api_key_path", api_key_path,
89
+ "--platform", platform,
90
+ "--use_live_version", use_live_version ? "true" : "false",
91
+ )
92
+ end
93
+
94
+ def sigh(app_identifier:, api_key_path:, team_id:)
95
+ @lane.other_action.sigh(
96
+ force: true,
97
+ app_identifier: app_identifier,
98
+ api_key_path: api_key_path,
99
+ team_id: team_id,
100
+ )
101
+ end
102
+
103
+ def update_code_signing_settings(team_id:, code_sign_identity:, profile_name:, build_configurations:)
104
+ @lane.other_action.update_code_signing_settings(
105
+ team_id: team_id,
106
+ code_sign_identity: code_sign_identity,
107
+ use_automatic_signing: false,
108
+ profile_name: profile_name,
109
+ build_configurations: build_configurations,
110
+ )
111
+ end
112
+
113
+ def backup_xcarchive(xcarchive:, destination:, zip_filename: )
114
+ @lane.other_action.backup_xcarchive(
115
+ xcarchive: xcarchive,
116
+ destination: destination,
117
+ zip: true,
118
+ zip_filename: zip_filename,
119
+ versioned: false,
120
+ )
121
+ end
122
+
123
+ # Resolves the metadata path: either a custom one relative to the root,
124
+ # or the standard Fastlane structure.
125
+ def get_metadata_path(platform: "ios", metadata_path: nil, flavor:, distribution_platform:)
126
+ # If a custom path is provided (and not nil or empty string), use it.
127
+ unless metadata_path.to_s.empty?
128
+ # Path structure: @root_folder / custom_path / flavor
129
+ return File.join(@root_folder, metadata_path, flavor, distribution_platform)
130
+ end
131
+
132
+ # Default Path: Use the standard Fastlane structure.
133
+ # Path structure: @root_folder / fastlane / platform / metadata / flavor
134
+ File.join(@root_folder, "fastlane", platform, 'metadata', flavor, distribution_platform)
135
+ end
136
+
137
+
138
+ # Resolves the screenshots path: either a custom one relative to the root,
139
+ # or the standard Fastlane structure.
140
+ def get_screenshots_path(platform: "ios", screenshots_path: nil, flavor:, distribution_platform:)
141
+ # If a custom path is provided (and not nil or empty string), use it.
142
+ unless screenshots_path.to_s.empty?
143
+ # Path structure: @root_folder / custom_path / flavor
144
+ return File.join(@root_folder, screenshots_path, flavor, distribution_platform)
145
+ end
146
+
147
+ # Default Path: Use the standard Fastlane structure.
148
+ # Path structure: @root_folder / fastlane / platform / metadata / flavor
149
+ File.join(@root_folder, "fastlane", platform, 'screenshots', flavor, distribution_platform)
150
+ end
151
+
152
+ def get_deliver_file(platform: "ios")
153
+ return File.join(@root_folder, "fastlane", "Deliverfile")
154
+ end
155
+
156
+ end
157
+ end