At my first thought, this article had supposed to be named "The Modern Guide of Carthage with Xcode 12 for Beginners". However, while the process of learning Carthage and replace my own projects from using CocoaPods to Carthage. I found that using Carthage alone was not enough, or too complex for a one-week-learner like me.
The purpose of this article is to speed up your Xcode building and archiving time. In my own test, the speed could be over the original 10 times.
Since I am a beginner for Carthage, I may change this article a lot with updates.
A Framework is a prebuilt code package that you can use in your own code.
As programmers, we use frameworks a lot. For example, when you
import UIKit, you are using UIKit framework provided by Apple.
UIKit is a build-in framework, so you just need to import it. There are also many other frameworks provided by third-parties. You can even create your own frameworks. For third-party frameworks, it is your responsibility to let Xcode know how to using them.
You can manually drag and drop those frameworks to Xcode. Or you can use framework tools like CocoaPods or Carthage.
CocoaPods VS Carthage
CocoaPods is more widely used. It has a long history ever since Objective-c. It uses source code so it has the most compatibility. Since you have to compile the framework from source code every time, it takes more time when build and archive.
Unless CocoaPods, Carthage builds the frameworks while you download them. Then you can drag and drop those frameworks to Xcode as if there are prebuilt. Those frameworks won't need to recompile again as they are already binaries. Your own project building time is saved.
We could use CocoaPods or Carthage alone, or mixed, or neither. The more you use CocoaPods, the complex the source codes are, the more build time of your own project lasts. So we intent to use Carthage alone. However, Carthage is not as compatible as CocoaPods with Xcode. Sometime you may find no solution to solve the problem of Carthage. Then you can try CocoaPods.
Xcframework is the latest framework format that Xcode 12 supports and recommended.
Before xcframework, when we use a framework on macOS. The framework is easy to build. As for a Mac, only x86_64 architecture is used. If the framework is for iOS, things go complex. As if you could run an iOS app on both iOS simulators and iOS devices. For an iOS simulator running on a Mac, its architecture is x86_64, the same as the Mac. For an iOS device, the architecture is arm64. The framework you built should work in both x86_64 iOS simulators and arm64 iOS devices.
Framework tools use
lipo to merge and split frameworks of different architectures.
$ man lipo
lipo - create or operate on universal files
A framework that contains more than one architectures is called a fat framework. Xcode could use the framework for both iOS simulators and iOS devices.
Apple Silicon Macs
Things go left when M1 Macs released. As they are arm based Macs instead of Intel based Macs. Everything on them is arm64 architecture.
For a framework runs on Mac, it now needs to be built into both x86_64 and arm64.
lipo could do the trick.
For a framework runs on iOS, it now needs to be built into x86_64 and arm64 for iOS simulators and arm64 for iOS devices. You may think you can still use
lipo. No, you can't. As you could see, there are arm64 in both iOS simulators and iOS devices.
lipo could only specify a framework by its architecture, but it doesn't know if it is an iOS simulator or an iOS device.
lipo cannot combine those frameworks together as the arm64 architectures are duplicated.
Xcframework comes. Xcframework is a bundle that contains an Info.plist with the information that the frameworks it contains. For each individual framework, it could be a fat framework or not.
Below is a picture of two built xcframeworks of Realm. The left is the Realm office prebuilt framework. The right is the framework built by Carthage by my Intel based iMac.
As we could see, for the left, there is an extra iOS maccatalyst framework. And for all simulators, there are extra arm64 architectures. I think it is because that xcframework was built on a M1 based Mac.
I didn't find the way to build arm64 architecture frameworks for simulators on an Intel based Mac. This leads to a bug of Xcode 12 on iOS app with watchOS app as companion.
Carthage by default can build xcframeworks with all architectures in all platforms, except Mac Catalyst.
Xcode 12 Requests arm64 Framework for watchOS Simulator
It is unnecessary to request arm64 framework for watchOS simulator on an Intel based Mac. It is a tradeoff. As if you are in a team that uses both Intel based and Mac based Mac, this feature is unnecessary. You can get rid of it manually.
Go to watchOS extension target -> Building Settings -> Excluded Architectures -> Debug, add "arm64".
Carthage Working Steps
Cartfile is the place where you put the framework's name and version. All frameworks that in Cartfile is called
$ cat Cartfile github "realm/realm-cocoa"
When you call
carthage update, carthage resolves the Cartfile as a
Cartfile.resolved file. The resolved file may contain more frameworks than Cartfile as some frameworks request other frameworks.
$ cat Cartfile.resolved github "realm/realm-cocoa" "v10.7.2"
Checkout downloads source codes of frameworks.
The building process.
Install Frameworks to Xcode 12.4
To install frameworks to Xcode, basically we just need to drag and drop the frameworks to Xcode. However, depending the dropping locations, there are two methods of adding frameworks.
how to installing frameworks
- drag to frameworks
- drag to general
remove unused framework
- download binary instead of create xcframework
- download binary along with creation of xcframework
Xcode known issues
watchOS arm64 issue on simulator of Intel based Mac