Sitemap
Natasha Radika

Natasha Radika

Software Engineer

CocoaPods in Xcode 27

What I learned from trying out CocoaPods in an iOS app project built using Xcode 27.2.

4 min readOct 31, 2026

--

I’m creating an iOS app project using Xcode 27.2 on macOS Golden Gate 27.0. This article shares my experience experimenting with CocoaPods in an iOS project, covering both Xcode 27 compatibility issues and general learnings about how CocoaPods works.

Press enter or click to view image in full size
A random crumpled plastic as a thumbnail image, it has pretty blue and purple colors.
shinny old things

#1 (Xcode 27): CocoaPods incompatibility with .xcproj JSON format

After installation, the first step to initialize CocoaPods in your project is to run pod init. In previous Xcode versions, as long as you have a project.pbxproj file in your project, this command runs successfully. But in Xcode 27, Apple updated the default project configuration to.xcproj, which uses a JSON file. This may cause this error when you run pod init:

[!] The plist file at path `CocoapodsExercise/CocoapodsExercise.xcodeproj/project.pbxproj` doesn't exist.

This is because CocoaPods uses a Ruby library called xcodeproj to parse and modify Xcode projects. My installed version uses xcodeproj 1.28.1 (latest version at the time of writing) which expect project.pbxproj format and does not understand .xcproj format.

Fortunately, Xcode 27 supports both .pbxproj and .xcproj format. To convert the default .xcproj to.pbxproj, head to Project Navigator> select project > File Inspector> Project document. Change the Project Format from JSON to Property List.

Select format in Project Document

#2 (Xcode 27): CocoaPods version string incompatibility with object version 110

Once you fix the issue in #1, you’ll face a new warning message (the Podfile will still be created even though we don’t fix this):

[!] [Xcodeproj] Xcode project version (110) is higher than the latest supported by xcodeproj (100).

I think there are many incompatibility issues because CocoaPods trunk will be in read-only mode in December this year. That’s why there are no patches available for newer versions of Xcode 😔.

Get Natasha Radika’s stories in your inbox

Join Medium for free to get updates from this writer.

Anyway, to fix that, simply go to the project.pbxproj > Show Package Contents > change objectVersion to 100.

archiveVersion = 1;
classes = {
};
objectVersion = 100;

#3 (General): CocoaPods for client app

In #2, we can create a new Podfile. Now, let’s look at how CocoaPods works in the client app (the app that consumes the dependencies).

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'CocoapodsExercise' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!

pod 'SwiftyJSON', '~> 4.0'
pod 'Alamofire', '~> 5.0.0-rc.2'

# Pods for CocoapodsExercise

target 'CocoapodsExerciseTests' do
inherit! :search_paths
# Pods for testing
end

target 'CocoapodsExerciseUITests' do
# Pods for testing
end

end

I’ll also add SwiftyJSON and Alamofire there, then run pod install to install those dependencies. The command ran without any issues and generated .xcworkspace , Podfile.lock and Pods/ folder.

folder structure now

.xcworkspace is an Xcode document that groups projects and other documents so we can work on them together. It is a higher organizational layer than .xcodeproj and contains a directory bundle. One of the most important files iscontents.xcworkspacedata, it is an XML file describing workspace structure and references to the projects it contains.

<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:CocoapodsExercise.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

CocoaPods will automatically generate this when we run pod install because we need to generate a separate Xcode project for Pods, which contain build targets for the dependencies.

Podfile.lock is a file to track the version of each Pod that was installed; this file will be generated after the first run of pod install and updated in pod update. For example, our Podfile didn’t specify any version; this means that we will install that dependency using the latest version.

target 'MyApp' do
pod 'RestKit'
end

Suppose that the current latest version is0.10.3, when we runpod install, it will generate Podfile.lock with that version, so next time another developer runs on their machine, they can build the app with that version instead of the current latest.

Then, why do we need Podfile.lock at all? Why don’t we define the exact version in Podfile?

Consider this scenario in a multi-modular app. We have Client App, SDK A, and SDK B with this dependency graph:

Press enter or click to view image in full size
client has dependency with A and B, SDK A has dependency with SDK B

For example, SDK A Podspec

Pod::Spec.new do |s|
s.name = 'SDK-A'
s.dependency 'SDK-B', '~> 2.0'
end

Client Podspec

target 'ClientApp' do
pod 'SDK-A'
pod 'SDK-B', '2.0'
end

Suppose that we need to bump SDK B version to 2.5.0 in the Client App, we run, pod update and CocoaPods resolves SDK B again. If 2.5.0 satisfies the constraints declared by both SDK A and the Client App, CocoaPods can install it. This is the resulting lockfile in the Client App:

PODS:
- SDK-A (1.0.0):
- SDK-B (~> 2.0)
- SDK-B (2.5.0)

Notice that we don’t have to bump SDK B in SDK A as well! That’s one benefit of the lockfile design; it gives us this kind of flexibility.

That’s all about CocoaPods for today! Hopefully we can apply this knowledge and underlying principle when dealing with other dependency managers such as SPM in the future. Keep in touch :)

--

--