Class: Fastlane::Actions::CreateXcframeworkAction

Inherits:
Action
  • Object
show all
Defined in:
lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb

Class Method Summary collapse

Class Method Details

.authorsObject


197
198
199
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 197

def self.authors
  ["Boris Bielik", "Alexey Alter-Pesotskiy"]
end

.available_destinationsObject


158
159
160
161
162
163
164
165
166
167
168
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 158

def self.available_destinations
  {
    'iOS' => ['generic/platform=iOS', 'generic/platform=iOS Simulator'],
    'iPadOS' => ['generic/platform=iPadOS', 'generic/platform=iPadOS Simulator'],
    'tvOS' => ['generic/platform=tvOS', 'generic/platform=tvOS Simulator'],
    'watchOS' => ['generic/platform=watchOS', 'generic/platform=watchOS Simulator'],
    'carPlayOS' => ['generic/platform=carPlayOS', 'generic/platform=carPlayOS Simulator'],
    'macOS' => ['generic/platform=macOS'],
    'maccatalyst' => ['generic/platform=macOS,variant=Mac Catalyst']
  }
end

.available_optionsObject


206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 206

def self.available_options
  XcarchiveAction.available_options + [
    FastlaneCore::ConfigItem.new(
      key: :scheme,
      description: "The project's scheme. Make sure it's marked as Shared",
      optional: false
    ),
    FastlaneCore::ConfigItem.new(
      key: :enable_bitcode,
      description: "Should the project be built with bitcode enabled?",
      optional: true,
      is_string: false,
      default_value: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :destinations,
      description: "Use custom destinations for building the xcframework",
      optional: true,
      is_string: false,
      default_value: ['iOS']
    ),
    FastlaneCore::ConfigItem.new(
      key: :xcframework_output_directory,
      description: "The directory in which the xcframework should be stored in",
      optional: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :include_dSYMs,
      description: "Includes dSYM files in the xcframework",
      optional: true,
      default_value: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :include_BCSymbolMaps,
      description: "Includes BCSymbolMap files in the xcframework",
      optional: true,
      default_value: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :include_debug_symbols,
      description: 'This feature was added in Xcode 12.0.' \
                    'If this is set to false, the dSYMs and BCSymbolMaps wont be added to XCFramework itself',
      optional: true,
      default_value: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :product_name,
      description: "The name of your module. Optional if equals to :scheme. Equivalent to CFBundleName",
      optional: true
    ),
    FastlaneCore::ConfigItem.new(
      key: :remove_xcarchives,
      description: 'This option will auto-remove the xcarchive files once the plugin finishes.' \
                    'Set this to false to preserve the xcarchives',
      optional: true,
      default_value: true
    )
  ]
end

.categoryObject


266
267
268
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 266

def self.category
  :building
end

.clean(params) ⇒ Object


51
52
53
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 51

def self.clean(params)
  FileUtils.rm_rf(@xchelper.xcarchive_path) if params[:remove_xcarchives]
end

.copy_BCSymbolMaps(params) ⇒ Object


108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 108

def self.copy_BCSymbolMaps(params)
  return if params[:enable_bitcode] == false || params[:include_BCSymbolMaps] == false

  symbols_output_dir = @xchelper.xcframework_BCSymbolMaps_path
  FileUtils.mkdir_p(symbols_output_dir)

  params[:destinations].each_with_index do |_, framework_index|
    symbols_xcarchive_dir = @xchelper.xcarchive_BCSymbolMaps_path(framework_index)
    next unless Dir.exist?(symbols_xcarchive_dir)

    FileUtils.cp_r("#{symbols_xcarchive_dir}/.", symbols_output_dir)
    FastlaneCore::UI.important("▸ Copying #{Dir.children(symbols_xcarchive_dir)} to #{symbols_output_dir}")
  end
end

.copy_dSYMs(params) ⇒ Object


91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 91

def self.copy_dSYMs(params)
  return if params[:include_dSYMs] == false

  dSYMs_output_dir = @xchelper.xcframework_dSYMs_path
  FileUtils.mkdir_p(dSYMs_output_dir)

  params[:destinations].each_with_index do |_, framework_index|
    dSYM_source = "#{@xchelper.xcarchive_dSYMs_path(framework_index)}/#{@xchelper.framework}.dSYM"
    identifier = @xchelper.library_identifier(framework_index)
    dSYM = "#{@xchelper.framework}.#{identifier}.dSYM"
    dSYM_destination = "#{dSYMs_output_dir}/#{dSYM}"

    FastlaneCore::UI.important("▸ Copying #{dSYM} to #{dSYMs_output_dir}")
    FileUtils.cp_r(dSYM_source, dSYM_destination)
  end
end

.create_xcframework(params) ⇒ Object


55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 55

def self.create_xcframework(params)
  xcframework = @xchelper.xcframework_path
  begin
    FileUtils.rm_rf(xcframework) if File.exist?(xcframework)
    framework_links = params[:destinations].each_with_index.map do |_, index|
      "-framework #{@xchelper.xcarchive_framework_path(index)} #{debug_symbols(index: index, params: params)}"
    end

    Actions.sh("set -o pipefail && xcodebuild -create-xcframework #{framework_links.join(' ')} -output #{xcframework}")
  rescue => err
    UI.user_error!(err)
  end
end

.debug_symbols(index:, params:) ⇒ Object


69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 69

def self.debug_symbols(index:, params:)
  return "" unless Helper.xcode_at_least?('12.0.0') && params[:include_debug_symbols] == true

  debug_symbols = []

  # Include dSYMs in xcframework
  if params[:include_dSYMs] != false
    debug_symbols << "-debug-symbols #{@xchelper.xcarchive_dSYMs_path(index)}/#{@xchelper.framework}.dSYM"
  end

  # Include BCSymbols in xcframework
  if params[:include_BCSymbolMaps] != false && params[:enable_bitcode] != false
    bc_symbols_dir = @xchelper.xcarchive_BCSymbolMaps_path(index)
    if Dir.exist?(bc_symbols_dir)
      arguments = Dir.children(bc_symbols_dir).map { |path| "-debug-symbols #{File.expand_path("#{bc_symbols_dir}/#{path}")}" }
      debug_symbols << arguments.join(' ')
    end
  end

  debug_symbols.join(' ')
end

.descriptionObject

Documentation #


174
175
176
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 174

def self.description
  "Fastlane plugin that creates xcframework for given list of destinations."
end

.detailsObject


201
202
203
204
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 201

def self.details
  'Create xcframework plugin generates xcframework for specified destinations. ' \
    'The output of this action consists of the xcframework itself, which contains dSYM and BCSymbolMaps, if bitcode is enabled.'
end

.example_codeObject


178
179
180
181
182
183
184
185
186
187
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 178

def self.example_code
  [
    create_xcframework(
      workspace: 'path/to/your.xcworkspace',
      scheme: 'framework scheme',
      destinations: ['iOS'],
      xcframework_output_directory: 'output_directory'
    )
  ]
end

.is_supported?(platform) ⇒ Boolean

Returns:

  • (Boolean)

270
271
272
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 270

def self.is_supported?(platform)
  [:ios, :mac].include?(platform)
end

.outputObject


189
190
191
192
193
194
195
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 189

def self.output
  [
    ['XCFRAMEWORK_OUTPUT_PATH', 'The path to the newly generated xcframework'],
    ['XCFRAMEWORK_DSYM_OUTPUT_PATH', 'The path to the folder with dSYMs'],
    ['XCFRAMEWORK_BCSYMBOLMAPS_OUTPUT_PATH', 'The path to the folder with BCSymbolMaps']
  ]
end

.provide_shared_valuesObject


42
43
44
45
46
47
48
49
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 42

def self.provide_shared_values
  Actions.lane_context[SharedValues::XCFRAMEWORK_OUTPUT_PATH] = File.expand_path(@xchelper.xcframework_path)
  ENV[SharedValues::XCFRAMEWORK_OUTPUT_PATH.to_s] = File.expand_path(@xchelper.xcframework_path)
  Actions.lane_context[SharedValues::XCFRAMEWORK_DSYM_OUTPUT_PATH] = File.expand_path(@xchelper.xcframework_dSYMs_path)
  ENV[SharedValues::XCFRAMEWORK_DSYM_OUTPUT_PATH.to_s] = File.expand_path(@xchelper.xcframework_dSYMs_path)
  Actions.lane_context[SharedValues::XCFRAMEWORK_BCSYMBOLMAPS_OUTPUT_PATH] = File.expand_path(@xchelper.xcframework_BCSymbolMaps_path)
  ENV[SharedValues::XCFRAMEWORK_BCSYMBOLMAPS_OUTPUT_PATH.to_s] = File.expand_path(@xchelper.xcframework_BCSymbolMaps_path)
end

.run(params) ⇒ Object


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 14

def self.run(params)
  if Helper.xcode_at_least?('11.0.0')
    verify_delicate_params(params)
    params[:destinations] = update_destinations(params)
    params[:xcargs] = update_xcargs(params)

    @xchelper = Helper::CreateXcframeworkHelper.new(params)

    params[:destinations].each_with_index do |destination, framework_index|
      params[:destination] = destination
      params[:archive_path] = @xchelper.xcarchive_path_for_destination(framework_index)
      XcarchiveAction.run(params)
    end

    create_xcframework(params)

    copy_dSYMs(params)

    copy_BCSymbolMaps(params)

    clean(params)

    provide_shared_values
  else
    FastlaneCore::UI.important('xcframework can be produced only using Xcode 11 and above')
  end
end

.update_destinations(params) ⇒ Object


147
148
149
150
151
152
153
154
155
156
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 147

def self.update_destinations(params)
  return available_destinations.values[0] if params[:destinations].nil?

  requested_destinations = params[:destinations].map do |requested_de|
    available_destinations.select { |available_de, _| available_de == requested_de }.values
  end
  UI.user_error!("Error: available destinations: #{available_destinations.keys}") if requested_destinations.any?(&:empty?)

  requested_destinations.flatten
end

.update_xcargs(params) ⇒ Object


130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 130

def self.update_xcargs(params)
  FastlaneCore::UI.important('Overwriting SKIP_INSTALL and BUILD_LIBRARY_FOR_DISTRIBUTION options')
  if params[:xcargs]
    params[:xcargs].gsub!(/SKIP_INSTALL(=|\s+)(YES|NO)/, '')
    params[:xcargs].gsub!(/BUILD_LIBRARY_FOR_DISTRIBUTION(=|\s+)(YES|NO)/, '')
    params[:xcargs] += ' '
  end
  xcargs = ['SKIP_INSTALL=NO', 'BUILD_LIBRARY_FOR_DISTRIBUTION=YES']

  if params[:enable_bitcode] != false
    params[:xcargs].gsub!(/ENABLE_BITCODE(=|\s+)(YES|NO)/, '') if params[:xcargs]
    xcargs << ['OTHER_CFLAGS="-fembed-bitcode"', 'BITCODE_GENERATION_MODE="bitcode"', 'ENABLE_BITCODE=YES']
  end

  params[:xcargs].to_s + xcargs.join(' ')
end

.verify_delicate_params(params) ⇒ Object


123
124
125
126
127
128
# File 'lib/fastlane/plugin/create_xcframework/actions/create_xcframework_action.rb', line 123

def self.verify_delicate_params(params)
  UI.user_error!("Error: :scheme is required option") if params[:scheme].nil?
  if !params[:destinations].nil? && !params[:destinations].kind_of?(Array)
    UI.user_error!("Error: :destinations option should be presented as Array")
  end
end