Dependency Management in iOS
What is Dependency Manager?
A package/dependency manager can be said as a tool that automates the process of installing, upgrading, configuring, removing software in our application.
Let’s assume we need to handle network requests inside our app, but we don’t want to waste our time in creating something that already exists. We just want to use an existing framework that is robust, reliable, well crafted, and well-tested.
These frameworks are the dependencies on which our app relies.
Dependency/Package manager helps to manage the dependencies in our application. Eg. Alamofire is a framework/dependency we add for network requests.
Dependencies can be linked to the iOS Project statically or dynamically.
In Static linking, all dependencies are copied to the project at compile time where as Dynamic linking allows only references to the dependencies to be stored in our project by loading them at run time.
System frameworks like UIKit are linked dynamically so that there is no need to update our application every time whenever it is modified. Third party frameworks like AFNetworking, ObjectMapper can be linked statically or dynamically.
Manual Dependency Management
While adding a dependency to the project manually, the below steps are followed:
- Download a project / add it as a git submodule
$ git submodule add https://github.com/Alamofire/Alamofire.git
2. Add a project to your existing project
Open the new Alamofire
folder, and drag the Alamofire.xcodeproj
into the Project Navigator of your application's Xcode project.
Select the Alamofire.xcodeproj
in the Project Navigator and verify the deployment target matches that of your application target.
3. Add Framework to project settings
In the tab bar at the top of that window, open the “General” panel. Click on the +
button under the "Embedded Binaries" section. Select the framework Alamofire.framework
based on the requirement as it includes both iOS and macOS frameworks.
Dependency Management using Dependency Managers:
Below are the most commonly used Dependency Managers for iOS:
- Cocoapods
- Carthage
- Swift Package Manager
Package Manager should have the following abilities:
- Centralised hosting of packages and source code with public server with access to developers or contributors
- Download the source code at the run time, so that we don’t need to include it in the repository.
- Link the source code to our working repository by including source files.
- Allow packages to be versioned
Cocoapods
- Centralized dependency manager
- Can be used for Swift and Objective-C cocoa projects
- Open-source
- Built with Ruby
- Cocoa pods are based on main central Repo called Specs.git
- Specs.git hosts all the framework specification
- To make package manager available for other developers, package developers have to push the code to this repo using pod command line
- It has a public search feature on its website so that developers can search for different frameworks in one place
- Supports all Apple platforms- iOS, macOS, tvOS, watchOS
Installation $ sudo gem install cocoapods
To integrate dependency using Cocoa pods, we need to create Podfile in Project root folder. pod init command which will create empty Podfile.
Download dependency using pod install which will generate Podfile.lock file.
A folder with name “Pods” also gets created.
platform :ios, '11.0'
use_frameworks!
target 'Project Name' do# Pods for "Project Name"
pod 'Alamofire', '~> 5.2'end
COCOAPODS AND XCODE COLLABORATION
- Cocoapods and XCode work together to integrate the dependency in the iOS project.
- pod install command creates .xcworkspace file on top of .xcodeproj file to open project
- Creates Podfile.lock file in the Project root folder
- Pods directory which has the source code of all the Pod dependencies added in Podfile.
- Makes changes in the XCode Project settings.
CocoaPods — Pros and Cons
Advantages
- Easy to set up and use.
- Automatically does all the XCode project setup. No manual set up required to add the dependency in the iOS Project.
- Lots of contributors are available so the dynamic libraries are available for integration. Easily searchable libraries using a public search on Cocoapods website.
Limitations
- It’s built on Ruby and we have to manage Ruby dependencies e.g Bundler, Gems etc etc
- CocoaPods updating Xcode Projects and Files is like magic without understanding what’s changed.
- Centralized
Carthage
- Carthage is a decentralized dependency manager for Swift and Objective-C Cocoa projects
- Decentralized: There are no central specs.git repository for Carthage.
This reduces the maintenance work and possibilities of central points of failure.
- But, we need to check for each dependency repo if it is outdated or not instead of the centralized one in Cocoa-pods.
- Supports all Apple platforms: iOS, MacOS, tvOS. watchOS
- Carthage command-line tool works on only Mac.
- Open-source
- Built with Swift
CARTHAGE AND XCODE COLLABORATION
- Doesn’t change XCode and Project files.
- Provides control over XCode what files need to be added.
- Carthage being simple just add and build the dependencies and leave it to the developer to add the binaries to the project.
Step 1:
Carthage Installation Methods:
There are multiple options for installing Carthage:
- Installer:
Download Carthage package installer
https://github.com/Carthage/Carthage/releases
Download the latest release of Carthage:
https://github.com/Carthage/Carthage/releases
Select the most recent build, then under Downloads select Carthage.pkg.
Double-click Carthage.pkg to run the installer. Click Continue, select a location to install the package, click Continue again, and finally click Install.
Possible Difficulties:
if Carthage.pkg not installed, you may see a message stating “Carthage.pkg can’t be opened because it is from an unidentified developer.”
Open the finder Right-click on Carthage.pkg → openwith → Installer
The installation process start select a location to install, Click to continue.
Check the version:
carthage version
- Homebrew
Install Homebrew with command:
/usr/bin/ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
Install carthage:
brew install carthage
if you previously installed the binary version of Carthage, you should delete /Library/Frameworks/CarthageKit.framework
- Macports:
Under downloads, select the latest package.
install MacPorts 2.6.4 for macOS
Run commands:
sudo port selfupdate
sudo port install carthage
Step 2:
Navigate to the root directory of your project in Terminal
cd /Users/sukanksha.paralikar/Documents/POC/DemoCarthageDependencyManager
Step 3:
Create an empty Cartfile with the touch command:
touch Cartfile
Open Cartfile using command:
Open -a Xcode Cartfile
Add the Dependency you want to add to the project
github “Alamofire/Alamofire”
Step 4:
Type the command to get the updated dependencies.
carthage update — platform iOS
Step 5:
Carthage creates Cartfile.resolved file, so that when you checkout the code from the server, you should add the same version of the same dependency in the project.
Open Directory by using the command:
open Carthage
Carthage Directory has two folders -
- Build -> iOS
- Checkouts
Build has iOS folder inside it which has the frameworks added in the Cartfile
The checkouts folder has the source code for the dependency added in the project.
Step 6:
On your Project targets “General” settings tab, in the “Linked Frameworks and Libraries” section, drag and drop each framework you want to use from the Carthage/Build folder on disk.
General -> Linked Frameworks and Libraries -> Add folder -> project_directory_path -> Carthage -> Build -> iOS -> Alamofire.framework
Step 7:
On your application targets’ “Build Phases” settings tab, click the “+” icon and choose “New Run Script Phase”. Create a Run Script in which you specify your shell (ex: /bin/sh), add the following contents to the script area below the shell:
Application Target -> Build Phases -> + Icon -> New Run Script phase -> Run Script ->Shell
Type below in the Shell text field:
/usr/local/bin/carthage copy-frameworks
Check -> Show Environment variables in Build log
Check -> Run script only when installing
Step 8:
Under Input files:
$(SRCROOT)/Carthage/Build/iOS/“Result.framework”
Step 9:
Add the paths to the copied frameworks to the “Output Files”
- Navigate to Build Phases tab
- Click on the + button and select New Copy Files Phase
- Expand the Copy Files section.
- For Destination dropdown, select Frameworks.
- Drop the Alamofire.framework file in the drop target (where it says “Add Files here”). When prompted, check the Destination: Copy items if needed checkbox.
- Also make sure the checkbox Code Sign On Copy is checked. Leave the Copy only when installing box unchecked.
Carthage — Advantages and Disadvantages:
Advantages
- Provides control to the developer as doesn’t touch XCode project
- Decentralised
Limitations
- Not many contributors as Carthage has small community working with it.
- Slow and unstable
- Requires lots of manual steps to integrate dependency using Carthage.
Swift Package Manager
The Swift Package Manager has been around since Swift 3.0. With Xcode 11, Apple has added the Swift Package Manager support for managing the distribution of Swift code in iOS.
A Swift package mainly includes two parts: The source code which is the heart of the package, and a manifest file, the Package.swift, which is the place where the package configuration takes place.
To check if you have Swift Package Manager Installed :
swift build –version
Create a package using SPM:
Open Terminal and create a directory named Demo, then enter in SPMDemo
mkdir SPMDemo
cd SPMDemo
SPM — Advantages and Disadvantages:
Advantages
- Official package management tool for Swift
- Managed by Apple
- Useful in server-side swift projects
Limitations
- New tool as compared to Cocoapods and Carthage
- Supports only macOS and Linux
Summary
In this way, we have seen different ways of adding dependency to your iOS project and their pros and cons. Although we have cocoapods and Carthage usage is more as compared to Swift Package Manager, it could be a better option as an official tool by Apple in future.
Happy reading :-)