Skip to content

Instantly share code, notes, and snippets.

@wojciech-kulik
Last active September 14, 2021 19:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wojciech-kulik/e2470d8280b5ca4cf81201205fd2bffc to your computer and use it in GitHub Desktop.
Save wojciech-kulik/e2470d8280b5ca4cf81201205fd2bffc to your computer and use it in GitHub Desktop.
Duplicated frameworks remover
#
# DuplicatedFrameworksRemover.rb
# Created by Wojciech Kulik on 14/09/2021.
#
# Description:
# This code fixes warnings caused by linking the same frameworks in multiple targets.
#
# Sample warning: "objc[1111]: Class XXXX is implemented in both path/FrameworkName1 and path/FrameworkName2.
# One of the two will be used. Which one is undefined."
# Usage:
# - Put this file next to your Podfile
# - Add in the Podfile:
# load 'DuplicatedFrameworksRemover.rb'
#
# post_install do |installer|
# remove_duplicated_frameworks('Pods-YourMainTargetName', installer)
# end
def remove_duplicated_frameworks(app_pod_name, installer)
test_targets = get_test_targets(app_pod_name, installer)
puts "Detected test targets: #{test_targets}"
puts "Removing duplicated frameworks from OTHER_LDFLAGS"
targets = installer.aggregate_targets.select { |x| !test_targets.include?(x.name) }
# Checks each pair of targets if they have common pods. Duplicates are removed from the first one's xcconfig.
for i in 0..targets.size-1 do
target = targets[i]
remainingAppPodTargets = targets[i+1..targets.size-1].flat_map(&:pod_targets)
target.xcconfigs.each do |config_name, config_file|
# Removes all frameworks which exist in other pods
remainingAppPodTargets
.flat_map { |pod_target| get_framework_names(pod_target) }
.each { |framework| config_file.frameworks.delete(framework) }
# Saves updated xcconfig
xcconfig_path = target.xcconfig_path(config_name)
config_file.save_as(xcconfig_path)
end
end
end
def get_test_targets(app_pod_name, installer)
installer.aggregate_targets
.find { |x| x.name == app_pod_name }
.user_project
.targets
.select { |x| is_test_target(x) }
.map { |x| "Pods-#{x}" }
.uniq
end
def is_test_target(target)
target.build_configurations.any? do |config|
target.build_settings(config.name)["TEST_TARGET_NAME"] != nil
end
end
def get_framework_names(pod_target)
frameworkNames = pod_target.specs.flat_map do |spec|
# We should take framework names from 'vendored_frameworks'.
# If it's not defined, we use 'spec.name' instead.
#
# spec.name can be defined like Framework/Something - we take the first part
# because that's what appears in OTHER_LDFLAGS.
frameworkPaths = unless spec.attributes_hash['ios'].nil?
then spec.attributes_hash['ios']['vendored_frameworks']
else spec.attributes_hash['vendored_frameworks']
end || [spec.name.split(/\//, 2).first]
map_paths_to_filenames(frameworkPaths)
end
frameworkNames.uniq
end
def map_paths_to_filenames(paths)
Array(paths).map(&:to_s).map do |filename|
extension = File.extname filename
File.basename filename, extension
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment