CocoaPods 0.38 - watchOS and target de-duplication

TL;DR: CocoaPods 0.38 has been released, with watchOS 2 support, target de-duplication, and Stats for everyone.

CocoaPods 0.38 has been released. This is our first update since WWDC and it brings support for Apple's latest releases, including Xcode 7 and watchOS. It also includes lots of improvements that make building Pods easier. Furthermore, it rolls out Stats for everyone.

watchOS

The update allows you to use Pods with watchOS. As a Pod Author, you have to specify the deployment target for watchOS in the Podspec, as seen below:

Pod::Spec.new do |s|
  # …
  s.watchos.deployment_target = '2.0'
end

What this means in practice, is that not all Pods are automatically available by default. Any Pod that can support watchOS needs to explicitly add support by adding s.watchos.deployment_target. It is an entirely new platform.

Target Deduplication

CocoaPods now de-duplicates Pod targets, which means that it recognises when a dependency is used multiple times across different user targets but only needs to be built once. But sometimes this is not possible and they still need to be generated in different variants and thus build multiple times. The targets in Pods.xcodeproj need to be duplicated when one of the following conditions applies:

  • They are used on different platforms.
  • They are used with differents sets of subspecs.
  • They have any dependency which needs to be duplicated.

This fixes several issues with Archiving apps with extensions, but also reduces build times significantly.

Removal of the Enviroment Header

After updating and running pod install on your integration, you will see that some header files in the Pods directory won't be generated anymore matching the pattern Pods-*-environment.h. This was the environment header, which contained precompiler macro definitions with the version components of each dependency used in the integrated target. It was visible not only for the user target, but also for all its dependencies. It could be used to make additional features available if a given pod is present. But this was also the cause of some issues. One of them was that it wouldn't be possible to de-duplicate frameworks. If you relied on that, you can still use the Clang file checking macro __has_include to determine (by the presence of a header) whether a specific dependency is available or not:

#if __has_include(<QueryKit/QueryKit.h>)
  #import <QueryKit/QueryKit.h>
#endif

To make optional behavior in your Pod available, you should use subspecs, exclude the subspec from the default_subspecs and declare there an explicit dependency, which is versioned and will affect the dependency resolution only when the user explicitly includes the subspec.

Breaking Change to the Hooks-API

The Podfile allows you to define pre_install and post_install hooks. Before this update, we maintained a proxy layer, so that we could alter the installation / integration process and the model and just change how the Hooks API representations access those artifacts. This worked for a while, but finally we became aware that we reached a point where both came completely out-of-sync. Because of that, we relinquished that approach and made the underlying installer directly available, which was exposed before anyway and allowed more advanced possibilities for this more advanced feature.

If you relied on that feature, this table may help you with the mapping and give you some help how to migrate:

InstallerRepresentation Installer
sandbox_root sandbox.root
project pods_project
pods ~> pod_targets
libraries ~> aggregate_targets
specs_by_lib use #find or #select on pod_targets
pods_by_lib use #find or #select on aggregate_targets
sandbox sandbox
config config
installer not needed

See also the gem API documentation of the Installer.

If you need to keep compatibility to the older versions of CocoaPods, then you can simply check the gem version in the Podfile as it is just Ruby code after all.

post_install do |installer_or_rep|
  # @note: Remove after CocoaPods 0.38+ is completely rolled out
  # and rename block argument to `installer`.
  installer = installer_or_rep.respond_to?(:installer) ? installer_or_rep.installer : installer_or_rep

  # You can use the installer from now on.
end

Split of xcconfig

One of the more advanced attribute in Podspecs is - or better was - the attribute xcconfig.

This allow you to specify build settings for your Pod. Previously those were made available to libraries and the integrated target.

We broke this with the support for frameworks. This wasn't an issue for most Pods because the build setting is mostly used to configure build settings which are relevant only to the generated Pod target itself. When we mentioned that there were still some Pods which weren't working anymore as expected due to that change, we decided to split the attribute from now on. This way Pods also can't accidentally overwrite or conflict with build settings of the user target.

The former attribute xcconfig is deprecated and will cause a linter error when pushing new versions to trunk. The new attributes are available as pod_target_xcconfig and user_target_xcconfig, which makes their effects more clear. The latter attribute (user_target_xcconfig) should be used with great care, because well designed Pods should be self-contained and make as few assumptions about their environment as possible. Furthermore, this attribute can cause conflicts when different values are specified by two Pods for a build setting which doesn't allow multiple values and so cannot be merged.

Deterministic UUIDs by Xcodeproj

This update also includes the latest version of Xcodeproj, which encapsulates the API to Xcode projects. Beside support for new build settings, it now supports the generation of deterministic UUIDs for every object in the project file. That means in practice mostly, that you have smaller diffs for the Pods.xcodeproj after running pod install or pod update, which reduce unnecessary merge conflicts. This behavior can be disabled via the new COCOAPODS_DISABLE_DETERMINISTIC_UUIDS environment variable.

Resolver takes the Deployment Target into account

The deployment target of a podspec is now taken into account in the dependency resolution process. This will ensure that CocoaPods will always be able to resolve your Podfile, even if newer versions of pods are released that have higher minimum deployment targets. It makes the behavior of CocoaPods overall less surprising.

Thanks to Contributors of Bug Fixes

Along with these enhancements, 0.38 features dozens of bug fixes. Special thanks to all the new contributors we had for this release, especially for their help in squashing bugs.

Updating

To install the last release of CocoaPods you can run:

$ [sudo] gem install cocoapods

Until version 1.0 we strongly encourage you to keep CocoaPods up-to-date.

For all the details, don’t miss the Changelog!