One weird Podfile trick to manage your App farm
We have a lot of apps in Wikia and a lot more to come!
To manage the codebase we're using CocoaPods with our whole code split into local Development Pods. Every app is generated from a thin skeleton project that pulls the rest of the code as Pods.
For every App to have something special, we can add additional Pods only for this one app, and the main Podfile from our skeleton App only includes the App-specific Podfile:
local_podfile = "keep/Podfile"
eval(File.open(local_podfile).read) if File.exist? local_podfile
Additionally if we want to add some classes or resources to the App, that are not a separate Pod - for instance code that makes use of the above included new Pods - we use this:
post_install do |installer_representation|
project = Xcodeproj::Project.open('Project.xcodeproj')
target = project.targets[0]
code_directory = Dir.pwd + '/keep/Classes/'
code_directory_glob = code_directory + '**/*'
res_directory = Dir.pwd + '/keep/Resources/'
res_directory_glob = res_directory + '*' #include folders as folders, not recursively
puts "Adding custom code from #{code_directory} directory"
Dir.glob(code_directory_glob) do |f|
if project.reference_for_path(f)
next
end
if f.include? '.m'
libFile = project.new_file("#{f}")
puts "Adding %s to %s Source Build Phases" % [libFile, target.name]
target.source_build_phase.add_file_reference(libFile, avoid_duplicates = true)
elsif f.include? '.h'
libFile = project.new_file("#{f}")
puts "Adding %s to %s Copy Headers Phases" % [libFile, target.name]
target.headers_build_phase.add_file_reference(libFile, avoid_duplicates = true)
end
end if File.directory?(code_directory)
puts "Adding custom resources from #{res_directory} directory"
Dir.glob(res_directory_glob) do |f|
if File.directory?(f)
if Dir[ f +'/*'].empty?
puts "Directory empty, skipping #{f}"
next
end
first_file = Dir[ f + '/*'][0]
if project.reference_for_path(first_file)
puts "Files from directory already added, skipping #{f}"
next
end
end
if project.reference_for_path(f)
next
end
libFile = project.new_file("#{f}")
puts "Adding %s to %s Copy Bundle Resources Phases" % [libFile, target.name]
target.resources_build_phase.add_file_reference(libFile, avoid_duplicates = true)
end if File.directory?(res_directory)
project.save
end
This piece of code, after every pod update
adds all the classes and headers from the keep/Classes
directory and all the resources from the keep/Resources
directory to the project Project.xcodeproj
. It is using the Xcodeproj
class that is used in Cocoapods internals.
This code has a little caveat. When you add a resource to a subdirectory in keep/Resources
(like a new version of a Code Data model) this code will skip it. If anyone knows how to better handle directory references in Xcode projects, please let me know.
One can ask why are we doing this automatically instead of just adding the files manually to the specific App project. Our skeleton project is updated frequently and to update the skeleton in our Apps, we just delete them and regenerate them from the skeleton and do pod update
. Nobody has to remember to add some App specific classes to it - everything is handled automatically.