Class: Gym::XcodebuildFixes

Inherits:
Object
  • Object
show all
Defined in:
lib/gym/xcodebuild_fixes/swift_fix.rb,
lib/gym/xcodebuild_fixes/watchkit_fix.rb,
lib/gym/xcodebuild_fixes/package_application_fix.rb

Class Method Summary collapse

Class Method Details

.check_for_swift(pcg) ⇒ Object

Returns true if swift.

Parameters:

  • the

    PackageCommandGenerator

Returns:

  • true if swift



51
52
53
54
55
# File 'lib/gym/xcodebuild_fixes/swift_fix.rb', line 51

def check_for_swift(pcg)
  Helper.log.info "Checking for Swift framework" if $verbose
  default_swift_libs = "#{pcg.appfile_path}/Frameworks/libswift.*" # note the extra ., this is a string representation of a regexp
  zip_entries_matching(pcg.ipa_path, /#{default_swift_libs}/).count > 0
end

.patch_package_applicationObject

Fix PackageApplication Perl script by Xcode to create the IPA from the archive



5
6
7
8
9
10
11
12
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
# File 'lib/gym/xcodebuild_fixes/package_application_fix.rb', line 5

def patch_package_application
  require 'fileutils'

  # Initialization
  @patched_package_application_path = File.join("/tmp", "PackageApplication4Gym")

  return @patched_package_application_path if File.exist?(@patched_package_application_path)

  Dir.mktmpdir do |tmpdir|
    # Check current PackageApplication MD5
    require 'digest'

    path = File.join(Helper.gem_path("gym"), "lib/assets/package_application_patches/PackageApplication_MD5")
    expected_md5 = File.read(path)

    # If that location changes, search it using xcrun --sdk iphoneos -f PackageApplication
    package_application_path = "#{Xcode.xcode_path}/Platforms/iPhoneOS.platform/Developer/usr/bin/PackageApplication"

    raise "Unable to patch the `PackageApplication` script bundled in XCode. This is not supported." unless expected_md5 == Digest::MD5.file(package_application_path).hexdigest

    # Duplicate PackageApplication script to PackageApplication4Gym
    FileUtils.copy_file(package_application_path, @patched_package_application_path)

    # Apply patches to PackageApplication4Gym from patches folder
    Dir[File.join(Helper.gem_path("gym"), "lib/assets/package_application_patches/*.diff")].each do |patch|
      Helper.log.info "Applying Package Application patch: #{File.basename(patch)}" if $verbose
      command = ["patch '#{@patched_package_application_path}' < '#{patch}'"]
      Runner.new.print_command(command, "Applying Package Application patch: #{File.basename(patch)}") if $verbose

      FastlaneCore::CommandExecutor.execute(command: command,
                                          print_all: false,
                                      print_command: $verbose,
                                              error: proc do |output|
                                                ErrorHandler.handle_package_error(output)
                                              end)
    end
  end

  return @patched_package_application_path # Return path to the patched PackageApplication
end

.swift_library_fixObject

Determine whether it is a Swift project and, eventually, include all required libraries to copy from Xcode’s toolchain directory. Since there’s no “xcodebuild” target to do just that, it is done post-build when exporting an archived build.



12
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
# File 'lib/gym/xcodebuild_fixes/swift_fix.rb', line 12

def swift_library_fix
  require 'fileutils'

  return if check_for_swift PackageCommandGenerator

  Helper.log.info "Packaging up the Swift Framework as the current app is a Swift app" if $verbose
  ipa_swift_frameworks = Dir["#{PackageCommandGenerator.appfile_path}/Frameworks/libswift*"]

  Dir.mktmpdir do |tmpdir|
    # Copy all necessary Swift libraries to a temporary "SwiftSupport" directory so that we can
    # easily add it to the .ipa later.
    swift_support = File.join(tmpdir, "SwiftSupport")

    Dir.mkdir(swift_support)

    ipa_swift_frameworks.each do |path|
      framework = File.basename(path)

      FileUtils.copy_file("#{Xcode.xcode_path}/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos/#{framework}", File.join(swift_support, framework))
    end

    # Add "SwiftSupport" to the .ipa archive
    Dir.chdir(tmpdir) do
      command_parts = ["zip --recurse-paths '#{PackageCommandGenerator.ipa_path}' SwiftSupport"]
      command_parts << "> /dev/null" unless $verbose
      Runner.new.print_command(command_parts, "Fix Swift embedded code if needed") if $verbose

      FastlaneCore::CommandExecutor.execute(command: command_parts,
                                          print_all: false,
                                      print_command: !Gym.config[:silent],
                                              error: proc do |output|
                                                ErrorHandler.handle_package_error(output)
                                              end)
    end
  end
end

.watchkit?Boolean

Does this application have a WatchKit target

Returns:

  • (Boolean)


28
29
30
31
32
# File 'lib/gym/xcodebuild_fixes/watchkit_fix.rb', line 28

def watchkit?
  Dir["#{PackageCommandGenerator.appfile_path}/**/*.plist"].any? do |plist_path|
    `/usr/libexec/PlistBuddy -c 'Print WKWatchKitApp' '#{plist_path}' 2>&1`.strip == 'true'
  end
end

.watchkit_fixObject

Determine whether this app has WatchKit support and manually package up the WatchKit framework



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# File 'lib/gym/xcodebuild_fixes/watchkit_fix.rb', line 5

def watchkit_fix
  return unless watchkit?

  Helper.log.info "Adding WatchKit support" if $verbose

  Dir.mktmpdir do |tmpdir|
    # Make watchkit support directory
    watchkit_support = File.join(tmpdir, "WatchKitSupport")
    Dir.mkdir(watchkit_support)

    # Copy WK from Xcode into WatchKitSupport
    FileUtils.copy_file("#{Xcode.xcode_path}/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/Library/Application Support/WatchKit/WK", File.join(watchkit_support, "WK"))

    # Add "WatchKitSupport" to the .ipa archive
    Dir.chdir(tmpdir) do
      abort unless system %(zip --recurse-paths "#{PackageCommandGenerator.ipa_path}" "WatchKitSupport" > /dev/null)
    end

    Helper.log.info "Successfully added WatchKit support" if $verbose
  end
end

.zip_entries_matching(zipfile, file_pattern) ⇒ Object

return the entries (files or directories) in the zip matching the pattern

Parameters:

  • zipfile

    a zipfile

Returns:

  • the files or directories matching the pattern



60
61
62
63
64
65
66
67
68
# File 'lib/gym/xcodebuild_fixes/swift_fix.rb', line 60

def zip_entries_matching(zipfile, file_pattern)
  files = []
  Zip::File.open(zipfile) do |zip_file|
    zip_file.each do |entry|
      files << entry.name if entry.name.match file_pattern
    end
  end
  files
end