Managing third party dependencies in iOS App

Managing dependencies in every programming project is always some kind of a ‘hell’. I have never known any developer who would have told me only pros of their dependency manager even about NPM which is in use for JavaScript based projects.

As iOS Software Engineers for a long time we didn’t have any official dependency manager which wouldn’t break on every tool update. But things change and I would like to share a few thougts about what is the current state.

Fun fact: Some people say that iOS developers are even faster than JS developers in creating new frameworks/tools and integrating them into the project.

How to add external library to an iOS project?

There are a few ways to add external dependency to a project:

  • Add dependency as source code — if a framework/library is open and available on Github we could easily check out the project and move source files to ours. This way we could simply modify the sources as we want.
  • Add dependency as sub-project — this way is similar to the above one but we keep things in separate workspaces so we avoid mess in source files in our base project.
  • (legacy shortly) Add dependency as .framework — self-contained, reusable chunks of code and resources you can import into many apps. You can even share them across iOS, tvOS, watchOS and macOS apps. When combined with Swift’s access control, frameworks help define strong, testable interfaces between code modules
  • Add dependency as .xcframework — it is the same as .framework but contains bundled resources for few platforms in once eg. for iOS/iPadOS and macOS, iPhone simulators etc. Using xcframework is a preferred way today.
  • Use dependency manager — we could use one of the most popular dependency managers which is: CocaPods, Carthage or oficial one from Apple — Swift Package Manager

Dependency Managers in details

CocoaPods

Launched in 2011, CocoaPods was the first dependency manager for the iOS and macOS environment. It is written in Ruby lang so it has to be distributed as a Gem. If you want to use CocoaPods you’ll need a compatible version of the Ruby lang.

CocoaPods has a centralized approach. This means that CocoaPods has a github repository that maps the name of a Pod with the location of where to download that Pod. The advantage of having a centralized approach is that you have a place where you can store the metadata of all the available libraries on CocoaPods. In turn, this provides a simple way to search for libraries. The drawback is that if something happens to that repository you won’t be able to resolve your dependencies.

Carthage

Carthage is a open sourced dependency manager written in Swift. It fetches or builds frameworks locally as a dynamic one. Carthage uses decentralized approach. The biggest drawback is that after every Xcode toolchain update open source community has to do some crucial changes in carthage to make it work with newest Xcode. Sometime it takes longer than usual so having big project and depending on Carthage may cause huge problems for development.

Swift Package Manager (SPM)

The Swift Package Manager is an official Apple tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Packages are written in Swift but could also be added by Xcode manually using graphic interface.

SPM by default adds packages as static libraries so using it could make iOS app to start quicker.

Not every dependency could be added by SPM yet but the best approach is to merge SPM with manually added frameworks as described above.

Use cases

The most common use case for dependency managers is to add external dependency. But what about splitting project into modules using this approach?

If we have a common service layer which could be used by TV platform (tvOS) and iOS platform (iPhones, iPads etc) we could eaisly extract these API/service layer into Swift package / framework and distribute across our projects. What advantages does it give us?

  • Team members can allocate one or two people to integrate new services or APIs, and their work will not affect other team members
  • this kind of dependency could be versioning and have changelog so everything is clean and readable for all team members regardless of their seniority .

As iOS Mobile team in DAZN we use this approach to distribute video player. We treat player as separate module which could be versioned and simply developed by other teams even complectly new team in te future.

Summary

As you can see dependency management is at the good state in the iOS world. Future will show what will be the best approach, but personally I keep fingers crossed for the SPM. From year to year it’s getting better but there is still a lot of work to do.

You could ask what would be the best choice for my new project? I would say that SPM could be an otpion but you should be open to other solutions too. Practise shows that currently we could not have 100% dependencies added by SPM. In our mobile team we have manually added frameworks (XCFrameworks), SPM and few dependencies added by Carthage.

This kind of migration is a long time process especially if a project is developed for a long time already.

Check this up if you want to know more:

https://www.swiftbysundell.com/articles/managing-dependencies-using-the-swift-package-manager/

https://blog.embrace.io/should-you-use-cocoapods-or-carthage/