Class: Pod::XBuilder

Inherits:
Object
  • Object
show all
Includes:
Config::Mixin, PodUtil, XcodeProjHelper, XcodeXBuilder
Defined in:
lib/cocoapods-xcframework/xbuilder.rb,
lib/cocoapods-xcframework/xbuilder/xcode_xbuild.rb,
lib/cocoapods-xcframework/xbuilder/xcodeproj_helper.rb

Defined Under Namespace

Modules: XcodeProjHelper, XcodeXBuilder

Instance Method Summary collapse

Methods included from PodUtil

#build_static_sandbox, #fix_bundle_file, #fix_header_file, #generic_new_podspec_hash, #installation_root, #installation_root_muti, #muti_config_with_file, #podfile_from_muti_configs, #podfile_from_spec, #spec_with_name, #spec_with_path, #to_native_platform

Methods included from XcodeProjHelper

#modify_xcode_project_sdk_to_simullator

Methods included from XcodeXBuilder

#compare_xcode_14_version, #xcode_version, #xcode_xbuild

Constructor Details

#initialize(installer, source_dir, sandbox_root, spec, configuration, symbols = true, support_maccatalyst = true) ⇒ XBuilder

Returns a new instance of XBuilder.



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 9

def initialize(installer, source_dir, sandbox_root, spec, configuration, symbols=true, support_maccatalyst=true)
# def initialize(platform, installer, source_dir, sandbox_root, spec, config)
    # @platform = platform
  @installer = installer
  @source_dir = source_dir
  @sandbox_root = sandbox_root
  @spec = spec
  @muti = @spec.is_a? Array
  @configs = @spec if @muti
  @spec = "muti" if @muti

  @configuration = configuration
  @outputs = Hash.new
  @symbols = symbols
  @support_maccatalyst = support_maccatalyst
end

Instance Method Details

#buildObject



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 26

def build
  UI.puts("Building framework #{@spec} with configuration #{@configuration}")
  UI.puts "Work dir is :#{@sandbox_root} isSymbols:#{@symbols}"
  # defines = "GCC_PREPROCESSOR_DEFINITIONS='$(inherited) PodsDummy_Pods_#{@spec.name}=PodsDummy_PodPackage_#{@spec.name}'"
  defines = ""
  if @configuration == 'Debug'
    defines << 'GCC_GENERATE_DEBUGGING_SYMBOLS=YES ONLY_ACTIVE_ARCH=NO'
  else
    if @symbols
      defines << "GCC_GENERATE_DEBUGGING_SYMBOLS=YES" # Release模式需要符号表应于问题排查(二进制切源码操作) by hm 21/10/13
    else
      defines << "GCC_GENERATE_DEBUGGING_SYMBOLS=NO" # 去除符号表
    end
  end
  
  build_all_device defines

  collect_xc_frameworks

  collect_bundles
end

#build_all_device(defines) ⇒ Object



137
138
139
140
141
142
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 137

def build_all_device defines
  # build general first because simulator will exchange SDKROOT to simulat sdk
  build_general_device defines
  build_simulator_device defines
  build_MacCatalyst_device defines if @support_maccatalyst
end

#build_general_device(defines) ⇒ Object



144
145
146
147
148
149
150
151
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 144

def build_general_device defines
  UI.puts("--- Building framework #{@spec} with general device")
  xcode_xbuild(
    defines,
    @configuration,
    @sandbox_root
  )
end

#build_MacCatalyst_device(defines) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 165

def build_MacCatalyst_device defines
  UI.puts("--- Building framework #{@spec} with MacCatalyst device")
  xcode_xbuild(
    defines,
    @configuration,
    @sandbox_root,
    'export',       # build_dir
    'macOS',        # platform
    "#{@sandbox_root}/Pods.xcodeproj", # project
    "#{@spec.name}" # scheme
  )
end

#build_simulator_device(defines) ⇒ Object



153
154
155
156
157
158
159
160
161
162
163
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 153

def build_simulator_device defines
  UI.puts("--- Building framework #{@spec} with simulator device")
  modify_xcode_project_sdk_to_simullator "#{@sandbox_root}/Pods.xcodeproj"
  xcode_xbuild(
    defines,
    @configuration,
    @sandbox_root,
    'export',
    'iOS Simulator'
  )
end

#colelct_muti_bundlesObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 79

def colelct_muti_bundles 
  @outputs[:bundle] = Hash.new
  @configs.each do |cfg|
    # "" 这个是用来代表mac os的 macos 没有后缀奇怪吧
    ["iphoneos","","appletvos","watchos"].each do |plat|
      export_dir = "#{@sandbox_root}/export/*-#{plat}/**/#{cfg["name"]}.bundle/**"
      Pathname.glob(export_dir).each do |bundle|
        if bundle.to_s.include? "#{@spec.name}.bundle/Info.plist"
          return
        end
        target_path = "#{@sandbox_root}/bundle/#{cfg["name"]}"
        @outputs[:bundle][cfg["name"]] = target_path
        native_platform = to_native_platform plat
        path = Pathname.new "#{target_path}/#{native_platform}"
        if not path.exist?
          path.mkpath
        end
        FileUtils.cp_r(Dir["#{bundle}"],"#{path}")
      end
    end
  end
end

#collect_bundlesObject



71
72
73
74
75
76
77
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 71

def collect_bundles
  if @muti
    colelct_muti_bundles
  else
    collect_single_bundles
  end
end

#collect_muti_xcframworksObject



56
57
58
59
60
61
62
63
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 56

def collect_muti_xcframworks
  @outputs[:xcframework] = Hash.new
  @configs.each do |cfg|
    export_dir = "#{@sandbox_root}/export/**/#{cfg["name"]}.framework"
    frameworks = Pathname.glob(export_dir)
    @outputs[:xcframework][cfg["name"]] = create_xc_framework_by_frameworks frameworks, cfg["name"]
  end
end

#collect_single_bundlesObject



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 102

def collect_single_bundles 
  # "" 这个是用来代表mac os的 macos 没有后缀奇怪吧
  ["iphoneos","","appletvos","watchos"].each do |plat|
    export_dir = "#{@sandbox_root}/export/*-#{plat}/**/#{@spec.name}.bundle/**"
    Pathname.glob(export_dir).each do |bundle|
      if bundle.to_s.include? "#{@spec.name}.bundle/Info.plist"
        return
      end
      @outputs[:bundle] = "#{@sandbox_root}/bundle"
      native_platform = to_native_platform plat
      path = Pathname.new "#{@sandbox_root}/bundle/#{native_platform}"
      if not path.exist?
        path.mkpath
      end
      FileUtils.cp_r(Dir["#{bundle}"],"#{path}")
    end
  end
end

#collect_single_xcframeworksObject



65
66
67
68
69
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 65

def collect_single_xcframeworks
  export_dir = "#{@sandbox_root}/export/**/#{@spec.name}.framework"
  frameworks = Pathname.glob(export_dir)
  @outputs[:xcframework] = create_xc_framework_by_frameworks frameworks, @spec.name
end

#collect_xc_frameworksObject



48
49
50
51
52
53
54
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 48

def collect_xc_frameworks
  if @muti
    collect_muti_xcframworks
  else
   collect_single_xcframeworks
  end
end

#create_xc_framework_by_frameworks(frameworks, spec_name) ⇒ Object



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 121

def create_xc_framework_by_frameworks frameworks, spec_name
  command = 'xcodebuild -create-xcframework '
  frameworks.each do |framework|
    command << "-framework #{framework} "
  end
  command << "-output #{@sandbox_root}/#{spec_name}.xcframework 2>&1"
  output = `#{command}`.lines.to_a
  UI.puts("make xcframework command:#{command}")
  UI.puts("make xcframework output:#{output}")
  if $?.exitstatus != 0
    Pod::ErrorUtil.error_report command,output
    Process.exit -1
  end
  "#{@sandbox_root}/#{spec_name}.xcframework"
end

#find_bundles(target_dir) ⇒ Object



222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 222

def find_bundles target_dir
  bundle_root = "#{target_dir}/bundle/"
  pattern = "#{bundle_root}*"
  result = {}
  Pathname.glob(pattern).each do |bundle|
    bundle_relative_path = bundle.to_s.gsub(bundle_root, "")
    plat = bundle_relative_path
    result[plat] = {
      "#{@spec.name}" => "bundle/" + bundle_relative_path + "/*"
    }
  end
  result
end

#fix_xcframework_error(target_dir, name) ⇒ Object



211
212
213
214
215
216
217
218
219
220
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 211

def fix_xcframework_error target_dir, name
  command = "find #{target_dir} -name '*.swiftinterface' -exec sed -i -e 's/#{name}\\.//g' {} \\; && find #{target_dir} -name '*.swiftinterface-e' | xargs rm -rf"
  UI.puts "fix swift error command :#{command}"

  output = `#{command}`.lines.to_a
  if $?.exitstatus != 0
    Pod::ErrorUtil.error_report command,output
    Process.exit -1
  end
end

#generic_new_podspec_hash_muti(target_dir) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 260

def generic_new_podspec_hash_muti target_dir
  work_dir = config.installation_root
  @configs.map do |cfg|
    podspec_path = "#{work_dir}/#{cfg["name"]}/#{cfg["name"]}.podspec"
    if not File.exist? podspec_path
      podspec_path = "#{podspec_path}.json"
    end
    podspec = Pod::Specification.from_file podspec_path
    new_spec_hash = generic_new_podspec_hash podspec
    new_spec_hash[:vendored_frameworks] = "#{podspec.name}.xcframework"
    new_spec_hash = fix_header_file new_spec_hash, "#{target_dir}/#{@spec.name}.xcframework"
    find_bundles("#{target_dir}/#{podspec.name}").each do |plat, value|
      if new_spec_hash[plat]
        new_spec_hash[plat]["resource_bundles"] = value
      else
        new_spec_hash[plat] = {
          "resource_bundles" => value
        }
      end
    end
    require 'json'
    spec_json = JSON.pretty_generate(new_spec_hash) << "\n"
    File.open("#{target_dir}/#{podspec.name}/#{podspec.name}.podspec.json",'wb+') do |f|
      f.write(spec_json)
    end
    UI.puts "result export at :#{target_dir}/#{podspec.name}"
    "#{target_dir}/#{podspec.name}"
  end
end

#outputs(target_dir) ⇒ Object



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 178

def outputs target_dir
  if not File.exist? target_dir
    Pathname.new(target_dir).mkdir
  end
  outputs_xcframework target_dir
  outputs_bundle target_dir
  new_spec_hash = generic_new_podspec_hash @spec
  new_spec_hash[:vendored_frameworks] = "#{@spec.name}.xcframework"
  xcframework_path = "#{target_dir}/#{@spec.name}.xcframework"
  new_spec_hash = fix_header_file new_spec_hash, xcframework_path
  new_spec_hash = fix_bundle_file(@spec, new_spec_hash, @source_dir, xcframework_path)
  find_bundles(target_dir).each do |plat, value| 
    if new_spec_hash[plat]
      new_spec_hash[plat]["resource_bundles"] = value
    else
      new_spec_hash[plat] = {
        "resource_bundles" => value
      }
    end
  end
  require 'json'
  spec_json = JSON.pretty_generate(new_spec_hash) << "\n"
  File.open("#{target_dir}/#{@spec.name}.podspec.json",'wb+') do |f|
    f.write(spec_json)
  end
  # fix xcframework-is-not-a-member-type-of-error https://v3.bbcloud.babybus.com/team/184/wiki/13820
  UI.puts "fix xcframework-is-not-a-member-type-of-error:#{target_dir}"
  fix_xcframework_error(target_dir, @spec.name)

  UI.puts "result export at :#{target_dir} 生成成功".green
  target_dir
end

#outputs_bundle(target_dir) ⇒ Object



245
246
247
248
249
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 245

def outputs_bundle target_dir
  if @outputs[:bundle]
    FileUtils.cp_r(Dir[@outputs[:bundle]],target_dir)
  end
end

#outputs_bundle_muti(target_dir) ⇒ Object



298
299
300
301
302
303
304
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 298

def outputs_bundle_muti target_dir
  @outputs[:bundle].each do |name, path|
    target_dir_path = "#{target_dir}/#{name}/bundle/"
    Pathname.new(target_dir_path).mkpath
    FileUtils.cp_r(path, target_dir_path)
  end
end

#outputs_muti(target_dir) ⇒ Object



251
252
253
254
255
256
257
258
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 251

def outputs_muti target_dir
  if not File.exist? target_dir
    Pathname.new(target_dir).mkdir
  end
  outputs_xcframework_muti target_dir
  outputs_bundle_muti target_dir
  generic_new_podspec_hash_muti target_dir
end

#outputs_xcframework(target_dir) ⇒ Object



236
237
238
239
240
241
242
243
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 236

def outputs_xcframework target_dir
  command = "cp -rp #{@outputs[:xcframework]} #{target_dir} 2>&1"
  output = `#{command}`.lines.to_a
  if $?.exitstatus != 0
    Pod::ErrorUtil.error_report command,output
    Process.exit -1
  end
end

#outputs_xcframework_muti(target_dir) ⇒ Object



290
291
292
293
294
295
296
# File 'lib/cocoapods-xcframework/xbuilder.rb', line 290

def outputs_xcframework_muti target_dir
  @outputs[:xcframework].each do |name, path|
    target_dir_path = "#{target_dir}/#{name}/"
    Pathname.new(target_dir_path).mkpath
    FileUtils.cp_r(path, target_dir_path)
  end
end