Freeing the space used by Xcode with XcodeCleaner

With every release of Xcode it seems to eat more and more space. I was thrilled to find the XcodeCleaner project from Baye on Github.  This is a great project that allows you to tailor the space Xcode uses.  I’ve been able to free up an easy 12GB without any issues.

I highly recommend checking out the project on GitHub at XcodeCleaner. You can build the project from source or download from the macOS App Store for $0.99.
68747470733a2f2f7777772e6170706c652e636f6d2f6974756e65732f6c696e6b2f696d616765732f6c696e6b2d62616467652d61707073746f72652e706e67

screenshot

Fastlane: Solving the WatchKit CFBundleVersion matching problem

Fastlane is one of the tools that a developer shouldn’t live without. At this point it must have saved me hundreds of hours.  As great as fastlane is out of the box it has a few rough edges when you introduce a WatchKit app.

Recently I added a WatchKit app into one of my projects and started getting the below error:

error: The value of CFBundleVersion in your WatchKit app’s Info.plist (262) does not match the value in your companion app’s Info.plist (263). These values are required to match.

In a nutshell, Apple requires that your WatchKit app and it’s companion app share the same version. If your fastlane build includes increment_build_number these will never match by default.

Solving this problem is pretty easy, although alittle more involved then just changing your versioning system like in your core app. Hopefully the below will help people Googling for this error in the future.

Step 1: Update your Watch App’s Versioning Configurations

The first thing you will need to do is update the versioning configuration for your Watch App’s target.

  1. In Xcode click on your Watch App’s target
  2. Go to the Build Settings tab
  3. Scroll (or search) for the Versioning section
  4. Update the “Current Project Version” to match your core app target’s version. It is important you get this correct the first time.
  5. Switch the “Versioning System” to “Apple Generic”

watchapp-versioning.png

With these changes in place fastlane increment your Watch App’s Current Project Version every time increment_build_number is called. This will work just like it does in your core app target.

Step 2: Update your Watch App’s Extension Configuration

Just like step 1, you will need to update the versioning configuration for your Watch App’s extension target.

  1. In Xcode click on your Watch App’s Extension target
  2. Go to the Build Settings tab
  3. Scroll (or search) for the Versioning section
  4. Update the “Current Project Version” to match your core app target’s version. It is important you get this correct the first time.
  5. Switch the “Versioning System” to “Apple Generic”

watchext-versioning.png

This again let’s fastlane increment your Watch App’s Extension when increment_build_number is called.

Step 3: Keeping your CFBundleVersion in sync

If you run your fastlane build process now you will notice you still get an error that your CFBundleVersion information does not match. Whereas fastlane is updating the Current Project Version in both your Watch App and Watch App Extension it doesn’t update their CFBundleVersion value.

The best way I’ve found to do this is to use PlistBuddy and update the CFBundleVersion as part of the fastlane build process. Below is a small convenience function created to manage the process of updating the build numbers.

def setBuildNumberOnExtension(build_number)
raise if build_number.nil?
puts "Setting Extension to build number #{build_number}"
sh("/usr/libexec/PlistBuddy -c 'Set CFBundleVersion #{build_number}' ../myWatchApp/Info.plist")
sh("/usr/libexec/PlistBuddy -c 'Set CFBundleVersion #{build_number}' ../myWatchAppExtension/Info.plist")
end

For my workflow I’ve incorporated the setBuildNumberOnExtension helper function into my build method that is called as part of my deployment, testing, or CI process.

desc "Create ipa"
lane :build do
increment_build_number
setBuildNumberOnExtension(
get_build_number
)
gym(scheme: "TestApp", workspace: "TestApp.xcworkspace", output_directory: "../../../Builds/TestApp", clean:true, silent: true, export_method: "enterprise")
end

The same approach should work for all extensions. Even if you only have a “Today Extension” I’d recommend keeping the version numbers in sync with your core app. This will make life easier when you are debugging.

Check of the fastlane examples for more ideas on how to create extensions to improve your workflow.

Plugin to help fight the DerivedData Junk Drawer

It just takes creating a few example projects and suddenly you have a ton of simulator folders to deal with. Over time this becomes a junk drawer of simulator references to experiments and samples.

Toshihiro Morimoto (dealforest) has released the Cichlid Xcode plugin to help combat this.  It is super simple to use and simply deletes the DerivedData associated with your project when you run Product-> Clean.  I’ve been using it for the last week and it simply works.

Give it a try if you are looking for an easy way to clean the ~/Library/Developer/Xcode/DerivedData folders associated with your project.

Learn more on Github : https://github.com/dealforest/Cichlid

banner