---
title: Framework with dependencies
slug: framework-with-dependencies
docTags: 
createdAt: 2021-03-12T18:33:51.000Z
---

Let's say we have two frameworks **CalcEngine** and **Core**, and we need to include **CalcEngine** framework inside **Core** as dependency. There are multiple methods and some of them are described below.

# Manual integration

There are multiple ways to add **CalcEngine** framework to a **Core** framework manually.

## As source code

If we have code of both frameworks we can include the dependency framework directly to the code of the main framework. It can be included as gitsubmodule as well.

## As xcframework

We can also add **CalcEngine** to the source code of **Core** by dragging **CalcEngine.xcframework** to the **Frameworks and Libraries** section in **Core** target settings.&#x20;

## As hidden dependency

Procedure for adding **CalcEngine** as hidden dependency of **Core** is same as adding is as xcframework. The only difference is that we cannot simply `import CalcEngine`. Instead, we need to use `@implementationOnly import` to hide **CalcEngine** from `swiftinterface` file and Objective-C headers.

### Limitation

The Limitation of this approach is that we cannot use any types, classes or conform to protocols from **CalcEngine** in public types/methods/classes/protocols of **Core** framework. This is enforced by the compiler. Also, `@testable import Core` used in unit tests can behave unexpectedly.

:::hint{type="danger"}
@implementationOnly import is not officially supported by Apple!
:::

More details in [Framework with hidden dependencies](docId\:KSakbfMWRnfWqQf1Jr6gO)article.

# CocoaPods

## As dependency

We can add **CalcEngine** to **Core.podspec** file and define which versions we work with.

```ruby
Pod::Spec.new do |s|
  s.name             = 'Core'
  s.version          = '1.0.0'
  
  s.summary          = 'Core framework used inside MyCompany'
  s.description      = 'Core framework used inside MyCompany'

  s.homepage         = 'https://mycompany.com'
  s.license          = { :type => 'MIT', :file => 'LICENCE' }
  s.author           = { 'MyCompany' => 'example@mycompany.com' }
  s.source           = { :http => 'https://mycompany/frameworks/core/#{s.version}/Core.zip'}
  
  s.ios.deployment_target = '10.0'
  s.ios.vendored_frameworks = 'Core.xcframework'
  
  s.frameworks = 'UIKit'
  s.dependency 'CalcEngine', '>= 0.1 < 0.3'

end

```

This states that **Core** depends on **CalcEngine** and can use any version between 0.1 and 0.3.

There's also possibility to use "optimistic version indicator" `~>`, it's also recommended by [CocoaPods](https://cocoapods.org).

### Optimistic version indicator

It uses the last semantic version defined and allows updating of it but doesn't allow higher semantic version.

- `~> major.minor.patch` → allow updating of patch version but don't allow minor version update
- `~> major.minor` → allow patch and minor version update

**Examples**

- `~> 1.0.1` is equivalent to `>= 1.0.1` combined with `< 1.1`
- `~> 1.0` will match `1.0`, `1.0.1`, `1.1`, but will not `2.0`

Developers can provide a different version of the framework, but it must be compatible with the version defined in **Core.podspec**, otherwise it will throw an error.

If the developer specifies `pod CalcEngine, '1.0'` in **Podfile** and in **Core.podspec** we have `s.dependency CalcEngine, '~> 0.1'`, the developer will receive the following error.

:::BlockQuote
Specs satisfying the CalcEngine (= 1.0), CalcEngine (\~> 0.1) dependency were found, but they required a higher minimum deployment target.
:::

## As subspec

Another solution that is that we can create a "parent" framework that will have subspec frameworks defined.

If we have a framework that offers multiple frameworks that all together are one big solution but at the same time can be used separately we can define one "parent" framework that lists all others as subspec.

```ruby
Pod::Spec.new do |s|
 s.name = 'MyCompany'

 s.subspec 'Core' do |core|
  core.source_files = 'Core.xcframework'
  core.dependency 'MyCompany/CalcEngine'
 end

 s.subspec 'CalcEngine' do |ce|
  ce.source_files = 'CalcEngine.xcframework'
 end
end

```

More details in [Pod with child pods](docId\:pKe-IgfRywZ62tlbxuy1f)article.&#x20;

# References

- [https://guides.cocoapods.org/making/specs-and-specs-repo.html#examples-of-specifications](https://guides.cocoapods.org/making/specs-and-specs-repo.html#examples-of-specifications)
- [https://guides.cocoapods.org/syntax/podspec.html#subspec](https://guides.cocoapods.org/syntax/podspec.html#subspec)
- [https://forums.swift.org/t/challenges-creating-an-xcframework-for-native-libraries/41600](https://forums.swift.org/t/challenges-creating-an-xcframework-for-native-libraries/41600)
- [https://forums.swift.org/t/update-on-implementation-only-imports/26996/17](https://forums.swift.org/t/update-on-implementation-only-imports/26996/17)
- [https://forums.swift.org/t/exported-and-fixing-import-visibility/9415](https://forums.swift.org/t/exported-and-fixing-import-visibility/9415)
- [https://medium.com/@anuragajwani/modular-ios-guide-60810f5a7f97](https://medium.com/@anuragajwani/modular-ios-guide-60810f5a7f97)

