How to use private cocoapods dependencies in public pods

10 Jan 2023

How to use private cocoapods dependencies in public pods

This article is the result of some findings I have come across or learned while freelancing at Tiendeo. It's a bit of an edge case, and I hope It can be useful to you

As an iOS developer, you will encounter Cocoapods very often. Most likely, you will be using It to import your dependencies into your app or target.

However, when exporting your frameworks for others to use, you might run into some edge cases. One such case will happen if you ever want to publish a framework that includes a private framework. This could be common if your company offers an SDK, while using some internal components. The resulting dependency diagram could be the following:

Diagrarm showing cocoapods dependencies of an Xcode project

The problem

When attempting to publish My Public Pod, by using pod trunk push you will encounter the following error:


- ERROR | iOS unknown: Encountered an unknown error (Unable to find a specification for `[Private Framework] (= x.y.z)` depended upon by `[My Public Framework]`


[!] The spec did not pass validation, due to 1 error

The solution (?)

The issue lies on the private framework not being found in the public cocoapods repo, so the standard mechanism for declaring dependencies in cocoapods is not the way to go. Instead, we'll have to use the vendored_frameworks declaration in our Podspec, and upload the private dependency as one of our own. At this point, your podspec will most likely look like this:

Pod::Spec.new do |spec|
  spec.name         = 'MyPublicFramework'
  spec.version      = '1.0'
  spec.license      = 'MIT'
  spec.summary      = 'A description of my pod'
  spec.homepage     = 'https://darioroa.com'
  spec.author       = 'Dario Roa'
  spec.source       = { :git => 'git://github.com/darioroa/MyPublicFramework.git', :tag => 'v1.0' }

  # Vendored Frameworks
  s.vendored_frameworks = 'MyPublicFramework.framework'

  # Dependency declaration
  spec.dependency 'MyPrivateFramework'
end

Our goal is to include the private framework alongside our public one, by declaring It as a vendored framework:

Pod::Spec.new do |spec|
  spec.name         = 'MyPublicFramework'
  spec.version      = '1.0'
  spec.license      = 'MIT'
  spec.summary      = 'A description of my pod'
  spec.homepage     = 'https://darioroa.com'
  spec.author       = 'Dario Roa'
  spec.source       = { :git => 'git://github.com/darioroa/MyPublicFramework.git', :tag => 'v1.0' }
  
  # Vendored Frameworks
  s.vendored_frameworks = 'MyPublicFramework.framework', 'Frameworks/MyPrivateFramework.framework' 

  # Private framework not listed as a dependency anymore
end

Note that this is more of a workaround, and will also require including any dependencies of our private dependency in this format. For instance, if MyPrivateFramework depends on SuperSecretFramework:

# Vendored Frameworks
s.vendored_frameworks = 'MyPublicFramework.framework', 'Frameworks/MyPrivateFramework.framework', 'Frameworks/SuperSecretFramework.framework' 

You may also notice we have declared these frameworks inside a Frameworks folder. This is the way we will include them into our upload.

When calling pod trunk push, you will need to also include this Frameworks folder containing the private framework and all of its dependencies.

With this setup, you will hopefully be able to publish your framework in the public Cocoapods repo, but including non-public components.

Constraints

This guide is more of a workaround, and as such will likely not always work. If it does, you should also keep in mind its restrictions:

  • The private framework and its dependencies must be compiled to a .framework file. So you have to also manage those dependencies manually and make sure you're including the right version for each upload.
  • You need to include all dependencies of the private framework. This could result in this method not being viable anymore, depending on your setup and needs.

I hope you found this useful. Have fun with Cocoapods 😉

Tags: