require_relative "xcodebuild_raw" module Jxedt class XcodebuildCommand # rubocop:disable Metrics/ClassLength def initialize(options) @options = options case options[:targets][0].platform.name when :ios @options[:device] = "iphoneos" @options[:simulator] = "iphonesimulator" when :tvos @options[:device] = "appletvos" @options[:simulator] = "appletvsimulator" when :watchos @options[:device] = "watchos" @options[:simulator] = "watchsimulator" end @build_args = make_up_build_args(options[:args] || {}) end def run sdks.each { |sdk| build_for_sdk(sdk) @options[:clean_build] = false # 如果需要编译真机和模拟器,那么第二次编译的时候不能clean } targets.each do |target| # create static framework with library create_framework_from_library(target) if target.build_as_library? if Jxedt.config.xcframework? create_xcframework(target) elsif sdks.count > 1 create_fat_framework(target) else collect_output(target, Dir[target_products_dir_of(target, sdks[0]) + "/*"]) end end end private def sdks @sdks ||= begin sdks_ = [] sdks_ << simulator if build_types.include?(:simulator) sdks_ << device if build_types.include?(:device) sdks_ end end def preferred_sdk @preferred_sdk ||= sdks.include?(device) ? device : sdks[0] end def build_types @build_types ||= begin types = [] types << :simulator if simulator_build_enabled? types << :device if device_build_enabled? types end end def make_up_build_args(args) # Note: The build arguments explicitly passed from config_cocoapods_binary_cache # should be preceded by the default arguments so that they could take higher priority # when there are argument collisions in the xcodebuild command. # For ex. `xcodebuild AN_ARG=1 AN_ARG=2` should use `AN_ARG=2` instead. args_ = args.clone args_[:default] ||= [] args_[:simulator] ||= [] args_[:device] ||= [] args_[:default].prepend("BITCODE_GENERATION_MODE=bitcode") if bitcode_enabled? args_[:default].prepend("DEBUG_INFORMATION_FORMAT=dwarf") if disable_dsym? # args_[:simulator].prepend("ARCHS=x86_64", "ONLY_ACTIVE_ARCH=NO") if simulator == "iphonesimulator" # args_[:device].prepend("ONLY_ACTIVE_ARCH=NO") args_[:simulator] += args_[:default] args_[:device] += args_[:default] args_ end def build_for_sdk(sdk) Jxedt::XcodebuildCommand.xcodebuild( sandbox: sandbox, scheme: scheme, targets: targets.map(&:label), configuration: configuration, sdk: sdk, deployment_target: targets.map { |t| t.platform.deployment_target }.max.to_s, log_path: log_path(sdk), clean_build: clean_build?, args: sdk == simulator ? @build_args[:simulator] : @build_args[:device] ) end def create_framework_from_library(target) require_relative 'framework' sdks.each do |sdk| procuct_dir = Pathname.new(target_products_dir_of(target, sdk)) # make static framework fwk = StaticFramework::Tree.new(target.product_module_name, procuct_dir.to_s) # copy library lib_output = fwk.fwk_path + target.product_module_name lib_file = procuct_dir + "lib#{target.name}.a" `lipo -create -output #{lib_output} #{lib_file}` if lib_file.exist? # copy public headers headers_source = target.sandbox.headers_root + 'Public' + target.pod_name Dir.glob("#{headers_source}/**/*.h").each { |h| `ditto #{h} #{fwk.headers_path}/#{File.basename(h)}` } # target support module if target.defines_module? # create modulemap path fwk.module_map_path.mkpath unless fwk.module_map_path.exist? # check and copy umbrella headers umbrella_headers = Dir.glob("#{procuct_dir}/*-umbrella.h") umbrella_headers.each { |h| FileUtils.cp_r(h.to_s, fwk.headers_path) } # check and copy swift headers swift_headers = Dir.glob("#{procuct_dir}/*/*-Swift.h") swift_headers.each { |h| FileUtils.cp_r(h.to_s, fwk.headers_path) } # check and copy swiftmodule files swiftmodule_path = procuct_dir + "#{target.product_module_name}.swiftmodule" FileUtils.cp_r(swiftmodule_path, fwk.module_map_path) if swiftmodule_path.exist? # umbrella header name umbrella_header_name = "#{target.pod_name}-umbrella.h" unless File.exist?("#{fwk.headers_path}/#{umbrella_header_name}") # 从Target Support Files文件夹中获取unbrella header target_support_files_root = target.sandbox.target_support_files_root + target.name Dir.glob("#{target_support_files_root}/*-umbrella.h").each { |h| FileUtils.cp_r(h.to_s, fwk.headers_path + umbrella_header_name) } end # make modulemap if File.exist?("#{fwk.headers_path}/#{umbrella_header_name}") module_map = <