Top Level Namespace

Defined Under Namespace

Modules: CocoapodsBinary, Pod

Constant Summary collapse

CONFIGURATION =
"Debug"
PLATFORMS =
{ 'iphonesimulator' => 'iOS',
'appletvsimulator' => 'tvOS',
'watchsimulator' => 'watchOS' }

Instance Method Summary collapse

Instance Method Details

#append_bin_resources_script(script_path, bin_resources) ⇒ Object

仅追加 .bin 安装(保留相对路径;不改动原有 Debug 资源块)



421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
# File 'lib/cocoapods-binary-matchup/Main.rb', line 421

def append_bin_resources_script(script_path, bin_resources)
    return if bin_resources.empty?

    content = script_path.read
    content = content.gsub(
        /\n?[ \t]*# Prebuilt Framework Bin Resources\n.*?echo "Prebuilt framework bin resources installation completed"\n/m,
        "\n"
    )

    block = "# Prebuilt Framework Bin Resources\n"
    block += "echo \"Installing prebuilt framework bin resources...\"\n"
    bin_resources.each do |resource|
        block += "PREBUILT_BIN_SRC=\"#{resource[:source]}\"\n"
        block += "PREBUILT_BIN_DST=\"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/#{resource[:relative]}\"\n"
        block += "mkdir -p \"$(dirname \"$PREBUILT_BIN_DST\")\"\n"
        block += "if [[ -e \"$PREBUILT_BIN_SRC\" ]]; then\n"
        block += "  cp -f \"$PREBUILT_BIN_SRC\" \"$PREBUILT_BIN_DST\"\n"
        block += "fi\n"
    end
    block += "echo \"Prebuilt framework bin resources installation completed\"\n"

    if content.include?('exit 0')
        content = content.sub(/exit 0/, "#{block}\nexit 0")
    else
        content = content + "\n#{block}"
    end
    script_path.write(content)
end

#bin_relative_path_for_copy(child, source_root_dir) ⇒ Object

仅 .bin:Apps/Cocome/Resources/m/m.bin -> m/m.bin



244
245
246
247
248
249
250
251
252
253
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 244

def bin_relative_path_for_copy(child, source_root_dir)
  rel_parts = child.relative_path_from(source_root_dir).each_filename.to_a
  if (idx = rel_parts.index('Resources')) && idx < rel_parts.length - 1
    return Pathname.new(rel_parts[(idx + 1)..-1].join('/'))
  end
  if rel_parts.length >= 2
    return Pathname.new(rel_parts[-2..-1].join('/'))
  end
  Pathname.new(child.basename)
end

#build_for_iosish_platform(sandbox, build_dir, output_path, target, device, simulator, bitcode_enabled, custom_build_options = [], custom_build_options_simulator = []) ⇒ Object

Build specific target to framework file @param [PodTarget] target a specific pod target



13
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 13

def build_for_iosish_platform(sandbox, 
                              build_dir, 
                              output_path,
                              target, 
                              device, 
                              simulator,
                              bitcode_enabled,
                              custom_build_options = [], # Array<String>
                              custom_build_options_simulator = [] # Array<String>
                              )
  
  target_label = target.label # name with platform if it's used in multiple platforms
  Pod::UI.puts "Prebuilding #{target_label}..."
  
  other_options = []
  # bitcode enabled
  other_options += ['BITCODE_GENERATION_MODE=bitcode'] if bitcode_enabled

  is_succeed, _ = xcodebuild(sandbox, target_label, device, target, other_options + custom_build_options)
  exit 1 unless is_succeed
  if Pod::Podfile::DSL.simulator_build_enabled
    # make less arch to iphone simulator for faster build
    custom_build_options_simulator += ['ARCHS=x86_64', 'ONLY_ACTIVE_ARCH=NO'] if simulator == 'iphonesimulator'
    is_succeed, _ = xcodebuild(sandbox, target_label, simulator, target, other_options + custom_build_options_simulator)
    exit 1 unless is_succeed
  end

  # paths
  target_name = target.name # equals target.label, like "AFNeworking-iOS" when AFNetworking is used in multiple platforms.
  module_name = target.product_module_name
  device_framework_path = "#{build_dir}/#{CONFIGURATION}-#{device}/#{target_name}/#{module_name}.framework"
  device_binary = device_framework_path + "/#{module_name}"

  tmp_lipoed_binary_path = "#{build_dir}/#{target_name}"
  lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_binary}`

  if Pod::Podfile::DSL.simulator_build_enabled
    simulator_framework_path = "#{build_dir}/#{CONFIGURATION}-#{simulator}/#{target_name}/#{module_name}.framework"
    simulator_binary = simulator_framework_path + "/#{module_name}"
    return unless File.file?(device_binary) && File.file?(simulator_binary)
  else
    return unless File.file?(device_binary)
  end

  puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
  FileUtils.mv tmp_lipoed_binary_path, device_binary, :force => true
  
  # collect the swiftmodule file for various archs.
  device_swiftmodule_path = device_framework_path + "/Modules/#{module_name}.swiftmodule"
  if File.exist?(device_swiftmodule_path) && Pod::Podfile::DSL.simulator_build_enabled
    simulator_framework_path = "#{build_dir}/#{CONFIGURATION}-#{simulator}/#{target_name}/#{module_name}.framework"
    simulator_swiftmodule_path = simulator_framework_path + "/Modules/#{module_name}.swiftmodule"
    FileUtils.cp_r simulator_swiftmodule_path + "/.", device_swiftmodule_path
  end

  # combine the generated swift headers
  # (In xcode 10.2, the generated swift headers vary for each archs)
  # https://github.com/leavez/cocoapods-binary/issues/58
  if Pod::Podfile::DSL.simulator_build_enabled
    device_generated_swift_header_path = device_framework_path + "/Headers/#{module_name}-Swift.h"
    device_header = File.read(device_generated_swift_header_path)
    simulator_generated_swift_header_path = simulator_framework_path + "/Headers/#{module_name}-Swift.h"
    if File.exist? simulator_generated_swift_header_path
      
      simulator_header = File.read(simulator_generated_swift_header_path)
      # https://github.com/Carthage/Carthage/issues/2718#issuecomment-473870461
      combined_header_content = %Q{
  #if TARGET_OS_SIMULATOR // merged by cocoapods-binary

  #{simulator_header}

  #else // merged by cocoapods-binary

  #{device_header}

  #endif // merged by cocoapods-binary
  }
      File.write(device_generated_swift_header_path, combined_header_content.strip)
    end
  else
    device_generated_swift_header_path = device_framework_path + "/Headers/#{module_name}-Swift.h"
    if File.exist?(device_generated_swift_header_path)
      device_header = File.read(device_generated_swift_header_path)
      combined_header_content = %Q{
        #if TARGET_OS_SIMULATOR // merged by cocoapods-binary

        #else // merged by cocoapods-binary
      
        #{device_header}
      
        #endif // merged by cocoapods-binary
        }
      File.write(device_generated_swift_header_path, combined_header_content.strip)
    end
  end

  # handle the dSYM files
  # device_dsym = "#{device_framework_path}.dSYM"
  # if File.exist? device_dsym
  #   # lipo the simulator dsym
  #   simulator_dsym = "#{simulator_framework_path}.dSYM"
  #   if File.exist? simulator_dsym
  #     tmp_lipoed_binary_path = "#{output_path}/#{module_name}.draft"
  #     lipo_log = `lipo -create -output #{tmp_lipoed_binary_path} #{device_dsym}/Contents/Resources/DWARF/#{module_name} #{simulator_dsym}/Contents/Resources/DWARF/#{module_name}`
  #     puts lipo_log unless File.exist?(tmp_lipoed_binary_path)
  #     FileUtils.mv tmp_lipoed_binary_path, "#{device_framework_path}.dSYM/Contents/Resources/DWARF/#{module_name}", :force => true
  #   end
  #   # move
  #   FileUtils.mv device_dsym, output_path, :force => true
  # end

  # output
  output_path.mkpath unless output_path.exist?

  if target.static_framework?
    # 🔑 添加资源处理 - 修复静态库资源丢失问题
    copy_resources_to_framework(sandbox, target, device_framework_path)
  end

  FileUtils.mv device_framework_path, output_path, :force => true

  # resource_bundles(如 MatchUpSecurityWB.bundle)由 xcodebuild 生成在 products 目录,
  # 原先只 mv 了 .framework,bundle 会随 build_dir 被删掉 → App 里找不到 m/m.bin。
  # Integration 会把 resource_bundles 改成 resources: ["Xxx.bundle"],必须放在预编译产物根目录。
  copy_resource_bundles_to_output(sandbox, target, output_path, build_dir, device)

end

#build_framework_resources_block(framework_resources) ⇒ Object

构建framework资源安装代码块



407
408
409
410
411
412
413
414
415
416
417
418
# File 'lib/cocoapods-binary-matchup/Main.rb', line 407

def build_framework_resources_block(framework_resources)
    block = "  # Prebuilt Framework Resources\n"
    block += "  echo \"Installing prebuilt framework resources...\"\n"
    
    framework_resources.each do |resource|
        block += "  install_resource \"#{resource}\"\n"
    end
    
    block += "  echo \"Prebuilt framework resources installation completed\"\n"
    
    return block
end

#class_attr_accessor(symbol) ⇒ Object

attr_accessor for class variable. usage:

```
class Pod
  class_attr_accessor :is_prebuild_stage
end
```


10
11
12
# File 'lib/cocoapods-binary-matchup/tool/tool.rb', line 10

def class_attr_accessor(symbol)
    self.class.send(:attr_accessor, symbol)
end

#collect_prebuilt_framework_bin_resources(installer, aggregate_target) ⇒ Object

仅收集 framework 内 .bin(支持 m/m.bin 嵌套)



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/cocoapods-binary-matchup/Main.rb', line 277

def collect_prebuilt_framework_bin_resources(installer, aggregate_target)
    bin_resources = []
    prebuilt_pod_names = installer.refresh_prebuild_pod_names!

    aggregate_target.pod_targets.each do |pod_target|
        next unless prebuilt_pod_names.include?(pod_target.pod_name)

        pod_dir = installer.sandbox.pod_dir(pod_target.pod_name)
        next unless pod_dir.exist?

        pod_dir.children.select { |c| c.directory? && c.extname == '.framework' }.each do |framework_dir|
            framework_name = framework_dir.basename.to_s
            Dir.glob(framework_dir.join('**/*.bin')).each do |bin_path|
                rel = Pathname(bin_path).relative_path_from(framework_dir).to_s
                bin_resources << {
                    source: "${PODS_ROOT}/#{pod_target.pod_name}/#{framework_name}/#{rel}",
                    relative: rel
                }
            end
        end
    end

    bin_resources.uniq { |r| r[:source] }
end

#collect_prebuilt_framework_resources(installer, aggregate_target) ⇒ Object

收集预编译framework中的资源



243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/cocoapods-binary-matchup/Main.rb', line 243

def collect_prebuilt_framework_resources(installer, aggregate_target)
    framework_resources = []
    
    # 获取预编译的pod列表 - 强制刷新以确保获取最新状态
    prebuilt_pod_names = installer.refresh_prebuild_pod_names!
    
    aggregate_target.pod_targets.each do |pod_target|
        next unless prebuilt_pod_names.include?(pod_target.pod_name)
        
        Pod::UI.puts "    📱 Scanning prebuilt pod: #{pod_target.pod_name}"
        
        # 获取pod目录
        pod_dir = installer.sandbox.pod_dir(pod_target.pod_name)
        next unless pod_dir.exist?
        
        # 查找framework目录
        framework_dirs = pod_dir.children.select { |child| 
            child.directory? && child.extname == '.framework' 
        }
        
        framework_dirs.each do |framework_dir|
            framework_name = framework_dir.basename.to_s
            Pod::UI.puts "      🔍 Scanning framework: #{framework_name}"
            
            # 扫描framework中的资源
            resources = scan_framework_resources(framework_dir, pod_target.pod_name)
            framework_resources.concat(resources)
        end
    end
    
    framework_resources.uniq
end

#copy_resource_bundles_to_output(sandbox, target, output_path, build_dir, device) ⇒ Object

把 podspec resource_bundles 产物拷到预编译输出目录(与 .framework 同级)



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 142

def copy_resource_bundles_to_output(sandbox, target, output_path, build_dir, device)
  output_path = Pathname(output_path)
  output_path.mkpath unless output_path.exist?

  products_dir = Pathname("#{build_dir}/#{CONFIGURATION}-#{device}/#{target.name}")
  copied = []

  if products_dir.exist?
    products_dir.children.select { |p| p.directory? && p.extname == '.bundle' }.each do |bundle|
      dest = output_path + bundle.basename
      FileUtils.rm_rf(dest) if dest.exist?
      FileUtils.cp_r(bundle.to_s, dest.to_s)
      copied << bundle.basename.to_s
      Pod::UI.puts "  📦 Copied resource bundle from build products: #{bundle.basename}"
    end
  end

  # 兜底:xcodebuild 未产出 bundle 时,按 file_accessor.resource_bundles 从源码组装
  # (保留 Resources/ 之后的相对路径,如 m/m.bin)
  expected_bundles = {}
  Array(target.file_accessors).each do |fa|
    next unless fa.respond_to?(:resource_bundles)
    fa.resource_bundles.each do |name, paths|
      expected_bundles[name] ||= []
      expected_bundles[name].concat(Array(paths))
    end
  end

  expected_bundles.each do |bundle_name, paths|
    dest_bundle = output_path + "#{bundle_name}.bundle"
    next if dest_bundle.exist? && copied.include?("#{bundle_name}.bundle")

    Pod::UI.puts "  📦 Assembling resource bundle from sources: #{bundle_name}.bundle"
    FileUtils.rm_rf(dest_bundle) if dest_bundle.exist?
    dest_bundle.mkpath

    pod_root = Pathname(sandbox.pod_dir(target.pod_name))
    Array(paths).each do |path|
      src = Pathname(path)
      next unless src.file?

      relative = resource_bundle_relative_path(src, pod_root)
      dest = dest_bundle + relative
      dest.dirname.mkpath unless dest.dirname.exist?
      FileUtils.cp(src.to_s, dest.to_s)
      Pod::UI.puts "    📄 #{relative}"
    end
    copied << "#{bundle_name}.bundle"
  end

  Pod::UI.puts "  ✅ Resource bundles ready: #{copied.uniq.join(', ')}" unless copied.empty?
end

#copy_resources_to_framework(sandbox, target, framework_path) ⇒ Object

新增函数:拷贝资源文件到 framework



205
206
207
208
209
210
211
212
213
214
215
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 205

def copy_resources_to_framework(sandbox, target, framework_path)
  Pod::UI.puts "📋 Processing resources for #{target.name}..."
  
  pod_dir = Pathname.new(sandbox.pod_dir(target.pod_name))
  framework_dir = Pathname.new(framework_path)
  
  # 直接递归扫描 pod 目录下的所有资源文件,拷贝到 framework 根目录
  scan_and_copy_resources_flat(pod_dir, framework_dir)
  
  Pod::UI.puts "✅ Resource processing completed for #{target.name}"
end

#find_and_copy_resources_recursively(current_dir, target_dir, source_root_dir, resource_extensions, special_extensions) ⇒ Object

递归查找资源文件并拷贝



256
257
258
259
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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 256

def find_and_copy_resources_recursively(current_dir, target_dir, source_root_dir, resource_extensions, special_extensions)
  # 确保所有参数都是Pathname类型
  current_dir = Pathname.new(current_dir) unless current_dir.is_a?(Pathname)
  target_dir = Pathname.new(target_dir) unless target_dir.is_a?(Pathname) 
  source_root_dir = Pathname.new(source_root_dir) unless source_root_dir.is_a?(Pathname)
  
  return unless current_dir.exist? && current_dir.directory?
  
  current_dir.children.each do |child|
    # 跳过隐藏文件和系统目录
    next if child.basename.to_s.start_with?('.')
    next if ['.git', '.svn', 'node_modules', '.DS_Store'].include?(child.basename.to_s)
    
    if child.directory?
      # 检查是否是特殊资源目录(需要完整保留的)
      if special_extensions.include?(child.extname)
        Pod::UI.puts "  📦 Copying special directory: #{child.basename}"
        target_path = target_dir + child.basename
        FileUtils.cp_r(child.to_s, target_path.to_s, :remove_destination => true)
      else
        # 递归处理普通目录
        find_and_copy_resources_recursively(child, target_dir, source_root_dir, resource_extensions, special_extensions)
      end
    else
      # 检查是否是资源文件
      if resource_extensions.include?(child.extname.downcase)
        # .bin:仅扩展路径保留(m/m.bin),其它资源仍平铺,逻辑不变
        if child.extname.downcase == '.bin'
          relative_path = bin_relative_path_for_copy(child, source_root_dir)
          target_path = target_dir + relative_path
          Pod::UI.puts "  📄 Copying bin resource: #{relative_path}"
          target_path.dirname.mkpath unless target_path.dirname.exist?
          FileUtils.cp(child.to_s, target_path.to_s)
        else
          Pod::UI.puts "  📄 Copying resource file: #{child.basename}"
          target_path = target_dir + child.basename
          
          # 处理文件名冲突(如果有重名文件,添加路径前缀)
          if target_path.exist?
            # 计算相对于根目录的路径作为前缀
            relative_dir = child.dirname.relative_path_from(source_root_dir)
            safe_name = "#{relative_dir.to_s.gsub('/', '_')}_#{child.basename}"
            target_path = target_dir + safe_name
            Pod::UI.puts "    ⚠️  File name conflict, renamed to: #{safe_name}"
          end
          
          FileUtils.cp(child.to_s, target_path.to_s)
        end
      end
    end
  end
end

#modify_resources_script(script_path, framework_resources) ⇒ Object

修改resources脚本,添加framework资源



350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
# File 'lib/cocoapods-binary-matchup/Main.rb', line 350

def modify_resources_script(script_path, framework_resources)
    return if framework_resources.empty?
    
    original_content = script_path.read
    
    # 检查是否已经添加过framework资源(避免重复)
    # if original_content.include?('# Prebuilt Framework Resources')
    #     Pod::UI.puts "    ℹ️  Framework resources already added, skipping"
    #     return
    # end
    
    # Pod::UI.puts "    📝 Adding #{framework_resources.count} framework resources to script"
    # framework_resources.each_with_index do |resource, index|
    #     Pod::UI.puts "      #{index + 1}. #{resource}"
    # end
    
    # 构建要添加的资源安装代码
    framework_resources_block = build_framework_resources_block(framework_resources)
    
    # 在Debug配置块中插入framework资源(而不是脚本末尾)
    debug_pattern = /if \[\[ "\$CONFIGURATION" == "Debug" \]\]; then/
    if original_content.match(debug_pattern)
        # 找到Debug配置块,在其中插入framework资源
        modified_content = original_content.sub(debug_pattern) do |match|
            "#{match}\n#{framework_resources_block}"
        end
    else
        # 如果没有找到Debug配置块,创建一个新的
        framework_resources_with_condition = <<~SCRIPT
        if [[ "$CONFIGURATION" == "Debug" ]]; then
        #{framework_resources_block}
        fi
        SCRIPT
        
        # 在脚本末尾(exit 0之前)插入
        if original_content.include?('exit 0')
            modified_content = original_content.sub(/exit 0/, "#{framework_resources_with_condition}\nexit 0")
        else
            modified_content = original_content + "\n#{framework_resources_with_condition}"
        end
    end
    
    # 写回修改后的内容
    script_path.write(modified_content)
    
    Pod::UI.puts "    ✅ Script modified successfully"
    
    # 显示修改后脚本的相关部分以便验证
    debug_lines = modified_content.lines.select.with_index do |line, index|
        line.include?('CONFIGURATION') || line.include?('Prebuilt Framework') || 
        (index > 0 && modified_content.lines[index-1].include?('CONFIGURATION'))
    end
    Pod::UI.puts "    📄 Debug configuration block preview:"
    debug_lines.first(5).each { |line| Pod::UI.puts "      #{line.chomp}" }
end

#resource_bundle_relative_path(file_path, pod_root) ⇒ Object

Apps/Cocome/Resources/m/m.bin -> m/m.bin(与 CocoaPods resource_bundle 常见布局一致)



196
197
198
199
200
201
202
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 196

def resource_bundle_relative_path(file_path, pod_root)
  rel_parts = Pathname(file_path).relative_path_from(Pathname(pod_root)).each_filename.to_a rescue [file_path.basename.to_s]
  if (idx = rel_parts.index('Resources')) && idx < rel_parts.length - 1
    return Pathname.new(rel_parts[(idx + 1)..-1].join('/'))
  end
  Pathname.new(file_path.basename)
end

#scan_and_copy_resources_flat(source_dir, target_dir) ⇒ Object

递归扫描资源文件并平铺拷贝到目标目录



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 218

def scan_and_copy_resources_flat(source_dir, target_dir)
  # 确保参数是Pathname类型
  source_dir = Pathname.new(source_dir) unless source_dir.is_a?(Pathname)
  target_dir = Pathname.new(target_dir) unless target_dir.is_a?(Pathname)
  
  Pod::UI.puts "📁 Recursively scanning directory: #{source_dir}"
  
  # 资源文件扩展名
  resource_extensions = [
    '.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg',     # 图片
    '.storyboard', '.xib', '.storyboardc', '.nib',        # 界面文件
    '.ttf', '.otf', '.woff', '.woff2',                    # 字体
    '.mp3', '.wav', '.m4a', '.mp4', '.mov', '.avi',       # 媒体
    '.json', '.plist', '.strings', '.xcassets',           # 配置文件
    '.bin',                                               # 二进制资源
    'metallib'                                            # metal or opengl文件
  ]
  
  # 特殊处理的目录类型(这些需要完整保留)
  special_directory_extensions = ['.bundle', '.xcassets', '.lproj']
  
  # 递归查找并拷贝资源文件,传递原始根目录用于路径计算
  find_and_copy_resources_recursively(source_dir, target_dir, source_dir, resource_extensions, special_directory_extensions)
end

#scan_framework_resources(framework_dir, pod_name) ⇒ Object

扫描framework中的资源文件



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
# File 'lib/cocoapods-binary-matchup/Main.rb', line 303

def scan_framework_resources(framework_dir, pod_name)
    resources = []
    framework_name = framework_dir.basename.to_s
    
    Pod::UI.puts "      🎯 Framework path: #{framework_dir}"
    
    # 资源文件类型(.bin 由 append_bin_resources_script 单独处理,避免平铺路径错误)
    resource_patterns = [
        '*.png', '*.jpg', '*.jpeg', '*.gif', '*.webp',     # 图片
        '*.storyboard', '*.xib',                           # 界面文件
        '*.storyboardc',                                   # 编译后的storyboard
        '*.nib',                                           # 编译后的xib
        '*.bundle',                                        # 资源包
        '*.ttf', '*.otf',                                  # 字体
        '*.mp3', '*.wav', '*.m4a', '*.mp4', '*.mov',        # 媒体
        '*.metallib'                                            # metal or opengl文件
    ]
    
    # 扫描framework根目录
    resource_patterns.each do |pattern|
        Dir.glob(framework_dir + pattern).each do |resource_path|
            resource_file = Pathname(resource_path)
                # 其他资源使用BUILT_PRODUCTS_DIR/framework路径
                # 例如:${PODS_ROOT}/CocoaDebug/CocoaDebug.framework/App.storyboardc
            resource_entry = "${PODS_ROOT}/#{pod_name}/#{framework_name}/#{resource_file.basename}"            
            resources << resource_entry
        end
    end
    
    # 扫描framework/Resources目录
    resources_dir = framework_dir + 'Resources'
    if resources_dir.exist?
        resource_patterns.each do |pattern|
            Dir.glob(resources_dir + pattern).each do |resource_path|
                resource_file = Pathname(resource_path)
                
                # Resources目录中的资源也使用BUILT_PRODUCTS_DIR路径
                resource_entry = "${PODS_ROOT}/#{pod_name}/#{framework_name}/#{resource_file.basename}"
                resources << resource_entry                
            end
        end
    end
    
    resources
end

#xcodebuild(sandbox, target, sdk = 'macosx', deployment_target = nil, other_options = []) ⇒ Object



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/cocoapods-binary-matchup/rome/build_framework.rb', line 309

def xcodebuild(sandbox, target, sdk='macosx', deployment_target=nil, other_options=[])
  args = %W(-project #{sandbox.project_path.realdirpath} -scheme #{target} -configuration #{CONFIGURATION} -sdk #{sdk} )
  platform = PLATFORMS[sdk]
  args += Fourflusher::SimControl.new.destination(:oldest, platform, deployment_target) unless platform.nil?
  args += other_options
  Pod::UI.puts "📦 start compile project #{target} (#{args}) "
  log = `xcodebuild #{args.join(" ")} 2>&1`
  exit_code = $?.exitstatus  # Process::Status
  is_succeed = (exit_code == 0)

  if !is_succeed
    Pod::UI.puts "❌ Build failed for target #{target} (exit code: #{exit_code})".red
    begin
        if log.include?('** BUILD FAILED **')
            # use xcpretty to print build log
            # 64 represent command invalid. http://www.manpagez.com/man/3/sysexits/
            printer = XCPretty::Printer.new({:formatter => XCPretty::Simple, :colorize => 'auto'})
            log.each_line do |line|
              printer.pretty_print(line)
            end
        else
            raise "shouldn't be handle by xcpretty"
        end
    rescue
        puts log.red
    end
    Pod::UI.puts "💥 Compilation terminated due to build failure. Please check the error messages above.".red
    exit 1
  end
  [is_succeed, log]
end