• The problem
  • Removed manually
  • The script to delete
    • Delete methods
    • Deleted code
    • Remove the timing
  • Complete the process
  • See Also

The problem

After upgrading Xcode12, target (ReadInJoyTests) reported an error:

error: Cycle inside ReadInJoyTests; building could produce unreliable results.
Cycle details:To Target'ReadInJoyTests': CodeSign /Users/yoferzhang/Library/Developer/Xcode/DerivedData/QQMSFContact-gpvqexdcrtvrsdczqfqownxrezqo/Build/Products/Debug-iph Onesimulator/QQ app/EarlGrey. Framework "That command depends on the commandin Target 'ReadInJoyTests': script phase “[CP] Copy Pods Resources”
○ Target 'ReadInJoyTests': CodeSign /Users/yoferzhang/Library/Developer/Xcode/DerivedData/QQMSFContact-gpvqexdcrtvrsdczqfqownxrezqo/Build/Products/Debug-iph onesimulator/QQ.app/EarlGrey.frameworkCopy the code

ReadInJoyTests target [CP] Copy Pods Resources Output file lists

Removed manually

After manual clearing, pod install will still be generated.

The script to delete

Consider whether you can script it out.

Delete methods

Script deletion can be divided into the following steps:

  1. Get the main projectxcodeproj
  2. Find the targetReadInJoyTests target
  3. Find the build phase[CP] Copy Pods Resources
  4. Save the project

Deleted code

require 'xcodeproj'

def delete_rij_tests_output_file_lists
    puts "===================> Start delete ReadInJoyTests Target [CP] Copy Pods Resources output file lists"

    project_path = './QQMSFContact.xcodeproj'
    project = Xcodeproj::Project.open(project_path)
    project.targets.each do |target|
        if target.name == "ReadInJoyTests"
            puts "===================> Find ReadInJoyTests Target"
            build_phase = target.build_phases.find { |bp| bp.display_name == '[CP] Copy Pods Resources' }

            puts "===================> Before delete, Output file lists:"
            puts build_phase.output_file_list_paths
            
            # delete
            while build_phase.output_file_list_paths.length > 0
                build_phase.output_file_list_paths.pop()
            end
        end
    end

    Save the project file
    project.save
    puts "===================> Finish delete ReadInJoyTests Target [CP] Copy Pods Resources output file lists"
end
Copy the code

Remove the timing

Let’s start by looking at cocoapods hook execution order

  1. Terminal Execution commandpod install
  2. runpodfileThe ruby method
  3. Perform the hookspre_install
  4. Executes the pod Install action, but the changes are still in the installer in memory and have not yet been written to disk
  5. Perform the hookspost_install, again not written to disk
  6. Writes the installer changes to disk

If you execute delete_rij_tests_output_file_lists in post_install, the pod changes in post_install have not yet been written to disk, Delete_rij_tests_output_file_lists changes are overwritten by pod writes to disk after post_install. The deletion fails.

Debugging found that if the Output file Paths content existed prior to step 3, delete it in post_install and output file Paths will not be regenerated on overwrite writes.

In other words, you can use the script to write path to cocoapods before step 3 to trick cocoapods into believing that path exists. The delete logic is then performed in post_install, which solves the problem.

The code to write path is:

def add_rij_tests_temp_output_file_list
    project_path = './QQMSFContact.xcodeproj'
    project = Xcodeproj::Project.open(project_path)
    project.targets.each do |target|
        if target.name == "ReadInJoyTests"
            puts "===================> Find ReadInJoyTests Target"
            build_phase = target.build_phases.find { |bp| bp.display_name == '[CP] Copy Pods Resources' }

            puts "===================> Before add, temp output file lists:"
            puts build_phase.output_file_list_paths
            
            list_path = '${PODS_ROOT}/Target Support Files/Pods-ReadInJoyTests/Pods-ReadInJoyTests-resources-${CONFIGURATION}-output-files.xcfilelist'
            # add path
            if build_phase.output_file_list_paths.include? (list_path) ==false
                build_phase.output_file_list_paths.push(list_path)
            end
        end
    end

    Save the project file
    project.save
end
Copy the code

The last modified podfile is

# omit the above two method definitions
post_install do |installer|
	# omit...
  
  ReadInJoyTests Target [CP] Copy Pods Resources output file Lists
  delete_rij_tests_output_file_lists
end

# pod install # pod install # pod install # pod install
add_rij_tests_temp_output_file_list
Copy the code

Complete the process

Finally, look at the complete process

  1. Temporary addoutput file path, let Cocoapods think this timeinstallThere is no need to add path.
  2. Install builds project changes (without adding path)
  3. post_installTo deleteoutput file path
  4. Pod writes install to disk.

See Also

Finally, a deletion method without xcodeProj tool is provided

post_install do |installer|

  installer.aggregate_targets.each do |target|
    if target.name == "Pods-ReadInJoyTests"
      puts "==========> Find Pods-ReadInJoyTests:"
      project = target.user_project
      puts project
      project.targets.each do |sub_target|
        if sub_target.name =="ReadInJoyTests"
          puts "==========> Find ReadInJoyTests Target"
          build_phase = sub_target.build_ phases. find { |bp| bp.display_name == '[CP] Copy Pods Resources' }
          puts "==========> Before delete, Output file lists:"
          puts build_phase.output_file_list_paths
          
          # delete
          build_phase.output_file_list_paths.pop( )
          puts"==========> After delete, Output file lists:"
          puts build_phase.output_file_list_paths
        end
      end
      project. save
    end
  end
end
Copy the code