Adventures in iOS Development
Unit Testing and Clean Code Exploration Toolbox Archive About Feed

CocoaPods tools, tips & tricks

In the spirit of Ash Furrow’s Teaching & Learning, here’s a compilation of CocoaPods pointers I’ve picked up after maintaining private pods daily.

Using private spec repo

It’s something to consider, even if you don’t maintain private pods, in the following situations:

  • using bleeding edge version of the library, that isn’t deemed stable yet (not tagged, no podspec for this version yet),
  • there’s a bug fix that you just need, but fix isn’t in version referenced in a podspec and maintainers don’t want to update patch version,
  • having fork with functionality you specifically need/maintainer not appreciating the pull request.

And the usual use cases for this:

  • maintaining private library (you can get by using :git, however…),
  • private library having dependency on another private library.

When pod version is referenced by :git or :head:, each time pod update runs it pre-downloads dependencies. Doing:

pod 'PEPhotoCropEditor', :git => 'https://github.com/mr-v/PEPhotoCropEditor'

results in running:

git clone https://github.com/mr-v/PEPhotoCropEditor --single-branch --depth 1

This command, depending on your network connection, can take from ~10 seconds to a minute on a bad Wi-Fi. Repo is stable and doesn’t really change, so why should we pull all this stuff each time? Using private specs repo solves this. There’s a nice official guide on how to setup and use such repo. After you’re done with setup, add new spec repo as source to a Podfile, e.g.:

source 'https://github.com/artsy/Specs.git'

To use custom version of the library:

  • configure podspec to point to specific commit, here commit/tag/branch can be used without worrying about triggering unnecessary downloads,
  • push podspec to private repo (pod repo push reponame).

Now private dependency can be specified like public one, without referencing git repository directly:

pod 'PFXAmazingLibraryDoingStuff', '~> 0.0.1'

pod update updates only what is really needed.

Linting

When linting the private spec with dependency on another private lib, be sure to specify private spec repo in --sources switch.

pod spec lint --sources='https://github.com/suchprivatespecrepo/Specs.git,https://github.com/CocoaPods/Specs'

–allow-warnings

When pushing a pod with pod repo push reponame, --allow-warnings can be a lifesaver when you just don’t want to deal with writing summary for internal library or podspec isn’t pointing to a tag.

Updating podspec versions

Instead of updating podspec manually use a npm package called podspec-bump. To see how podspec file would look after updating patch version, just run the command without any parameters. My preffered way of working is to run podspec-bump -w (bumps patch version, writes change to file) and then check changes with quick git diff. -i switch for bumping major and minor versions is available. There’s also --dump-version, which can be put to work like this:

podspec-bump -w # update version
git commit -am "bump `podspec-bump --dump-version`" 
git tag "`podspec-bump --dump-version`"
git push --tags
pod trunk push 

Hey we don’t support those languages, do we?

If you are using libraries that have lots of localizations and support languages you don’t, you may encounter a problem with App Store displaying that app supports those languages as well. To mitigate it use CocoaPods cocoapods-prune-localizations plugin, which allows to specify supported language codes in a Podfile:

plugin 'cocoapods-prune-localizations', {:localizations => ["en"]}

On each install/update those unwanted localizations will be pruned. Aside from fixing info on the App Store, it has benefit of removing unused resources from your app.

Defining macro in a third party dependency

Macros can be great, macros can be bad. In the end it boils down to how you use them. In my case I needed to add support for ARAnalytics to AFNetworkActivityLogger. Figured out a way to do it in a quick and dirty fashion (switching NSLog calls in AFNetworkActivityLogger to ARLog). Following Stack Overflow advice it can be achieved by adding post_install hook to a Podfile:

post_install do |installer_representation|
  installer_representation.project.targets.each do |target|
      target.build_configurations.each do |config|
      if target.name == 'Pods-AFNetworkActivityLogger'
      puts "Setting preprocessor macro for #{target.name}"
        puts "#{config} configuration..."
        puts "before: #{config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].inspect}"
        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] ||= ['$(inherited)']
        config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] << 'NSLog=ARLog'
        puts "after: #{config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'].inspect}"
        puts '---'
	   end
      end
    end
end