Thumbnail image

How to Update Current Cocoapod Lib to Support SwiftPM

Table of Contents

Abstract

Today we will discuss how to update the cocoapod library to support SwiftPM. Last week, I updated my TTBaseUIkit library to support Swift Package Manager. So I want to share some useful experience with you.

What is Swift Package Manager?

First, if you don’t know about Swift Package Manager. I thought you read swiftpm-post to understand about this package.

The Swift Package Manager is a tool for managing the distribution of Swift code. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.

Setup

Current cocoapod structure

image

TTBaseUIKit Cocoapod Structure

Before updating the library, we should review our structure. Currently all source code locate in the root folder of cocoapods project TTBaseUIKit. We need to pay attention to the following two parts:

  1. The path of files in project: source_files, exclude_files, resource_bundle.

  2. Understanding configuration in TTBaseUIKit.podspec

Initial SwiftPM

Step1: Create new SwiftPM

In the root folder of our library. From Xcode and select File > New > Swift Package

After successfully, Xcode generates all necessary files and folders as it creates a Swift package:

  1. The Package.swift file, or package manifest,
  2. Source files reside in a folder named Sources and are scoped per Target.
  3. Unit test targets reside in a folder named Tests
image

TTBaseUIKit SwiftPM Structure

Step2: Configure our Swift Package

  1. Firstly, we need to move all old code into the new Sources folder, like this:

    image

    Move all source code

  2. Secondly, update Config Cocoapod. We need to update the config for Cocoapod to work correctly.

    We need to update the path in the .podspec. In my project the files updated: source_files, exclude_files, resource_bundle

    s.source_files = "Sources/TTBaseUIKit/**/*.{swift}"
    s.exclude_files = "Sources/TTBaseUIKit/**/*.plist"
    s.resource_bundle = { 'TTBaseUIKit' => ['Sources/TTBaseUIKit/**/*.{ttf}','Sources/TTBaseUIKit/**/*.{png}'] }
    
  3. And finally, update Config Package.swift

    The Package.swift file is a human-readable configuration file that is used by SwiftPM to build your library. It contains various properties that define your package. This file is created in the root folder of your project during initialization. The Package.swift file for my project looks like this:

    // swift-tools-version: 5.6
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(
        name: "TTBaseUIKit",
        platforms: [
            .iOS(.v10),
            .macCatalyst(.v13)
        ],
        products: [
            // Products define the executables and libraries a package produces, and make them visible to other packages.
            .library(
                name: "TTBaseUIKit",
                targets: ["TTBaseUIKit"]),
        ],
        dependencies: [
            // Dependencies declare other packages that this package depends on.
            // .package(url: /* package url */, from: "1.0.0"),
        ],
        targets: [
            // Targets are the basic building blocks of a package. A target can define a module or a test suite.
            // Targets can depend on other targets in this package, and on products in packages this package depends on.
            .target(
                name: "TTBaseUIKit",
                dependencies: [],
                exclude: ["Info.plist"],
            resources: [
                .process("Support/Resources/Fonts"),
                .process("Support/Resources/Images"),
            ]
            ),
            .testTarget(
                name: "TTBaseUIKitTests",
                dependencies: ["TTBaseUIKit"]),
        ],
        swiftLanguageVersions: [
            .v5
        ]
    )
    

    For more information about config, please go to the apple doc: https://developer.apple.com/documentation/xcode/creating-a-standalone-swift-package-with-xcode. Please note that:

    1. If you use resources, please add in config file:

              resources: [
                  .process("Support/Resources/Fonts"),
                  .process("Support/Resources/Images"),
              ]
      
    2. Please add exclude file .Plist

       exclude: ["Info.plist"],
      

Step 3: Commit

After setting up the project, the only thing that is left is to commit the changes, add a tag and push the changes:

git commit -m 'Add support for SwiftPM'
git push
git tag 1.5.0
git push origin 1.5.0

Update the cocoapod

pod lib lint --allow-warnings --verbose
pod trunk push --allow-warnings --verbose

You will get an email if everything is OK, and now our library supports both CocoaPods and SwiftPM.

image

Now our library support both cocoapods and SwiftPM

Demo

In my project (12bay). I used SwiftPM instead of cocoapods

image

12Bay integrated SwiftPM

Problems

Here are some problems you may encounter when update:

No such module “PackageDescription”

  1. Check the first line of the Package.swift file has

    // swift-tools-version: 5.6
    // The swift-tools-version declares the minimum version of Swift required to build this package
    
  2. Don’t use swift package generate-xcodeproj. Because this code is deprecated. You should using Xcode to create Swift Packages directly

.podspec error - source_files` pattern did not match any file

When you run pod trunk push --allow-warnings --verbose. This script will clone your code from github. So, make sure your tag version is TRUE and after that you need to check the files.

Full info you can check here: https://guides.cocoapods.org/making/specs-and-specs-repo.html

  s.source_files = "Sources/TTBaseUIKit/**/*.{swift}"
  s.exclude_files = "Sources/TTBaseUIKit/**/*.plist"
  s.resource_bundle = { 'TTBaseUIKit' => ['Sources/TTBaseUIKit/**/*.{ttf}','Sources/TTBaseUIKit/**/*.{png}'] }

May be you should clear the cache pod cache clean YourPodKit

The spec did not pass validation, due to 1 error

First, we find the root of the problem. Add --verbose to view more detail. For example:

pod lib lint --allow-warnings --verbose
or
pod trunk push --allow-warnings --verbose

If you use Bundle.module.url. Add code below to solve problem: #if SWIFT_PACKAGE. For example:

#if SWIFT_PACKAGE
		if let urlPackage =  Bundle.module.url(forResource: name, withExtension: "ttf") {
			TTBaseFunc.shared.printLog(object: "::Fonts podFont applied by urlPackage Bundle.module.url")
		}
#endif

Conclusion

Well done. We learned how to update the current cocoapod library to support SwiftPM. You can find my library at: https://github.com/tqtuan1201/TTBaseUIKit. Today, I just added my library to the Swift Package Index and thank for your reading this post. Swift Package Manager will soon replace CocoaPods for loading third-party libraries into your project. Also, let me know if you have any comments or problems. Thank you!

Posts in this Series